[libvigraimpex] 01/07: Imported Upstream version 0.10.0+git20160120.803d5d4

Daniel Stender danstender-guest at moszumanska.debian.org
Mon Jan 25 22:11:36 UTC 2016


This is an automated email from the git hooks/post-receive script.

danstender-guest pushed a commit to branch master
in repository libvigraimpex.

commit 1adbfc91952f7bf7db64e399a7a8c809b4c22932
Author: Daniel Stender <debian at danielstender.com>
Date:   Mon Jan 25 17:12:47 2016 +0100

    Imported Upstream version 0.10.0+git20160120.803d5d4
---
 CMakeLists.txt                                     |  151 +-
 README.md                                          |    9 +-
 config/FindHDF5.cmake                              |   54 +-
 config/FindVIGRANUMPY_DEPENDENCIES.cmake           |    4 +-
 config/VIGRA_ADD_NUMPY_MODULE.cmake                |   59 +-
 config/VigraAddTest.cmake                          |  116 +-
 config/VigraConfigureThreading.cmake               |   32 +
 config/VigraDetectCppVersion.cmake                 |   21 +
 config/VigraDetectThreading.cmake                  |   53 +
 config/VigraFindPackage.cmake                      |   10 +-
 config/VigraSetDefaults.cmake                      |    4 +
 config/checkTemplateDepth.cxx                      |   16 +
 config/check_std_thread.cxx                        |    3 +
 config/nuget/vigra.nuspec                          |   29 +
 config/nuget/vigra.redist.nuspec                   |   22 +
 config/nuget/vigra.redist.targets                  |    6 +
 config/nuget/vigra.targets                         |   11 +
 config/output_cplusplus_version.cxx                |   19 +
 config/run_test.bat.in                             |    8 +-
 config/run_test.sh.in                              |    2 +-
 config/testdebug.vcxproj.user.in                   |   17 +
 docsrc/Doxyfile.in                                 | 1156 +--
 docsrc/credits_changelog.dxx                       |  567 +-
 docsrc/examples.dxx                                |   66 +-
 docsrc/image_processing.dxx                        |    2 +-
 docsrc/index.dxx                                   |   51 +-
 docsrc/makeFunctionIndex.py                        |   70 +-
 docsrc/post.py                                     |   13 +-
 docsrc/tutorial.dxx                                |   64 +-
 include/vigra/accessor.hxx                         |   78 +-
 include/vigra/accumulator-grammar.hxx              |   26 +
 include/vigra/accumulator.hxx                      | 2562 +++---
 include/vigra/adjacency_list_graph.hxx             | 1165 +++
 include/vigra/affine_registration.hxx              |  362 +-
 include/vigra/affine_registration_fft.hxx          |  754 ++
 include/vigra/algorithm.hxx                        |   84 +-
 include/vigra/any.hxx                              |  407 +
 include/vigra/applywindowfunction.hxx              | 1010 +++
 include/vigra/array_vector.hxx                     |  109 +-
 include/vigra/axistags.hxx                         |   74 +-
 include/vigra/basicimage.hxx                       |   68 +-
 include/vigra/basicimageview.hxx                   |   36 +-
 include/vigra/blockify.hxx                         |  121 +
 include/vigra/blockwise_convolution.hxx            |  140 +
 include/vigra/blockwise_labeling.hxx               |  502 ++
 include/vigra/blockwise_watersheds.hxx             |  258 +
 include/vigra/box.hxx                              |   27 +-
 include/vigra/bucket_queue.hxx                     |  362 +-
 include/vigra/combineimages.hxx                    |    4 +-
 .../vigra/compression.hxx                          |   61 +-
 include/vigra/config.hxx                           |   76 +-
 .../{configVersion.hxx => config_version.hxx}      |    0
 include/vigra/convolution.hxx                      |  176 +-
 include/vigra/coordinate_iterator.hxx              |    3 +-
 include/vigra/correlation.hxx                      |  718 ++
 include/vigra/counting_iterator.hxx                |  407 +
 include/vigra/delegate/delegate.hxx                |   47 +
 include/vigra/delegate/detail/delegate_list.hxx    |  189 +
 .../vigra/delegate/detail/delegate_template.hxx    |  169 +
 include/vigra/eccentricitytransform.hxx            |  293 +
 include/vigra/edgedetection.hxx                    |   27 +-
 include/vigra/eigensystem.hxx                      |  186 +-
 include/vigra/fftw.hxx                             |   21 +
 include/vigra/fftw3.hxx                            |   28 +-
 include/vigra/fixedpoint.hxx                       |    2 +-
 include/vigra/graph_algorithms.hxx                 | 1566 ++++
 include/vigra/graph_generalization.hxx             |  252 +
 include/vigra/graph_item_impl.hxx                  |  575 ++
 include/vigra/graph_maps.hxx                       |  399 +
 include/vigra/graph_rag_project_back.hxx           |  193 +
 include/vigra/graphs.hxx                           |  155 +-
 include/vigra/hdf5impex.hxx                        | 1369 +++-
 include/vigra/hierarchical_clustering.hxx          |  797 ++
 include/vigra/histogram.hxx                        |   32 +-
 include/vigra/imagecontainer.hxx                   |    9 +-
 include/vigra/imageinfo.hxx                        |    5 +-
 include/vigra/imageiterator.hxx                    |   58 +-
 include/vigra/impex.hxx                            |    3 +-
 include/vigra/impexalpha.hxx                       |    2 +-
 include/vigra/impexbase.hxx                        |    6 +-
 include/vigra/integral_image.hxx                   |  219 +
 include/vigra/iteratoradapter.hxx                  |   24 +-
 include/vigra/iteratorfacade.hxx                   |  174 +
 include/vigra/iteratortraits.hxx                   |    2 +-
 include/vigra/labelimage.hxx                       |   80 +-
 include/vigra/labelvolume.hxx                      |  135 +-
 include/vigra/linear_solve.hxx                     |   39 +-
 include/vigra/mathutil.hxx                         |  373 +-
 include/vigra/matrix.hxx                           |   32 +-
 include/vigra/medianfilter.hxx                     |  193 +
 include/vigra/memory.hxx                           |  132 +-
 include/vigra/merge_graph_adaptor.hxx              | 1454 ++++
 include/vigra/metaprogramming.hxx                  |   64 +-
 include/vigra/metrics.hxx                          |  277 +
 include/vigra/multi_array.hxx                      |  150 +-
 include/vigra/multi_array_chunked.hxx              | 3477 ++++++++
 include/vigra/multi_array_chunked_hdf5.hxx         |  463 ++
 include/vigra/multi_blocking.hxx                   |  345 +
 include/vigra/multi_blockwise.hxx                  |  463 ++
 include/vigra/multi_convolution.hxx                |  505 +-
 include/vigra/multi_distance.hxx                   |  354 +-
 include/vigra/multi_fft.hxx                        |  300 +-
 include/vigra/multi_fwd.hxx                        |  223 +
 include/vigra/multi_gridgraph.hxx                  |  367 +-
 include/vigra/multi_handle.hxx                     | 1103 +++
 include/vigra/multi_hierarchical_iterator.hxx      |  631 ++
 include/vigra/multi_histogram.hxx                  |  332 +
 include/vigra/multi_impex.hxx                      |  135 +-
 include/vigra/multi_iterator.hxx                   |   54 +-
 include/vigra/multi_iterator_coupled.hxx           |  797 +-
 include/vigra/multi_labeling.hxx                   |  393 +-
 include/vigra/multi_localminmax.hxx                |   36 +-
 include/vigra/multi_morphology.hxx                 |    2 +-
 include/vigra/multi_pointoperators.hxx             |   67 +-
 include/vigra/multi_shape.hxx                      |  133 +-
 include/vigra/multi_watersheds.hxx                 |  273 +-
 include/vigra/non_local_mean.hxx                   |  952 +++
 include/vigra/numerictraits.hxx                    |    4 -
 include/vigra/numpy_array.hxx                      |  116 +-
 include/vigra/numpy_array_converters.hxx           |   87 +-
 include/vigra/numpy_array_taggedshape.hxx          |   91 +-
 include/vigra/numpy_array_traits.hxx               |    2 +-
 include/vigra/overlapped_blocks.hxx                |  213 +
 include/vigra/pixelneighborhood.hxx                |    4 +-
 include/vigra/polygon.hxx                          | 1825 ++++-
 include/vigra/polynomial_registration.hxx          |  278 +
 .../vigra/print_backtrace.hxx                      |   82 +-
 .../vigra/{bucket_queue.hxx => priority_queue.hxx} |  202 +-
 include/vigra/project2ellipse.hxx                  |    6 +-
 include/vigra/projective_registration.hxx          |  245 +
 include/vigra/python_graph.hxx                     |  839 ++
 include/vigra/python_utility.hxx                   |   10 +-
 include/vigra/quadprog.hxx                         |   38 +-
 include/vigra/random.hxx                           |   28 +-
 include/vigra/random_access_set.hxx                |  635 ++
 include/vigra/random_forest.hxx                    |   18 +-
 include/vigra/random_forest/rf_algorithm.hxx       |   13 +-
 include/vigra/random_forest/rf_common.hxx          |    4 +-
 include/vigra/random_forest/rf_earlystopping.hxx   |   51 +-
 include/vigra/random_forest/rf_preprocessing.hxx   |   19 +-
 include/vigra/random_forest/rf_region.hxx          |    2 +-
 include/vigra/random_forest/rf_ridge_split.hxx     |    4 +-
 include/vigra/random_forest/rf_split.hxx           |   10 +-
 include/vigra/random_forest/rf_visitors.hxx        |   47 +-
 include/vigra/random_forest_hdf5_impex.hxx         |   55 +
 include/vigra/rbf_registration.hxx                 |  312 +
 include/vigra/recursiveconvolution.hxx             |    2 +-
 .../vigra/region_shrinking.hxx                     |   83 +-
 include/vigra/regression.hxx                       |   59 +-
 include/vigra/resampling_convolution.hxx           |  171 +-
 include/vigra/resizeimage.hxx                      |    7 +-
 include/vigra/rgbvalue.hxx                         |    1 -
 include/vigra/sampling.hxx                         |   16 +-
 include/vigra/seededregiongrowing.hxx              |    2 +-
 .../vigra/seg_to_seeds.hxx                         |   83 +-
 include/vigra/separableconvolution.hxx             |  222 +-
 include/vigra/shockfilter.hxx                      |  312 +
 include/vigra/singular_value_decomposition.hxx     |   10 +-
 include/vigra/skeleton.hxx                         |  974 +++
 include/vigra/slanted_edge_mtf.hxx                 |  225 +-
 include/vigra/slic.hxx                             |    6 +-
 include/vigra/specklefilters.hxx                   | 1197 +++
 include/vigra/stdconvolution.hxx                   |   33 +-
 include/vigra/threading.hxx                        |  381 +
 include/vigra/threadpool.hxx                       |  665 ++
 include/vigra/tinyvector.hxx                       |  407 +-
 include/vigra/transform_iterator.hxx               |  192 +
 include/vigra/transformimage.hxx                   |    4 +-
 include/vigra/tv_filter.hxx                        |  242 +-
 include/vigra/union_find.hxx                       |  260 +-
 include/vigra/unittest.hxx                         |   17 +-
 include/vigra/unsupervised_decomposition.hxx       |  122 +-
 include/vigra/utilities.hxx                        |   94 +-
 include/vigra/vector_distance.hxx                  |  534 ++
 include/vigra/visit_border.hxx                     |  179 +
 include/vigra/watersheds.hxx                       |   14 +-
 include/vigra/watersheds3d.hxx                     |   17 +-
 include/vigra/windows.h                            |    6 +
 src/examples/CMakeLists.txt                        |    1 +
 src/examples/nnlsq.cxx                             |   55 +
 src/impex/CMakeLists.txt                           |   25 +-
 src/impex/bmp.cxx                                  |    2 +-
 src/impex/compression.cxx                          |  204 +
 src/impex/gif.cxx                                  |   14 +-
 src/impex/hdf5impex.cxx                            |   22 +-
 src/impex/imageinfo.cxx                            |    6 +-
 src/impex/lz4.c                                    |  865 ++
 src/impex/lz4.h                                    |  249 +
 src/impex/png.cxx                                  |    2 +-
 src/impex/pnm.cxx                                  |    2 +-
 src/impex/tiff.cxx                                 |   74 +-
 test/CMakeLists.txt                                |   56 +-
 test/adjacency_list_graph/CMakeLists.txt           |    1 +
 test/adjacency_list_graph/test.cxx                 | 1549 ++++
 test/blockwisealgorithms/CMakeLists.txt            |   14 +
 test/blockwisealgorithms/test_convolution.cxx      |  129 +
 test/blockwisealgorithms/test_labeling.cxx         |  310 +
 test/blockwisealgorithms/test_watersheds.cxx       |  227 +
 .../blockwisealgorithms/utils.hxx                  |   70 +-
 test/classifier/data/CMakeLists.txt                |    2 +-
 test/classifier/data/bare.hdf5                     |  Bin 0 -> 1832 bytes
 test/classifier/data/empty.hdf5                    |    0
 test/classifier/test.cxx                           |  104 +-
 test/correlation/CMakeLists.txt                    |    9 +
 test/correlation/test.cxx                          |  317 +
 test/counting_iterator/CMakeLists.txt              |    1 +
 test/counting_iterator/test.cxx                    |  281 +
 test/delegates/CMakeLists.txt                      |    1 +
 .../vigra/memory.hxx => test/delegates/test.cxx    |  149 +-
 test/filters/CMakeLists.txt                        |    1 +
 test/filters/test.cxx                              |  477 ++
 test/fourier/CMakeLists.txt                        |    4 +-
 test/graph_algorithm/CMakeLists.txt                |    1 +
 test/graph_algorithm/test.cxx                      |  575 ++
 test/gridgraph/test.cxx                            |   46 +-
 test/hdf5impex/test.cxx                            |   54 +-
 test/impex/CMakeLists.txt                          |    2 +-
 test/impex/bilevel.tiff                            |  Bin 0 -> 15218 bytes
 test/impex/test.cxx                                |   67 +
 test/integral_image/CMakeLists.txt                 |    2 +
 test/integral_image/test.cxx                       |  255 +
 test/math/test.cxx                                 |  200 +-
 test/merge_graph_adaptor/CMakeLists.txt            |    2 +
 test/merge_graph_adaptor/test.cxx                  | 1732 ++++
 test/multiarray/CMakeLists.txt                     |   44 +-
 test/multiarray/compression-ratio-benchmark.xlsx   |  Bin 0 -> 18944 bytes
 test/multiarray/test.cxx                           |  291 +-
 test/multiarray/test_chunked.cxx                   | 1618 ++++
 test/multidistance/CMakeLists.txt                  |   21 +-
 test/multidistance/blatt.xv                        |  Bin 0 -> 263168 bytes
 test/multidistance/raw_skeleton.xv                 |  Bin 0 -> 263168 bytes
 test/multidistance/skeleton_length.xv              |  Bin 0 -> 1049600 bytes
 test/multidistance/skeleton_length_greater_100.xv  |  Bin 0 -> 263168 bytes
 .../skeleton_length_greater_50_percent.xv          |  Bin 0 -> 263168 bytes
 test/multidistance/skeleton_salience.xv            |  Bin 0 -> 1049600 bytes
 test/multidistance/skeleton_salience_greater_10.xv |  Bin 0 -> 263168 bytes
 .../skeleton_salience_greater_60_percent.xv        |  Bin 0 -> 263168 bytes
 test/multidistance/skeleton_topology.xv            |  Bin 0 -> 263168 bytes
 .../skeleton_topology_without_center.xv            |  Bin 0 -> 263168 bytes
 test/multidistance/test.cxx                        | 1563 ++--
 test/multidistance/test_data.hxx                   | 8498 ++++++++++++++++++++
 test/multimorphology/test.cxx                      |   97 +-
 test/objectfeatures/CMakeLists.txt                 |    2 +-
 .../objectfeatures/stand_alone_acc_chain.cxx       |  102 +-
 test/objectfeatures/test.cxx                       |  133 +-
 test/pixeltypes/test.cxx                           |   57 +-
 test/polygon/CMakeLists.txt                        |    2 +
 test/{math => polygon}/convex_hull_test.hxx        |   30 +-
 test/polygon/test.cxx                              |  902 +++
 test/registration/CMakeLists.txt                   |   14 +
 test/registration/nuernberg-1991.png               |  Bin 0 -> 365414 bytes
 test/registration/nuernberg-1995.png               |  Bin 0 -> 547291 bytes
 test/registration/test.cxx                         |  839 ++
 test/sampler/test.cxx                              |    4 +-
 test/simpleanalysis/test.cxx                       |  351 +-
 test/slic2d/slic.xv                                |  Bin 62464 -> 62464 bytes
 test/slic2d/test.cxx                               |    4 +-
 test/threadpool/CMakeLists.txt                     |    2 +
 test/threadpool/test.cxx                           |  257 +
 test/unsupervised/test.cxx                         |    8 +-
 test/utilities/CMakeLists.txt                      |    8 +-
 test/utilities/test.cxx                            | 1153 ++-
 test/volumelabeling/test.cxx                       |   12 +-
 test/watersheds3d/test.cxx                         |   88 +-
 vigranumpy/CMakeLists.txt                          |   50 +-
 vigranumpy/docsrc/CMakeLists.txt                   |   38 +-
 .../docsrc/{conf.py.in => conf.py.cmake2.in}       |    2 +-
 vigranumpy/docsrc/conf.py.in                       |    8 +-
 vigranumpy/docsrc/index.rst                        |   56 +-
 vigranumpy/examples/100075.jpg                     |  Bin 0 -> 30857 bytes
 vigranumpy/examples/12003.jpg                      |  Bin 0 -> 85164 bytes
 vigranumpy/examples/12074.jpg                      |  Bin 0 -> 60437 bytes
 vigranumpy/examples/69015.jpg                      |  Bin 0 -> 66924 bytes
 vigranumpy/examples/VigraGraphs.ipynb              |  309 +
 vigranumpy/examples/blocking.py                    |   34 +
 vigranumpy/examples/eccentricity_transform.py      |   26 +
 vigranumpy/examples/gaussian_rank.py               |   17 +
 vigranumpy/examples/graph_3cycles.py               |   49 +
 .../examples/graph_agglomerative_clustering.py     |   69 +
 vigranumpy/examples/graph_felzenszwalb.py          |   43 +
 vigranumpy/examples/graph_smoothing.py             |   20 +
 vigranumpy/examples/graph_watersheds.py            |   61 +
 vigranumpy/examples/grid_graph_shortestpath.py     |  150 +
 vigranumpy/examples/islands.png                    |  Bin 0 -> 19987 bytes
 vigranumpy/examples/merge_graph.py                 |   68 +
 vigranumpy/examples/non_local_mean_2d_color.py     |   19 +
 vigranumpy/examples/rag_features.py                |   19 +
 vigranumpy/examples/shock_filter.py                |   25 +
 vigranumpy/lib/__init__.py                         | 2359 +++++-
 vigranumpy/lib/arraytypes.py                       |  882 +-
 vigranumpy/lib/pyqt/imagewindow.py                 |    2 +-
 vigranumpy/{setup.py.in => setup.py.cmake2.in}     |    6 +-
 vigranumpy/setup.py.in                             |    8 +-
 vigranumpy/src/core/CMakeLists.txt                 |   54 +-
 .../src/core/accumulator-region-singleband.cxx     |  351 +
 .../{vigranumpycore.cxx => adjacencyListGraph.cxx} |   89 +-
 vigranumpy/src/core/axistags.cxx                   |   52 +-
 vigranumpy/src/core/blockwise.cxx                  |  300 +
 .../core/{vigranumpycore.cxx => clustering.cxx}    |   43 +-
 vigranumpy/src/core/colors.cxx                     |   59 +-
 ...ranumpycore.cxx => construct_custodian_for.hpp} |   82 +-
 vigranumpy/src/core/converters.cxx                 |    5 +
 vigranumpy/src/core/convolution.cxx                |  239 +-
 .../src/core/export_graph_algorithm_visitor.hxx    | 1100 +++
 ...xport_graph_hierarchical_clustering_visitor.hxx |  477 ++
 vigranumpy/src/core/export_graph_rag_visitor.hxx   |  950 +++
 .../core/export_graph_shortest_path_visitor.hxx    |  348 +
 vigranumpy/src/core/export_graph_visitor.hxx       |  590 ++
 vigranumpy/src/core/filters.cxx                    |  135 +-
 .../src/core/{vigranumpycore.cxx => graphs.cxx}    |   75 +-
 .../core/{vigranumpycore.cxx => gridGraph2d.cxx}   |  103 +-
 .../core/{vigranumpycore.cxx => gridGraph3d.cxx}   |  102 +-
 vigranumpy/src/core/gridGraphNd.cxx                |  131 +
 .../core/{vigranumpycore.cxx => gridGraphNd.hxx}   |  100 +-
 .../src/core/grid_graph_implicit_edge_maps.cxx     |  136 +
 vigranumpy/src/core/histogram.cxx                  |  210 +
 vigranumpy/src/core/impex.cxx                      |    5 +-
 vigranumpy/src/core/learning.cxx                   |   30 +-
 ...ator-region-singleband.cxx => minindexedpq.cxx} |   70 +-
 vigranumpy/src/core/morphology.cxx                 |  450 +-
 vigranumpy/src/core/multi_array_chunked.cxx        |  804 ++
 vigranumpy/src/core/non_local_mean.cxx             |  182 +
 vigranumpy/src/core/pythonaccumulator.hxx          |    1 +
 vigranumpy/src/core/random_forest.cxx              |   69 +-
 vigranumpy/src/core/sampling.cxx                   |  118 +-
 vigranumpy/src/core/segmentation.cxx               |  843 +-
 .../src/core/{vigranumpycore.cxx => utilities.cxx} |   75 +-
 vigranumpy/src/core/vigranumpycore.cxx             |    2 +
 vigranumpy/src/fourier/CMakeLists.txt              |    2 +
 vigranumpy/test/CMakeLists.txt                     |  106 +-
 vigranumpy/test/set_paths.py.cmake2.in             |   45 +
 vigranumpy/test/set_paths.py.in                    |   75 +-
 vigranumpy/test/test4.py                           |  287 +
 vigranumpy/test/test_arraytypes.py                 |  652 +-
 vigranumpy/test/test_rf.py                         |   22 +
 vigranumpy/test/test_segmentation.py               |   37 +
 336 files changed, 74459 insertions(+), 8864 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6e01dd6..2a7dc9f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,8 +8,8 @@ cmake_minimum_required(VERSION 2.6)
 
 PROJECT(vigra)
 
-# read the current version from configVersion.hxx
-file(READ ${vigra_SOURCE_DIR}/include/vigra/configVersion.hxx VIGRA_VERSION_FILE)
+# read the current version from config_version.hxx
+file(READ ${vigra_SOURCE_DIR}/include/vigra/config_version.hxx VIGRA_VERSION_FILE)
 string(REGEX MATCH "VIGRA_VERSION_MAJOR[ \t\n]+[^ \t\n]+" VIGRA_VERSION_MAJOR ${VIGRA_VERSION_FILE})
 string(REGEX REPLACE "VIGRA_VERSION_MAJOR[ \t\n]" "" VIGRA_VERSION_MAJOR ${VIGRA_VERSION_MAJOR})
 string(REGEX MATCH "VIGRA_VERSION_MINOR[ \t\n]+[^ \t\n]+" VIGRA_VERSION_MINOR ${VIGRA_VERSION_FILE})
@@ -39,18 +39,54 @@ IF (MSVC)
     ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_DEPRECATE)
 ENDIF ()
 
-# if(CMAKE_COMPILER_IS_GNUCXX)
-  # exec_program(
-      # ${CMAKE_CXX_COMPILER}
-      # ARGS                    --version
-      # OUTPUT_VARIABLE _compiler_output)
-  # string(REGEX REPLACE ".*([0-9]\\.[0-9]\\.[0-9]).*" "\\1"  gcc_compiler_version ${_compiler_output})
-  # if(gcc_compiler_version VERSION_LESS "4.4.0")
-      # message(FATAL_ERROR "VIGRA requires at least gcc 4.4")
-  # else()
-      # message(STATUS "Using gcc ${gcc_compiler_version} [${CMAKE_CXX_COMPILER}]")
-  # endif()
-# endif()
+IF(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
+    set(SUFFICIENT_TEMPLATE_DEPTH FALSE)
+    TRY_COMPILE(SUFFICIENT_TEMPLATE_DEPTH
+                ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/config/checkTemplateDepth.cxx
+                COMPILE_DEFINITIONS "-DDEPTH=900")
+
+    IF(SUFFICIENT_TEMPLATE_DEPTH)
+        MESSAGE(STATUS "Checking template recursion depth: ok")
+    ELSE()
+        if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+            # As of cmake 2.8.10, there is a variable CMAKE_CXX_COMPILER_VERSION.
+            # Emulate it by a compiler call if not present.
+            IF(NOT CMAKE_CXX_COMPILER_VERSION)
+                exec_program(${CMAKE_CXX_COMPILER}
+                    ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion
+                    OUTPUT_VARIABLE CMAKE_CXX_COMPILER_VERSION)
+                string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1.\\2"
+                      CMAKE_CXX_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION})
+            endif()
+
+            message ("Detected GCC version ${CMAKE_CXX_COMPILER_VERSION}")
+            if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.4.0")
+                MESSAGE(WARNING "GNU c++ < 4.4 cannot build VIGRANumPy; disabling (found GCC ${CMAKE_CXX_COMPILER_VERSION})")
+                SET(WITH_VIGRANUMPY 0)
+            elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.5.0")
+                # gcc 4.4.x syntax is -ftemplate-depth-900 (not =900)
+                SET(CMAKE_CXX_FLAGS "-ftemplate-depth-900 ${CMAKE_CXX_FLAGS}")
+                MESSAGE(STATUS "Checking template recursion depth: using -ftemplate-depth-900")
+            else()
+                # new syntax is =900, not -900
+                SET(CMAKE_CXX_FLAGS "-ftemplate-depth=900 ${CMAKE_CXX_FLAGS}")
+                MESSAGE(STATUS "Checking template recursion depth: using -ftemplate-depth=900")
+            endif()
+        else()
+            # clang uses newer gcc syntax
+            SET(CMAKE_CXX_FLAGS "-ftemplate-depth=900 ${CMAKE_CXX_FLAGS}")
+            MESSAGE(STATUS "Checking template recursion depth: using -ftemplate-depth=900")
+        endif()
+    ENDIF()
+ENDIF()
+
+if(MSVC)
+    string(REGEX MATCH "[0-9.]+" MSVC_VERSION ${CMAKE_GENERATOR})
+endif()
+
+if(MACOSX)
+    set(CMAKE_MACOSX_RPATH 1)
+endif()
 
 ##################################################
 #
@@ -59,12 +95,14 @@ ENDIF ()
 ##################################################
 
 INCLUDE(VigraFindPackage)
-VIGRA_FIND_PACKAGE(TIFF NAMES libtiff)
+VIGRA_FIND_PACKAGE(ZLIB)
+VIGRA_FIND_PACKAGE(TIFF NAMES libtiff_i libtiff) # prefer DLL on Windows
 VIGRA_FIND_PACKAGE(JPEG NAMES libjpeg)
 VIGRA_FIND_PACKAGE(PNG)
 VIGRA_FIND_PACKAGE(FFTW3 NAMES libfftw3-3 libfftw-3.3)
 VIGRA_FIND_PACKAGE(FFTW3F NAMES libfftw3f-3 libfftwf-3.3)
 
+
 IF(WITH_OPENEXR)
     VIGRA_FIND_PACKAGE(OpenEXR)
 ENDIF()
@@ -73,11 +111,37 @@ IF(WITH_HDF5)
     VIGRA_FIND_PACKAGE(HDF5)
 ENDIF()
 
+set(WITH_BOOST "OFF")
+set(WITH_BOOST_COMPONENTS "")
+
 IF(WITH_BOOST_GRAPH)
-    IF(WITH_VIGRANUMPY)
-        VIGRA_FIND_PACKAGE( Boost 1.40.0 COMPONENTS python )
-    else()
-        VIGRA_FIND_PACKAGE( Boost 1.40.0 )
+    set(WITH_BOOST "ON")
+ENDIF()
+
+IF(WITH_VIGRANUMPY)
+    set(WITH_BOOST "ON")
+    set(WITH_BOOST_COMPONENTS ${WITH_BOOST_COMPONENTS} python)
+ENDIF()
+
+IF(WITH_BOOST_THREAD)
+    set(WITH_BOOST "ON")
+    set(WITH_BOOST_COMPONENTS ${WITH_BOOST_COMPONENTS} thread system date_time chrono)
+    ADD_DEFINITIONS(-DUSE_BOOST_THREAD)
+ENDIF()
+
+IF(WITH_BOOST)
+    VIGRA_FIND_PACKAGE( Boost 1.40.0 COMPONENTS ${WITH_BOOST_COMPONENTS})
+
+    if(Boost_FOUND)
+        INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})
+        if(WITH_BOOST_COMPONENTS)
+            # configure boost's autolink magic to use the right library name
+            # (default on Windows is a mangled name like 'boost_python-vc110-mt-1_51.lib')
+            if(("${Boost_PYTHON_LIBRARY}" MATCHES "boost_python\\.lib") OR
+               ("${Boost_SYSTEM_LIBRARY}" MATCHES "boost_system\\.lib"))
+                ADD_DEFINITIONS(-DBOOST_AUTO_LINK_NOMANGLE)
+            endif()
+        endif()
     endif()
 ENDIF()
 
@@ -87,7 +151,7 @@ ENDIF()
 
 SET(DOXYGEN_SKIP_DOT TRUE)
 FIND_PACKAGE(Doxygen)
-FIND_PACKAGE(PythonInterp)
+FIND_PACKAGE(PythonInterp 2)
 
 IF(WITH_VIGRANUMPY)
     FIND_PACKAGE( VIGRANUMPY_DEPENDENCIES )
@@ -97,6 +161,21 @@ IF(WITH_VALGRIND)
     FIND_PROGRAM(VALGRIND_EXECUTABLE valgrind)
 ENDIF()
 
+# Must be included AFTER boost is found.
+include(VigraDetectThreading)
+include(VigraConfigureThreading)
+
+# Should come after VigraDetectThreading, since that updates the -std flag.
+include(VigraDetectCppVersion)
+VIGRA_DETECT_CPP_VERSION()
+
+########################################
+#  finalize compiler flags
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}"
+    CACHE STRING  "Flags used by the C compiler during all build types" FORCE)
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}"
+    CACHE STRING  "Flags used by the C++ compiler during all build types" FORCE)
+
 ##################################################
 #
 #     setup testing environment
@@ -131,16 +210,16 @@ ENABLE_TESTING()
 ADD_CUSTOM_TARGET(doc)
 
 # Automatically push the latest documentation to github's gh-pages.
-# This only works when ${DOCDIR} refers to a VIGRA repository that is 
-# checked out in branch 'gh-pages', and the present repository is 
+# This only works when ${DOCDIR} refers to a VIGRA repository that is
+# checked out in branch 'gh-pages', and the present repository is
 # in branch 'master' (these conditions are checked in the script).
 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 
-    configure_file(${PROJECT_SOURCE_DIR}/config/update-gh-pages.sh.in 
+    configure_file(${PROJECT_SOURCE_DIR}/config/update-gh-pages.sh.in
                    ${PROJECT_BINARY_DIR}/update-gh-pages.sh @ONLY)
     EXECUTE_PROCESS(COMMAND chmod u+x ${PROJECT_BINARY_DIR}/update-gh-pages.sh OUTPUT_QUIET ERROR_QUIET)
-       
-    ADD_CUSTOM_TARGET(gh-pages 
+
+    ADD_CUSTOM_TARGET(gh-pages
           ${PROJECT_BINARY_DIR}/update-gh-pages.sh
           DEPENDS doc
           WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
@@ -198,7 +277,7 @@ INCLUDE(CPackConfig)
 #
 ##################################################
 
-find_program(GIT_EXECUTABLE 
+find_program(GIT_EXECUTABLE
               NAMES git git.exe git.cmd
               HINTS $ENV{ProgramFiles}/Git/bin
               DOC "git command line client")
@@ -210,7 +289,7 @@ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/config/package-src.cmake.in
 add_custom_target(PACKAGE_SRC_TAR
                    COMMAND ${CMAKE_COMMAND} -P package-src.cmake
                    WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
-                   COMMENT "Creating ${PROJECT_BINARY_DIR}/vigra-${vigra_version}-src.tar.gz")        
+                   COMMENT "Creating ${PROJECT_BINARY_DIR}/vigra-${vigra_version}-src.tar.gz")
 
 ADD_DEPENDENCIES(PACKAGE_SRC_TAR check)
 ADD_DEPENDENCIES(PACKAGE_SRC_TAR doc_cpp)
@@ -277,6 +356,18 @@ MESSAGE( STATUS "---------------------------------------------------------" )
 MESSAGE( STATUS "VIGRA configuration information:" )
 MESSAGE( STATUS "---------------------------------------------------------" )
 
+IF(ZLIB_FOUND)
+    MESSAGE( STATUS "  Using ZLIB  libraries: ${ZLIB_LIBRARIES}" )
+ELSE()
+    MESSAGE( STATUS "  ZLIB libraries not found (ZLIB support disabled)" )
+ENDIF()
+
+IF(PNG_FOUND)
+    MESSAGE( STATUS "  Using PNG  libraries: ${PNG_LIBRARIES}" )
+ELSE()
+    MESSAGE( STATUS "  PNG libraries not found (PNG support disabled)" )
+ENDIF()
+
 IF(TIFF_FOUND)
     MESSAGE( STATUS "  Using TIFF libraries: ${TIFF_LIBRARIES}" )
 ELSE()
@@ -289,12 +380,6 @@ ELSE()
     MESSAGE( STATUS "  JPEG libraries not found (JPEG support disabled)" )
 ENDIF()
 
-IF(PNG_FOUND)
-    MESSAGE( STATUS "  Using PNG  libraries: ${PNG_LIBRARIES}" )
-ELSE()
-    MESSAGE( STATUS "  PNG libraries not found (PNG support disabled)" )
-ENDIF()
-
 IF(OPENEXR_FOUND)
     MESSAGE( STATUS "  Using OpenEXR  libraries: ${OPENEXR_LIBRARIES}" )
 ELSEIF(NOT WITH_OPENEXR)
diff --git a/README.md b/README.md
index 5bcff8b..961d151 100644
--- a/README.md
+++ b/README.md
@@ -36,12 +36,11 @@ or online at
 Documentation
 -------------
 
-If you downloaded an official release, the documentation can be found in $VIGRA_PATH/doc/vigra/, the start file 
-is $VIGRA_PATH/doc/vigra/index.html. Online documentation for the latest release is at 
-http://hci.iwr.uni-heidelberg.de/vigra/doc/vigra/index.html
+If you downloaded an official release, the documentation can be found in `$VIGRA_PATH/doc/vigra/`, the start file 
+is `$VIGRA_PATH/doc/vigra/index.html`.
 
 When you use the development version from github, you can generate documentation by `make doc`. Up-to-date 
-online documentation for the 'master' branch is at http://ukoethe.github.io/vigra/doc/vigra/index.html
+online documentation for the 'master' branch is regularly pushed to http://ukoethe.github.io/vigra/doc/vigra/
 
 Download
 --------
@@ -52,7 +51,7 @@ repository is at https://github.com/ukoethe/vigra
 What is VIGRA
 -------------
 
-VIGRA is a computer vision library that puts its main emphasis on flexible algorithms, because algorithms represent the principle know-how of this field. The library was consequently built using generic programming as introduced by Stepanov and Musser and exemplified in the C++ Standard Template Library. By writing a few adapters (image iterators and accessors) you can use VIGRA's algorithms on top of your data structures, within your environment. Alternatively, you can also use the data [...]
+VIGRA is a computer vision library that puts its main emphasis on flexible algorithms, because algorithms represent the principal know-how of this field. The library was consequently built using generic programming as introduced by Stepanov and Musser and exemplified in the C++ Standard Template Library. By writing a few adapters (image iterators and accessors) you can use VIGRA's algorithms on top of your data structures, within your environment. Alternatively, you can also use the data [...]
 
 
 
diff --git a/config/FindHDF5.cmake b/config/FindHDF5.cmake
index e6b06e2..3244212 100644
--- a/config/FindHDF5.cmake
+++ b/config/FindHDF5.cmake
@@ -33,33 +33,39 @@ if(HDF5_INCLUDE_DIR)
     else()
         MESSAGE( STATUS "HDF5: need at least version ${HDF5_VERSION_MAJOR}.${HDF5_VERSION_MINOR}" )
     endif()
+    
+    if(HDF5_SUFFICIENT_VERSION)
+        # Only test for HDF5 features if a suitable version of the library was 
+        # found previously.
 
-    set(HDF5_USES_ZLIB FALSE)
-    TRY_COMPILE(HDF5_USES_ZLIB
-               ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/config/checkHDF5usesCompression.c
-               COMPILE_DEFINITIONS "-DH5_SOMETHING=H5_HAVE_FILTER_DEFLATE"
-               CMAKE_FLAGS "${HDF5_TRY_COMPILE_INCLUDE_DIR}") 
+        set(HDF5_USES_ZLIB FALSE)
+        TRY_COMPILE(HDF5_USES_ZLIB
+                   ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/config/checkHDF5usesCompression.c
+                   COMPILE_DEFINITIONS "-DH5_SOMETHING=H5_HAVE_FILTER_DEFLATE"
+                   CMAKE_FLAGS "${HDF5_TRY_COMPILE_INCLUDE_DIR}") 
 
-    if(HDF5_USES_ZLIB)
-        FIND_LIBRARY(HDF5_Z_LIBRARY NAMES zlib1 zlib z )
-        set(HDF5_ZLIB_OK ${HDF5_Z_LIBRARY})
-    else()
-        set(HDF5_ZLIB_OK TRUE)
-        set(HDF5_Z_LIBRARY "")
-    endif()
+        if(HDF5_USES_ZLIB)
+            FIND_LIBRARY(HDF5_Z_LIBRARY NAMES zlib1 zlib z )
+            set(HDF5_ZLIB_OK ${HDF5_Z_LIBRARY})
+        else()
+            set(HDF5_ZLIB_OK TRUE)
+            set(HDF5_Z_LIBRARY "")
+        endif()
 
-    set(HDF5_USES_SZLIB FALSE)
-    TRY_COMPILE(HDF5_USES_SZLIB 
-                ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/config/checkHDF5usesCompression.c
-                COMPILE_DEFINITIONS "-DH5_SOMETHING=H5_HAVE_FILTER_SZIP"
-                CMAKE_FLAGS "${HDF5_TRY_COMPILE_INCLUDE_DIR}") 
-            
-    if(HDF5_USES_SZLIB)
-        FIND_LIBRARY(HDF5_SZ_LIBRARY NAMES szlibdll sz szip)
-        set(HDF5_SZLIB_OK ${HDF5_SZ_LIBRARY})
-    else()
-        set(HDF5_SZLIB_OK TRUE)
-        set(HDF5_SZ_LIBRARY "")
+        set(HDF5_USES_SZLIB FALSE)
+        TRY_COMPILE(HDF5_USES_SZLIB 
+                    ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/config/checkHDF5usesCompression.c
+                    COMPILE_DEFINITIONS "-DH5_SOMETHING=H5_HAVE_FILTER_SZIP"
+                    CMAKE_FLAGS "${HDF5_TRY_COMPILE_INCLUDE_DIR}") 
+                
+        if(HDF5_USES_SZLIB)
+            FIND_LIBRARY(HDF5_SZ_LIBRARY NAMES szlibdll sz szip)
+            set(HDF5_SZLIB_OK ${HDF5_SZ_LIBRARY})
+        else()
+            set(HDF5_SZLIB_OK TRUE)
+            set(HDF5_SZ_LIBRARY "")
+        endif()
+    
     endif()
 endif()
 
diff --git a/config/FindVIGRANUMPY_DEPENDENCIES.cmake b/config/FindVIGRANUMPY_DEPENDENCIES.cmake
index 9e52a38..cd03011 100644
--- a/config/FindVIGRANUMPY_DEPENDENCIES.cmake
+++ b/config/FindVIGRANUMPY_DEPENDENCIES.cmake
@@ -2,12 +2,12 @@
 #
 MESSAGE(STATUS "Checking VIGRANUMPY_DEPENDENCIES")
 
-FIND_PACKAGE(PythonInterp)
+FIND_PACKAGE(PythonInterp 2)
 
 IF(PYTHONINTERP_FOUND)
     # check that Python version 2.x is used
     execute_process(COMMAND ${PYTHON_EXECUTABLE} -c
-                         "import sys; print sys.version[0]"
+                         "import sys; print(sys.version[0])"
                           OUTPUT_VARIABLE PYTHON_MAJOR_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
     IF(${PYTHON_MAJOR_VERSION} EQUAL 2)
         SET(PYTHONINTERP_V2_FOUND 1)
diff --git a/config/VIGRA_ADD_NUMPY_MODULE.cmake b/config/VIGRA_ADD_NUMPY_MODULE.cmake
index d56f74b..50b2383 100644
--- a/config/VIGRA_ADD_NUMPY_MODULE.cmake
+++ b/config/VIGRA_ADD_NUMPY_MODULE.cmake
@@ -6,22 +6,22 @@
 #                                   [LIBRARIES dependency1 dependency2 ...]
 #                                   [VIGANUMPY])
 #
-#        'modulename' is the module name to be used within Python (e.g. 'import modulename'). 
+#        'modulename' is the module name to be used within Python (e.g. 'import modulename').
 #        Unless 'VIGRANUMPY' is specified (see below), it is also the cmake target name.
 #
-#        SOURCE are the C++ sources of the module, LIBRARIES the necessary libraries. 
+#        SOURCE are the C++ sources of the module, LIBRARIES the necessary libraries.
 #        Dependency syntax must conform to the requirements of the cmake command
 #        TARGET_LINK_LIBRARIES. Modules are automatically linked against vigranumpycore
-#        and its dependencies (libpython, boost_python), so it is not necessary to state 
+#        and its dependencies (libpython, boost_python), so it is not necessary to state
 #        this dependency explicitly.
-#   
+#
 #        If VIGRANUMPY is given, the module is considered part of 'vigranumpy' and will
 #        be compiled and installed along with the other vigranumpy modules (otherwise,
-#        no installation target will be defined). The cmake target name becomes 
-#        'vigranumpy_modulename' in order to get useful alphabetic sorting of 
+#        no installation target will be defined). The cmake target name becomes
+#        'vigranumpy_modulename' in order to get useful alphabetic sorting of
 #        targets in project files.
 FUNCTION(VIGRA_ADD_NUMPY_MODULE target)
-    
+
     # parse the args
     set(v SOURCES)
     set(PART_OF_VIGRANUMPY 0)
@@ -36,7 +36,7 @@ FUNCTION(VIGRA_ADD_NUMPY_MODULE target)
             set(${v} ${${v}} ${i})
         endif()
     endforeach(i)
-    
+
     IF(PART_OF_VIGRANUMPY)
         set(TARGET_NAME vigranumpy_${target})
         if(target MATCHES "^core$")
@@ -49,44 +49,42 @@ FUNCTION(VIGRA_ADD_NUMPY_MODULE target)
         set(LIBRARY_NAME ${target})
     ENDIF()
 
-    ADD_LIBRARY(${TARGET_NAME} SHARED ${SOURCES})    
-    
+    ADD_LIBRARY(${TARGET_NAME} SHARED ${SOURCES})
+
     IF(PART_OF_VIGRANUMPY)
         ADD_DEPENDENCIES(vigranumpy ${TARGET_NAME})
-        
-        # Store dependencies as a custom target property, so that we can 
+
+        # Store dependencies as a custom target property, so that we can
         # later query them.
-        # TODO: Does cmake provide a standard way to query the dependencies? 
+        # TODO: Does cmake provide a standard way to query the dependencies?
         GET_TARGET_PROPERTY(VIGRANUMPY_DEPENDS vigranumpy VIGRA_DEPENDS)
         IF(NOT VIGRANUMPY_DEPENDS)
             set(VIGRANUMPY_DEPENDS "")
         ENDIF()
         SET_TARGET_PROPERTIES(vigranumpy PROPERTIES VIGRA_DEPENDS "${VIGRANUMPY_DEPENDS} ${TARGET_NAME}")
     ENDIF()
-    
+
     if(DEFINED LIBRARIES)
         TARGET_LINK_LIBRARIES(${TARGET_NAME} ${LIBRARIES})
     endif()
-    
-    # if(LIBRARY_NAME MATCHES "^vigranumpycore$")
-        # TARGET_LINK_LIBRARIES(${TARGET_NAME} ${VIGRANUMPY_LIBRARIES})
-    # else()
-        # TARGET_LINK_LIBRARIES(${TARGET_NAME} ${VIGRANUMPY_LIBRARIES} vigranumpy_core)
-    # endif()
-    
+
     TARGET_LINK_LIBRARIES(${TARGET_NAME} ${VIGRANUMPY_LIBRARIES})
-    
+
     IF(PYTHON_PLATFORM MATCHES "^windows$")
-        SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${LIBRARY_NAME}" 
+        SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${LIBRARY_NAME}"
                                                            PREFIX "" SUFFIX  ".pyd")
     ELSEIF(MACOSX)
-        SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${LIBRARY_NAME}" PREFIX "" 
-                              SUFFIX ".so" INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${VIGRANUMPY_INSTALL_DIR}/vigra") 
+        IF(${CMAKE_MAJOR_VERSION} LESS 3)
+            SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${LIBRARY_NAME}" PREFIX ""
+                              SUFFIX ".so" INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${VIGRANUMPY_INSTALL_DIR}/vigra")
+        ELSE()
+            SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${LIBRARY_NAME}" PREFIX ""    SUFFIX ".so" )
+        ENDIF()
     ELSE()
-        SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${LIBRARY_NAME}" 
+        SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${LIBRARY_NAME}"
                                                            PREFIX "")
     ENDIF()
-    
+
     IF(PART_OF_VIGRANUMPY)
         IF(PYTHON_PLATFORM MATCHES "^windows$")
             INSTALL(TARGETS ${TARGET_NAME} RUNTIME DESTINATION ${VIGRANUMPY_INSTALL_DIR}/vigra)
@@ -94,14 +92,13 @@ FUNCTION(VIGRA_ADD_NUMPY_MODULE target)
             INSTALL(TARGETS ${TARGET_NAME}
                     LIBRARY DESTINATION ${VIGRANUMPY_INSTALL_DIR}/vigra)
         ENDIF()
-        
+
         # create a temporary vigranumpy installation in ${vigranumpy_tmp_dir}
         # (required for testing and documentation generation)
-        GET_TARGET_PROPERTY(loc ${TARGET_NAME} LOCATION)
         ADD_CUSTOM_COMMAND(
             TARGET ${TARGET_NAME}
             POST_BUILD
-            COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${loc} ${vigranumpy_tmp_dir}/
-            COMMENT "Copying module to temporary module directory")
+            COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different $<TARGET_FILE:${TARGET_NAME}> ${vigranumpy_tmp_dir}/
+            COMMENT "Copying target ${TARGET_NAME} to temporary module directory")
     ENDIF()
 ENDFUNCTION(VIGRA_ADD_NUMPY_MODULE)
diff --git a/config/VigraAddTest.cmake b/config/VigraAddTest.cmake
index eedbe35..8a07975 100644
--- a/config/VigraAddTest.cmake
+++ b/config/VigraAddTest.cmake
@@ -19,10 +19,10 @@ MACRO(VIGRA_NATIVE_PATH out in)
         STRING(REGEX REPLACE "\\$\\([^\\)]*\\)" "%CONFIGURATION%" ${out} "${${out}}")
     ENDIF()
     IF(MINGW)
-        STRING(REGEX REPLACE "/" "\\\\" ${out} "${${out}}")
-    ELSE()
-        file(TO_NATIVE_PATH "${${out}}" ${out})
+        # turn "c:/" into "/c/"
+        STRING(REGEX REPLACE "^([a-zA-Z]):" "/\\1" ${out} "${${out}}")
     ENDIF()
+    file(TO_NATIVE_PATH "${${out}}" ${out})
 ENDMACRO(VIGRA_NATIVE_PATH)
 
 FUNCTION(VIGRA_ADD_TEST target)
@@ -37,96 +37,106 @@ FUNCTION(VIGRA_ADD_TEST target)
             set(${v} ${${v}} ${i})
         endif()
     endforeach(i)
-    
+
     FILE(GLOB TESTSUCCESS_FOUND ${CMAKE_CURRENT_BINARY_DIR}/testsuccess.cxx)
     IF(NOT TESTSUCCESS_FOUND)
-        FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/testsuccess.cxx 
+        FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/testsuccess.cxx
          "// auto-generated dummy file to force re-execution of failed tests
 ")
     ENDIF()
     SET(SOURCES ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/testsuccess.cxx)
-    
-    # configure the target 
+
+    # configure the target
     IF(AUTOBUILD_TESTS)
         ADD_EXECUTABLE(${target} ${SOURCES})
     ELSE()
         ADD_EXECUTABLE(${target} EXCLUDE_FROM_ALL ${SOURCES})
     ENDIF()
-    
+
     ADD_DEPENDENCIES(check_cpp ${target})
     ADD_DEPENDENCIES(ctest ${target})
     if(DEFINED LIBRARIES)
         TARGET_LINK_LIBRARIES(${target} ${LIBRARIES})
     endif()
-    
-    # find the test executable
-    GET_TARGET_PROPERTY(${target}_executable ${target} LOCATION)
-    VIGRA_NATIVE_PATH(VIGRA_TEST_EXECUTABLE ${${target}_executable})
-    
-    # Windows: set the DLL path
-    set(VIGRA_PATH "")
-    if(WIN32)
-        IF(CYGWIN)
-            SET(PATHSEP ":")
-        ELSE()
-            SET(PATHSEP ";")
-        ENDIF()
-        FOREACH(lib ${LIBRARIES})
+
+    # add dependencies to the PATH
+    cmake_policy(PUSH)
+    if(POLICY CMP0026)
+        # allow 'GET_TARGET_PROPERTY(... LOCATION)'
+        cmake_policy(SET CMP0026 OLD)
+    endif()
+
+    set(EXTRA_PATH "")
+    IF(MSVC)
+        SET(PATHSEP ";")
+    ELSE()
+        SET(PATHSEP ":")
+    ENDIF()
+    FOREACH(lib ${LIBRARIES})
+        if(TARGET ${lib})
             GET_TARGET_PROPERTY(p ${lib} LOCATION)
             if(p)
                 GET_FILENAME_COMPONENT(p ${p} PATH)
                 VIGRA_NATIVE_PATH(p ${p})
-                SET(VIGRA_PATH  "${p}${PATHSEP}${VIGRA_PATH}")
-           endif()
-        ENDFOREACH(lib)
-    endif()
-    
-    VIGRA_NATIVE_PATH(VIGRA_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
-    IF(MSVC OR MINGW)
-        SET(VIGRA_RUN_TEST "${CMAKE_CURRENT_BINARY_DIR}/run_${target}.bat")
-        SET(VIGRA_TEST_EXECUTABLE "\"${VIGRA_TEST_EXECUTABLE}\"")  # take care of paths with spaces
-        CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config/run_test.bat.in
-                       ${VIGRA_RUN_TEST}
+                SET(EXTRA_PATH  "${p}${PATHSEP}${EXTRA_PATH}")
+            endif()
+        endif()
+    ENDFOREACH(lib)
+    cmake_policy(POP)
+
+    # set up a script to run the test
+    IF(MSVC)
+        SET(VIGRA_TEST_EXECUTABLE "%CONFIGURATION%\\${target}.exe")
+        SET(VIGRA_TEST_SCRIPT     "run_${target}.bat")
+        CONFIGURE_FILE("${CMAKE_SOURCE_DIR}/config/run_test.bat.in"
+                       "${CMAKE_CURRENT_BINARY_DIR}/${VIGRA_TEST_SCRIPT}"
                        @ONLY)
     ELSE()
-        IF(VIGRA_RUN_TESTS_DIRECTLY)
-          SET(VIGRA_RUN_TEST "${CMAKE_CURRENT_BINARY_DIR}/${target}")
-        ELSE()
-          SET(VIGRA_RUN_TEST "${CMAKE_CURRENT_BINARY_DIR}/run_${target}.sh")
-          CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config/run_test.sh.in
-                         ${VIGRA_RUN_TEST}
-                         @ONLY)
-          EXECUTE_PROCESS(COMMAND chmod u+x ${VIGRA_RUN_TEST} OUTPUT_QUIET ERROR_QUIET)
-        ENDIF()
+        SET(VIGRA_TEST_EXECUTABLE "./${target}")
+        SET(VIGRA_TEST_SCRIPT     "${CMAKE_CURRENT_BINARY_DIR}/run_${target}.sh")
+        CONFIGURE_FILE("${CMAKE_SOURCE_DIR}/config/run_test.sh.in"
+                       "${VIGRA_TEST_SCRIPT}"
+                       @ONLY)
+        EXECUTE_PROCESS(COMMAND chmod u+x ${VIGRA_TEST_SCRIPT} OUTPUT_QUIET ERROR_QUIET)
     ENDIF()
-    
+
     # register the test execution command
     IF(NOT CMAKE_CFG_INTDIR STREQUAL ".")
         SET(VIGRA_CONFIGURATION ${CMAKE_CFG_INTDIR})
     ELSE()
         SET(VIGRA_CONFIGURATION)
     ENDIF()
-    
+
     IF(AUTOEXEC_TESTS)
         add_custom_command(
             TARGET ${target}
             POST_BUILD
-            COMMAND ${VIGRA_RUN_TEST} ARGS ${VIGRA_CONFIGURATION}
+            COMMAND ${VIGRA_TEST_SCRIPT} ARGS ${VIGRA_CONFIGURATION}
             COMMENT "Running ${target}")
     ENDIF()
-    
-    ADD_TEST(${target} ${VIGRA_RUN_TEST} ${VIGRA_CONFIGURATION})
-    
+
+    ADD_TEST(${target} ${VIGRA_TEST_SCRIPT} ${VIGRA_CONFIGURATION})
+
+    # if we configure for Visual Studio, setup the debug command
+    if(MSVC AND NOT (MSVC_VERSION VERSION_LESS "11"))
+        # FIXME: this may not portable between VC versions (works for 11.0 - 14.0)
+        set(VIGRA_TEST_EXE "${CMAKE_CURRENT_BINARY_DIR}/\$(Configuration)/${target}")
+        set(VIGRA_TEST_ENVIRONMENT "PATH=${EXTRA_PATH}%PATH%")
+        configure_file(${CMAKE_SOURCE_DIR}/config/testdebug.vcxproj.user.in
+                       ${CMAKE_CURRENT_BINARY_DIR}/${target}.vcxproj.user
+                       @ONLY)
+    endif()
+
     IF(WITH_VALGRIND AND VALGRIND_EXECUTABLE)
         IF(VALGRIND_SUPPRESSION_FILE)
             SET(VALGRIND_SUPPRESSION "--suppressions=${VALGRIND_SUPPRESSION_FILE}")
         ELSE()
             SET(VALGRIND_SUPPRESSION)
         ENDIF()
-        ADD_TEST(${target}_valgrind 
-                ${VALGRIND_EXECUTABLE} 
-                ${VALGRIND_SUPPRESSION} 
-                --error-exitcode=1 
+        ADD_TEST(${target}_valgrind
+                ${VALGRIND_EXECUTABLE}
+                ${VALGRIND_SUPPRESSION}
+                --error-exitcode=1
                 ${${target}_executable})
     ENDIF()
 
@@ -134,7 +144,7 @@ ENDFUNCTION(VIGRA_ADD_TEST)
 
 MACRO(VIGRA_COPY_TEST_DATA)
     FOREACH(test_data ${ARGN})
-        configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${test_data} 
+        configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${test_data}
                        ${CMAKE_CURRENT_BINARY_DIR}/${test_data}
                        COPYONLY)
     ENDFOREACH(test_data)
diff --git a/config/VigraConfigureThreading.cmake b/config/VigraConfigureThreading.cmake
new file mode 100644
index 0000000..ba807f9
--- /dev/null
+++ b/config/VigraConfigureThreading.cmake
@@ -0,0 +1,32 @@
+macro(VIGRA_CONFIGURE_THREADING)
+    get_property(THREADING_IMPLEMENTATION GLOBAL PROPERTY THREADING_IMPLEMENTATION)
+    if(NOT THREADING_IMPLEMENTATION)
+        message(FATAL_ERROR "Threading implementation not detected yet: "
+                            "Your CMakeLists file should not call VIGRA_CONFIGURE_THREADING() until after VigraDetectThreading " 
+                            "has been included from the root CMakeLists.txt file.")
+    endif()
+
+    set(THREADING_FOUND 1)
+    if(THREADING_IMPLEMENTATION MATCHES "boost")
+        include_directories(${Boost_INCLUDE_DIR})
+        set(THREADING_LIBRARIES ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${Boost_CHRONO_LIBRARY})
+    elseif(THREADING_IMPLEMENTATION MATCHES "std")
+        # Great, we can use the std library.  Nothing to do here...
+    elseif(THREADING_IMPLEMENTATION MATCHES "none")
+        if("${ARGN}" MATCHES "REQUIRED")
+            message(FATAL_ERROR 
+                "***********************************************\n"
+                "${THREADING_TEST_OUTPUT}\n"
+                "***********************************************\n"
+                "C++ threading is required, but your compiler doesn't support it. \n"
+                "For reference, the failed compiler output is shown above. \n"
+                "Try to run cmake with '-DWITH_BOOST_THREAD=1'.\n")
+        else()
+            message("(Compiling single threaded, consider running 'cmake -DWITH_BOOST_THREAD=1')")
+            add_definitions(-DVIGRA_SINGLE_THREADED)
+            set(THREADING_FOUND 0)
+        endif()
+    else()
+        message(FATAL_ERROR "CMakeLists bug: Unknown threading implementation")
+    endif()
+endmacro(VIGRA_CONFIGURE_THREADING)
diff --git a/config/VigraDetectCppVersion.cmake b/config/VigraDetectCppVersion.cmake
new file mode 100644
index 0000000..7aef322
--- /dev/null
+++ b/config/VigraDetectCppVersion.cmake
@@ -0,0 +1,21 @@
+macro(VIGRA_DETECT_CPP_VERSION)
+
+try_run(RUN_RESULT COMPILE_SUCCEEDED
+        ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/config/output_cplusplus_version.cxx
+        COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT_FROM_CPP_DETECT
+        RUN_OUTPUT_VARIABLE VIGRA_CPP_VERSION)
+
+    if(NOT COMPILE_SUCCEEDED)
+        message(FATAL_ERROR "Failed to detect c++ version with a simple test program!  Compiler Output is below.\n"
+                "${COMPILE_OUTPUT_FROM_CPP_DETECT}")
+    endif()
+
+    if(RUN_RESULT)
+        message(FATAL_ERROR "Failed to detect c++ version with a simple test program!\n"
+			    "Test program compiled, but did not execute cleanly. Run output is shown below.\n"
+ 			    "${VIGRA_CPP_VERSION}")
+    endif()
+
+    message(STATUS "Detected C++ version: ${VIGRA_CPP_VERSION}")
+
+endmacro(VIGRA_DETECT_CPP_VERSION)
diff --git a/config/VigraDetectThreading.cmake b/config/VigraDetectThreading.cmake
new file mode 100644
index 0000000..87a7ff3
--- /dev/null
+++ b/config/VigraDetectThreading.cmake
@@ -0,0 +1,53 @@
+#
+# This file determines which threading implementation, if any should be used for compiling vigra source files.
+# Source modules should use VIGRA_CONFIGURE_THREADING() from VigraConfigureThreading.cmake to set includes/preprocessor definitions.
+#
+
+cmake_minimum_required(VERSION 2.8)
+
+get_property(THREADING_IMPLEMENTATION GLOBAL PROPERTY THREADING_IMPLEMENTATION)
+if(THREADING_IMPLEMENTATION)
+    message(FATAL_ERROR "VigraDetectThreading.cmake should be included exactly once, from the root CMakeLists.txt file.  There should be no need to include it more than once.")
+endif()
+
+if(WITH_BOOST_THREAD)
+    if(Boost_FOUND)
+        # See boost library list, below.
+        MESSAGE(STATUS "Checking for threading support:   boost::thread")
+        set_property(GLOBAL PROPERTY THREADING_IMPLEMENTATION "boost")
+    else()
+        MESSAGE(FATAL_ERROR "Cmake was run with '-DWITH_BOOST_THREAD=1', but required boost components were not found.")
+    endif()
+else()
+    # Save original flags before we add new ones, in case there's no need for the new ones.
+    set(ORIG_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
+
+    if (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0")
+        SET(CXX_THREADING_FLAGS "-pthread -std=c++0x")
+    elseif(CMAKE_COMPILER_IS_GNUCXX)
+        SET(CXX_THREADING_FLAGS "-pthread -std=c++11")
+    elseif(NOT MSVC)
+        SET(CXX_THREADING_FLAGS "-std=c++11")
+    endif()
+
+    # add the threading flags if they are not already there
+    if(CXX_THREADING_FLAGS AND NOT ("${CMAKE_CXX_FLAGS}" MATCHES "pthread"))
+         SET(CMAKE_CXX_FLAGS "${CXX_THREADING_FLAGS} ${CMAKE_CXX_FLAGS}")
+    endif()
+    TRY_COMPILE(STD_THREADING_FOUND
+        ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/config/check_std_thread.cxx
+        OUTPUT_VARIABLE THREADING_TEST_OUTPUT )
+
+    if(STD_THREADING_FOUND)
+        MESSAGE(STATUS "Checking for threading support:   std::thread")
+        if(CXX_THREADING_FLAGS)
+            MESSAGE(STATUS "    (added compiler flags: ${CXX_THREADING_FLAGS})")
+        endif()
+        set_property(GLOBAL PROPERTY THREADING_IMPLEMENTATION "std")
+    else()
+        MESSAGE(STATUS "Checking for threading support:   NOT FOUND")
+        set_property(GLOBAL PROPERTY THREADING_IMPLEMENTATION "none")
+        # Revert to old CXX_FLAGS
+        set(CMAKE_CXX_FLAGS ${ORIG_CMAKE_CXX_FLAGS})
+    endif()
+endif()
diff --git a/config/VigraFindPackage.cmake b/config/VigraFindPackage.cmake
index e7c1288..f883b74 100644
--- a/config/VigraFindPackage.cmake
+++ b/config/VigraFindPackage.cmake
@@ -27,9 +27,7 @@ MACRO(VIGRA_FIND_PACKAGE package)
         endif()
     endforeach(i)
 
-    foreach(name ${NAMES})
-        SET(${package}_NAMES ${package}_NAMES ${name})
-    endforeach(name)
+    SET(${package}_NAMES ${NAMES} ${${package}_NAMES})
 
     IF(DEFINED COMPONENTS)
         SET(COMPONENTS COMPONENTS ${COMPONENTS})
@@ -51,7 +49,11 @@ MACRO(VIGRA_FIND_PACKAGE package)
                 ELSE()
                     SET(BOOST_INCLUDEDIR ${path}/include) # standard include path
                 ENDIF()
-                SET(BOOST_LIBRARYDIR ${path}/lib)
+                IF(EXISTS "${path}/stage/lib")
+                    SET(BOOST_LIBRARYDIR ${path}/stage/lib) # boost's default library path
+                ELSE()
+                    SET(BOOST_LIBRARYDIR ${path}/lib) # standard library path
+                ENDIF()
             ELSE()
                 SET(CMAKE_INCLUDE_PATH ${path}/include)
                 SET(CMAKE_LIBRARY_PATH ${path}/lib)
diff --git a/config/VigraSetDefaults.cmake b/config/VigraSetDefaults.cmake
index 3a3f7dd..3457126 100644
--- a/config/VigraSetDefaults.cmake
+++ b/config/VigraSetDefaults.cmake
@@ -36,6 +36,10 @@ SET(WITH_HDF5 ${WITH_HDF5}
     FORCE)
     
 OPTION(WITH_OPENEXR "Support for the OpenEXR graphics format" OFF)
+OPTION(WITH_LEMON "Support for the Lemon Graph library " OFF)
+OPTION(WITH_BOOST_GRAPH "Support for the BOOST Graph library " OFF)
+
+OPTION(WITH_BOOST_THREAD "Use boost::thread instead of std::thread" OFF)
 
 IF(NOT DEFINED WITH_VIGRANUMPY)
     SET(WITH_VIGRANUMPY "ON")
diff --git a/config/checkTemplateDepth.cxx b/config/checkTemplateDepth.cxx
new file mode 100644
index 0000000..ecfe35a
--- /dev/null
+++ b/config/checkTemplateDepth.cxx
@@ -0,0 +1,16 @@
+template <int N>
+struct Sum
+{
+    static const int sum = 1 + Sum<N-1>::sum;
+};
+
+template <>
+struct Sum<0>
+{
+    static const int sum = 0;
+};
+
+int main()
+{
+    static const int sum = Sum<DEPTH>::sum;
+}
diff --git a/config/check_std_thread.cxx b/config/check_std_thread.cxx
new file mode 100644
index 0000000..11ecda1
--- /dev/null
+++ b/config/check_std_thread.cxx
@@ -0,0 +1,3 @@
+#include <thread>
+int main() { std::this_thread::yield(); } // https://github.com/ukoethe/vigra/issues/220
+
diff --git a/config/nuget/vigra.nuspec b/config/nuget/vigra.nuspec
new file mode 100644
index 0000000..67d959e
--- /dev/null
+++ b/config/nuget/vigra.nuspec
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
+    <metadata>
+        <id>vigra</id>
+        <version>1.10.0</version>
+        <title>vigra</title>
+        <authors>Ullrich Koethe</authors>
+        <licenseUrl>http://ukoethe.github.io/vigra/LICENSE.txt</licenseUrl>
+        <projectUrl>http://hci.iwr.uni-heidelberg.de/vigra/</projectUrl>
+        <iconUrl>http://ukoethe.github.io/vigra/vigra_logo.gif</iconUrl>
+        <requireLicenseAcceptance>false</requireLicenseAcceptance>
+        <description>A generic C++ library for image analysis.</description>
+        <releaseNotes>first nuget version</releaseNotes>
+        <copyright>Copyright 2014</copyright>
+        <tags>VIGRA, image analysis, image processing, native</tags>
+        <dependencies>
+          <dependency id="libpng" version="1.5.10" />
+          <dependency id="libtiff" version="4.0.1" />
+          <dependency id="libjpeg" version="9.0.1" />
+          <dependency id="vigra.redist" version="1.10.0" />
+        </dependencies>
+    </metadata>
+    
+    <files>
+        <file src="include\**\*.*" target="build\native\include" />
+        <file src="lib\*.lib" target="build\native\lib\x64\v110" />
+        <file src="vigra.targets" target="build\native\vigra.targets" />
+    </files>
+</package>
diff --git a/config/nuget/vigra.redist.nuspec b/config/nuget/vigra.redist.nuspec
new file mode 100644
index 0000000..901c1db
--- /dev/null
+++ b/config/nuget/vigra.redist.nuspec
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
+    <metadata>
+        <id>vigra.redist</id>
+        <version>1.10.0</version>
+        <title>vigra Redist</title>
+        <authors>Ullrich Koethe</authors>
+        <licenseUrl>http://ukoethe.github.io/vigra/LICENSE.txt</licenseUrl>
+        <projectUrl>http://hci.iwr.uni-heidelberg.de/vigra/</projectUrl>
+        <iconUrl>http://ukoethe.github.io/vigra/vigra_logo.gif</iconUrl>
+        <requireLicenseAcceptance>false</requireLicenseAcceptance>
+        <description>Redistributable components for package 'vigra'.</description>
+        <releaseNotes>first nuget version</releaseNotes>
+        <copyright>Copyright 2014</copyright>
+        <tags>VIGRA, image analysis, image processing, native</tags>
+    </metadata>
+    
+    <files>
+        <file src="bin\*.dll" target="build\native\bin\x64\v110" />
+        <file src="vigra.redist.targets" target="build\native\vigra.redist.targets" />
+    </files>
+</package>
diff --git a/config/nuget/vigra.redist.targets b/config/nuget/vigra.redist.targets
new file mode 100644
index 0000000..d4f7d3f
--- /dev/null
+++ b/config/nuget/vigra.redist.targets
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
+  <Target Name="vigra_redist_AfterBuild"  AfterTargets="AfterBuild">
+    <Copy Condition="'$(Platform.ToLower())' == 'x64' And '$(PlatformToolset.ToLower())' == 'v110'" SourceFiles="$(MSBuildThisFileDirectory)..\..\build\native\bin\x64\v110\vigraimpex.dll" DestinationFolder="$(TargetDir)" SkipUnchangedFiles="true" />
+  </Target>
+</Project>
\ No newline at end of file
diff --git a/config/nuget/vigra.targets b/config/nuget/vigra.targets
new file mode 100644
index 0000000..2fde5d1
--- /dev/null
+++ b/config/nuget/vigra.targets
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
+  <ItemDefinitionGroup Condition="'$(Platform.ToLower())' == 'x64' And '$(PlatformToolset.ToLower())' == 'v110'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)..\..\build\native\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>$(MSBuildThisFileDirectory)..\..\build\native\lib\x64\v110\vigraimpex.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+</Project>
\ No newline at end of file
diff --git a/config/output_cplusplus_version.cxx b/config/output_cplusplus_version.cxx
new file mode 100644
index 0000000..d5a9e10
--- /dev/null
+++ b/config/output_cplusplus_version.cxx
@@ -0,0 +1,19 @@
+#include <iostream>
+
+int main() {
+    if (__cplusplus == 1)
+    {
+        // This is a workaround for a gcc bug:
+        // http://stackoverflow.com/questions/7530047/gnu-c-macro-cplusplus-standard-conform
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+        std::cout << 201103;
+#else
+        std::cout << 199711;
+#endif
+    }
+    else
+    {
+        std::cout << __cplusplus;
+    }
+    return 0;
+}
diff --git a/config/run_test.bat.in b/config/run_test.bat.in
index 1626353..f0a6037 100644
--- a/config/run_test.bat.in
+++ b/config/run_test.bat.in
@@ -7,12 +7,14 @@ if [%1] NEQ [] (
 
 echo Testing configuration '%CONFIGURATION%'
 
-set PATH=@VIGRA_PATH@%PATH%
-cd @VIGRA_CURRENT_BINARY_DIR@
+set PATH=@EXTRA_PATH@%PATH%
+
+set SCRIPT_DIR=%~dp0
+cd "%SCRIPT_DIR%"
 
 cmd /c @VIGRA_TEST_EXECUTABLE@
 IF %ERRORLEVEL% NEQ 0 (
     rem this is the Windows version of 'touch'
     copy /b testsuccess.cxx+,, > NUL
-    exit %ERRORLEVEL% 
+    exit %ERRORLEVEL%
 )
diff --git a/config/run_test.sh.in b/config/run_test.sh.in
index 086fa1c..9e95ef3 100644
--- a/config/run_test.sh.in
+++ b/config/run_test.sh.in
@@ -1 +1 @@
-PATH=@VIGRA_PATH@$PATH && cd @VIGRA_CURRENT_BINARY_DIR@ && (@VIGRA_TEST_EXECUTABLE@ || { touch testsuccess.cxx; exit 1; } )
+PATH=@EXTRA_PATH@$PATH && cd @CMAKE_CURRENT_BINARY_DIR@ && (@VIGRA_TEST_EXECUTABLE@ || { touch testsuccess.cxx; exit 1; } )
diff --git a/config/testdebug.vcxproj.user.in b/config/testdebug.vcxproj.user.in
new file mode 100644
index 0000000..6bdbf41
--- /dev/null
+++ b/config/testdebug.vcxproj.user.in
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">
+    <LocalDebuggerCommand>@VIGRA_TEST_EXE@</LocalDebuggerCommand>
+    <LocalDebuggerCommandArguments>@VIGRA_TEST_ARGS@</LocalDebuggerCommandArguments>
+    <LocalDebuggerWorkingDirectory>@CMAKE_CURRENT_BINARY_DIR@</LocalDebuggerWorkingDirectory>
+    <LocalDebuggerEnvironment>@VIGRA_TEST_ENVIRONMENT@</LocalDebuggerEnvironment>
+    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LocalDebuggerCommand>@VIGRA_TEST_EXE@</LocalDebuggerCommand>
+    <LocalDebuggerCommandArguments>@VIGRA_TEST_ARGS@</LocalDebuggerCommandArguments>
+    <LocalDebuggerWorkingDirectory>@CMAKE_CURRENT_BINARY_DIR@</LocalDebuggerWorkingDirectory>
+    <LocalDebuggerEnvironment>@VIGRA_TEST_ENVIRONMENT@</LocalDebuggerEnvironment>
+    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
diff --git a/docsrc/Doxyfile.in b/docsrc/Doxyfile.in
index 03093aa..1d4ee82 100644
--- a/docsrc/Doxyfile.in
+++ b/docsrc/Doxyfile.in
@@ -14,169 +14,169 @@
 # 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 
+# 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.
 
 DOXYFILE_ENCODING      = UTF-8
 
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
 # by quotes) that should identify the project.
 
 PROJECT_NAME           = @PROJECT_NAME@
 
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
-# This could be handy for archiving the generated documentation or 
+# 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         = @vigra_version@
 
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
-# base path where the generated documentation will be put. 
-# If a relative path is entered, it will be relative to the location 
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# 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       = @DOCDIR@
 
-# 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 
+# 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 cause performance problems for the file system.
 
 CREATE_SUBDIRS         = 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. 
-# The default language is English, other supported languages are: 
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
-# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
-# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
-# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
-# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, 
+# 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.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
 # and Ukrainian.
 
 OUTPUT_LANGUAGE        = English
 
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
-# include brief member descriptions after the members that are listed in 
-# the file and class documentation (similar to JavaDoc). 
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) 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.
 
 BRIEF_MEMBER_DESC      = YES
 
-# If the REPEAT_BRIEF tag is set to YES (the default) 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 
+# If the REPEAT_BRIEF tag is set to YES (the default) 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.
 
 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" 
+# 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" "the"
 
-ABBREVIATE_BRIEF       = 
+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 
+# 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.
 
 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 
+# 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.
 
 INLINE_INHERITED_MEMB  = NO
 
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
-# path before files name in the file list and in the header files. If set 
+# If the FULL_PATH_NAMES tag is set to YES then 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.
 
 FULL_PATH_NAMES        = YES
 
-# If the FULL_PATH_NAMES tag is set to YES then 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 
+# If the FULL_PATH_NAMES tag is set to YES then 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.
 
 STRIP_FROM_PATH        = @PROJECT_SOURCE_DIR@/include
 
-# 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 include paths that 
+# 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 include paths that
 # are normally passed to the compiler using the -I flag.
 
 STRIP_FROM_INC_PATH    = @PROJECT_SOURCE_DIR@/include
 
-# 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 
+# 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.
 
 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 
-# comments will behave just like regular Qt-style comments 
+# 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
+# comments will behave just like regular Qt-style comments
 # (thus requiring an explicit @brief command for a brief description.)
 
 JAVADOC_AUTOBRIEF      = NO
 
-# 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 comments 
-# will behave just like regular Qt-style comments (thus requiring 
+# 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 comments
+# will behave just like regular Qt-style comments (thus requiring
 # an explicit \brief command for a brief description.)
 
 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 behaviour. 
-# The new default is to treat a multi-line C++ comment block as a detailed 
+# 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 behaviour.
+# 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 behaviour instead.
 
 MULTILINE_CPP_IS_BRIEF = NO
 
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
-# member inherits the documentation from any documented member that it 
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
 # re-implements.
 
 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 
+# 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.
 
 SEPARATE_MEMBER_PAGES  = NO
 
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# 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.
 
 TAB_SIZE               = 4
 
-# This tag can be used to specify a number of aliases that acts 
-# 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:". 
+# This tag can be used to specify a number of aliases that acts
+# 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                = configured_docdir="\@docdir\@"
@@ -186,37 +186,37 @@ ALIASES                += deprecatedAPI{1}="<a href=\"#\" id=\"\1_OldAPIToggle\"
 ALIASES                += deprecatedUsage{1}="<a href=\"#\" id=\"\1_OldUsageToggle\" onclick=\"return toggleHiddenDocumentation('\1_OldUsage', '\1_OldUsageToggle', 'deprecated examples');\">show deprecated examples</a><div id=\"\1_OldUsage\" style=\"display:none\">"
 ALIASES                += deprecatedEnd="</div>"
 
-# 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 
+# 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.
 
 OPTIMIZE_OUTPUT_FOR_C  = NO
 
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
-# sources only. Doxygen will then generate output that is more tailored for 
-# Java. For instance, namespaces will be presented as packages, qualified 
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
 # scopes will look different, etc.
 
 OPTIMIZE_OUTPUT_JAVA   = NO
 
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
-# sources only. Doxygen will then generate output that is more tailored for 
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
 # Fortran.
 
 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 
+# 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.
 
 OPTIMIZE_OUTPUT_VHDL   = NO
 
-# 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); v.s. 
-# func(std::string) {}). This also make the inheritance and collaboration 
+# 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); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
 # diagrams that involve STL classes more complete and accurate.
 
 BUILTIN_STL_SUPPORT    = NO
@@ -226,42 +226,42 @@ BUILTIN_STL_SUPPORT    = NO
 
 CPP_CLI_SUPPORT        = NO
 
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
-# Doxygen will parse them like normal C++ but will assume all classes use public 
+# Set the SIP_SUPPORT tag to YES if your project consists of sip 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.
 
 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 (the default) 
-# 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 
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# 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.
 
 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 
+# 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.
 
 DISTRIBUTE_GROUP_DOC   = NO
 
-# Set the SUBGROUPING tag to YES (the default) 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 
+# Set the SUBGROUPING tag to YES (the default) 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.
 
 SUBGROUPING            = YES
 
-# When TYPEDEF_HIDES_STRUCT 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 
+# When TYPEDEF_HIDES_STRUCT 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.
 
 TYPEDEF_HIDES_STRUCT   = NO
@@ -270,284 +270,284 @@ TYPEDEF_HIDES_STRUCT   = NO
 # 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 
+# 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 and EXTRACT_STATIC tags are set to YES
 
 EXTRACT_ALL            = NO
 
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
 # will be included in the documentation.
 
 EXTRACT_PRIVATE        = NO
 
-# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
 # will be included in the documentation.
 
 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 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.
 
 EXTRACT_LOCAL_CLASSES  = YES
 
-# This flag is only useful for Objective-C code. When set to YES local 
-# methods, which are defined in the implementation section but not in 
-# the interface are included in the documentation. 
+# This flag is only useful for Objective-C code. When 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 (the default) only methods in the interface are included.
 
 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 
+# 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.
 
 EXTRACT_ANON_NSPACES   = NO
 
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
-# undocumented members of documented classes, files or namespaces. 
-# If set to NO (the default) these members will be included in the 
-# various overviews, but no documentation section is generated. 
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) 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.
 
 HIDE_UNDOC_MEMBERS     = YES
 
-# 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 (the default) these classes will be included in the various 
+# 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 (the default) these classes will be included in the various
 # overviews. This option has no effect if EXTRACT_ALL is enabled.
 
 HIDE_UNDOC_CLASSES     = YES
 
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
-# friend (class|struct|union) declarations. 
-# If set to NO (the default) these declarations will be included in the 
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
 # documentation.
 
 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 (the default) these blocks will be appended to the 
+# 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 (the default) these blocks will be appended to the
 # function's detailed documentation block.
 
 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 (the default) then the documentation will be excluded. 
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
 # Set it to YES to include the internal documentation.
 
 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 
+# 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.
 
 CASE_SENSE_NAMES       = YES
 
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
-# will show members with their full class and namespace scopes in the 
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
 # documentation. If set to YES the scope will be hidden.
 
 HIDE_SCOPE_NAMES       = YES
 
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
-# will put a list of the files that are included by a file in the documentation 
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
 # of that file.
 
 SHOW_INCLUDE_FILES     = YES
 
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
 # is inserted in the documentation for inline members.
 
 INLINE_INFO            = NO
 
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) 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 
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) 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.
 
 SORT_MEMBER_DOCS       = NO
 
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
-# brief documentation of file, namespace and class members alphabetically 
-# by member name. If set to NO (the default) the members will appear in 
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
 # declaration order.
 
 SORT_BRIEF_DOCS        = YES
 
-# 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 default) 
+# 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 default)
 # the group names will appear in their defined order.
 
 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 default), the class list will be sorted only by class name, 
-# not including the namespace part. 
+# 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 default), 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 
+# Note: This option applies only to the class list, not to the
 # alphabetical list.
 
 SORT_BY_SCOPE_NAME     = NO
 
-# The GENERATE_TODOLIST tag can be used to enable (YES) or 
-# disable (NO) the todo list. This list is created by putting \todo 
+# 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.
 
 GENERATE_TODOLIST      = YES
 
-# The GENERATE_TESTLIST tag can be used to enable (YES) or 
-# disable (NO) the test list. This list is created by putting \test 
+# 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.
 
 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 
+# 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.
 
 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 
+# 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.
 
 GENERATE_DEPRECATEDLIST= YES
 
-# The ENABLED_SECTIONS tag can be used to enable conditional 
+# The ENABLED_SECTIONS tag can be used to enable conditional
 # documentation sections, marked by \if sectionname ... \endif.
 
-ENABLED_SECTIONS       = 
+ENABLED_SECTIONS       =
 
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
-# the initial value of a variable or define consists of 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 initializer of individual variables and defines in the 
-# documentation can be controlled using \showinitializer or \hideinitializer 
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of 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 initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
 # command in the documentation regardless of this setting.
 
 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 
+# 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.
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories 
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
 # in the documentation. The default is NO.
 
 @DOXYGEN_BEFORE_1_8@ SHOW_DIRECTORIES       = NO
 
 # 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 
+# This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
 
 SHOW_FILES             = YES
 
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# 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 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 
+# 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. See the manual for examples.
 
-FILE_VERSION_FILTER    = 
+FILE_VERSION_FILTER    =
 
 #---------------------------------------------------------------------------
 # configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 
-# The QUIET tag can be used to turn on/off the messages that are generated 
+# The QUIET tag can be used to turn on/off the messages that are generated
 # by doxygen. Possible values are YES and NO. If left blank NO is used.
 
 QUIET                  = YES
 
-# The WARNINGS tag can be used to turn on/off the warning messages that are 
-# generated by doxygen. Possible values are YES and NO. If left blank 
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
 # NO is used.
 
 WARNINGS               = YES
 
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# If WARN_IF_UNDOCUMENTED 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.
 
 WARN_IF_UNDOCUMENTED   = NO
 
-# If WARN_IF_DOC_ERROR 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 
+# If WARN_IF_DOC_ERROR 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.
 
 WARN_IF_DOC_ERROR      = YES
 
-# This WARN_NO_PARAMDOC option can be abled to get warnings for 
-# functions that are documented, but have no documentation for their parameters 
-# or return value. If set to NO (the default) doxygen will only warn about 
-# wrong or incomplete parameter documentation, but not about the absence of 
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
 # documentation.
 
 WARN_NO_PARAMDOC       = NO
 
-# 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 
+# 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)
 
-WARN_FORMAT            = 
+WARN_FORMAT            =
 
-# 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 
+# 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 stderr.
 
-WARN_LOGFILE           = 
+WARN_LOGFILE           =
 
 #---------------------------------------------------------------------------
 # configuration options related to the input files
 #---------------------------------------------------------------------------
 
-# The INPUT tag can be 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 
+# The INPUT tag can be 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.
 
 INPUT                  = @PROJECT_SOURCE_DIR@/include \
                          @PROJECT_SOURCE_DIR@/docsrc
 
-# This tag can be used to specify the character encoding of the source files 
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
-# also the default input encoding. Doxygen uses libiconv (or the iconv built 
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. 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.
 
 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 pattern (like *.cpp 
-# and *.h) to filter out the source-files in the directories. If left 
-# blank the following patterns are tested: 
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_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 the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
 # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
 
 FILE_PATTERNS          = index.dxx \
@@ -559,87 +559,87 @@ FILE_PATTERNS          = index.dxx \
                          *.hxx \
                          viff.h
 
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
-# should be searched for input files as well. Possible values are YES and NO. 
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
 # If left blank NO is used.
 
 RECURSIVE              = YES
 
-# The EXCLUDE tag can be used to specify files and/or directories that should 
-# excluded from the INPUT source files. This way you can easily exclude a 
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# 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.
 
 EXCLUDE                = @PROJECT_SOURCE_DIR@/include/vigra/fftw.hxx
 
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
-# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
 # from the input.
 
 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 
+# 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       = 
+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, 
+# 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
 
 EXCLUDE_SYMBOLS        = vigra::detail
 
-# 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 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           = @PROJECT_SOURCE_DIR@/src/examples
 
-# 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 
+# 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       = *.cxx
 
-# 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. 
+# 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.
 # Possible values are YES and NO. If left blank NO is used.
 
 EXAMPLE_RECURSIVE      = NO
 
-# The IMAGE_PATH tag can be used to specify one or more files or 
-# directories that contain image that are included in the documentation (see 
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
 # the \image command).
 
 IMAGE_PATH             = @PROJECT_SOURCE_DIR@/src/images
 
-# 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 
+# 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.
 
-INPUT_FILTER           = 
+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 
-# info on how filters are used. If FILTER_PATTERNS is empty, 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
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
 # is applied to all files.
 
-FILTER_PATTERNS        = 
+FILTER_PATTERNS        =
 
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
-# INPUT_FILTER) will be used to filter the input files when producing source 
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
 # files to browse (i.e. when SOURCE_BROWSER is set to YES).
 
 FILTER_SOURCE_FILES    = NO
@@ -648,32 +648,32 @@ FILTER_SOURCE_FILES    = NO
 # 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 also 
+# 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 also
 # VERBATIM_HEADERS is set to NO.
 
 SOURCE_BROWSER         = NO
 
-# Setting the INLINE_SOURCES tag to YES will include the body 
+# Setting the INLINE_SOURCES tag to YES will include the body
 # of functions and classes directly in the documentation.
 
 INLINE_SOURCES         = NO
 
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
-# doxygen to hide any special comment blocks from generated source code 
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
 # fragments. Normal C and C++ comments will always remain visible.
 
 STRIP_CODE_COMMENTS    = NO
 
-# If the REFERENCED_BY_RELATION tag is set to YES 
-# then for each documented function all documented 
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
 # functions referencing it will be listed.
 
 REFERENCED_BY_RELATION = NO
 
-# If the REFERENCES_RELATION tag is set to YES 
-# then for each documented function all documented entities 
+# 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.
 
 REFERENCES_RELATION    = NO
@@ -685,16 +685,16 @@ REFERENCES_RELATION    = NO
 
 REFERENCES_LINK_SOURCE = 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 
+# 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.
 
 USE_HTAGS              = NO
 
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
-# will generate a verbatim copy of the header file for each class for 
+# If the VERBATIM_HEADERS tag is set to YES (the default) 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.
 
 VERBATIM_HEADERS       = YES
@@ -703,63 +703,63 @@ 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 
+# 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.
 
 ALPHABETICAL_INDEX     = YES
 
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
 # in which this list will be split (can be a number in the range [1..20])
 
 COLS_IN_ALPHA_INDEX    = 4
 
-# 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 one or more prefixes that 
+# 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 one or more prefixes that
 # should be ignored while generating the index headers.
 
-IGNORE_PREFIX          = 
+IGNORE_PREFIX          =
 
 #---------------------------------------------------------------------------
 # configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
 # generate HTML output.
 
 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 
+# 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. If left blank `html' will be used as the default path.
 
 HTML_OUTPUT            = @DOCDIR@/vigra
 
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
 # doxygen will generate files with .html extension.
 
 HTML_FILE_EXTENSION    = .html
 
-# The HTML_HEADER tag can be used to specify a personal HTML header for 
-# each generated HTML page. If it is left blank doxygen will generate a 
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
 # standard header.
 
 HTML_HEADER            = @PROJECT_SOURCE_DIR@/docsrc/header.html
 
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
-# each generated HTML page. If it is left blank doxygen will generate a 
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
 # standard footer.
 
 HTML_FOOTER            = @PROJECT_SOURCE_DIR@/docsrc/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 the tag is left blank doxygen 
-# will generate a default style sheet. Note that doxygen will try to copy 
-# the style sheet file to the HTML output directory, so don't put your own 
+# 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 the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
 # stylesheet in the HTML output directory as well, or it will be erased!
 
 HTML_STYLESHEET        = @PROJECT_SOURCE_DIR@/docsrc/vigra.css
@@ -784,68 +784,68 @@ HTML_STYLESHEET        = @PROJECT_SOURCE_DIR@/docsrc/vigra.css
 HTML_EXTRA_FILES       = @PROJECT_SOURCE_DIR@/src/examples/lenna_color.gif \
                          @PROJECT_SOURCE_DIR@/src/examples/lenna_gray.gif
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
-# files or namespaces will be aligned in HTML using tables. If set to 
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
 # NO a bullet list will be used.
 
 @DOXYGEN_BEFORE_1_8@ HTML_ALIGN_MEMBERS     = YES
 
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
-# will be generated that can be used as input for tools like the 
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
 # of the generated HTML documentation.
 
 GENERATE_HTMLHELP      = NO
 
-# 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, 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 
+# 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, 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.
 
 GENERATE_DOCSET        = NO
 
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
-# feed. A documentation feed provides an umbrella under which multiple 
-# documentation sets from a single provider (such as a company or product suite) 
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# 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.
 
 DOCSET_FEEDNAME        = "Doxygen generated docs"
 
-# When GENERATE_DOCSET tag is set to YES, 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 
+# When GENERATE_DOCSET tag is set to YES, 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.
 
 DOCSET_BUNDLE_ID       = org.doxygen.Project
 
-# 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. For this to work a browser that supports 
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# 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. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
 # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
 
 HTML_DYNAMIC_SECTIONS  = NO
 
-# If the GENERATE_HTMLHELP tag is set to YES, 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 
+# If the GENERATE_HTMLHELP tag is set to YES, 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.
 
-CHM_FILE               = 
+CHM_FILE               =
 
-# If the GENERATE_HTMLHELP tag is set to YES, 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 
+# If the GENERATE_HTMLHELP tag is set to YES, 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.
 
-HHC_LOCATION           = 
+HHC_LOCATION           =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
-# controls if a separate .chi index file is generated (YES) or that 
+# If the GENERATE_HTMLHELP tag is set to YES, 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).
 
 GENERATE_CHI           = NO
@@ -854,26 +854,26 @@ GENERATE_CHI           = NO
 # is used to encode HtmlHelp index (hhk), content (hhc) and project file
 # content.
 
-CHM_INDEX_ENCODING     = 
+CHM_INDEX_ENCODING     =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
-# controls whether a binary table of contents is generated (YES) or a 
+# If the GENERATE_HTMLHELP tag is set to YES, 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.
 
 BINARY_TOC             = NO
 
-# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
 # to the contents of the HTML help documentation and to the tree view.
 
 TOC_EXPAND             = NO
 
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
-# top of each HTML page. The value NO (the default) enables the index and 
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
 # the value YES disables it.
 
 DISABLE_INDEX          = YES
 
-# This tag can be used to set the number of enum values (range [1..20]) 
+# This tag can be used to set the number of enum values (range [1..20])
 # that doxygen will group on one line in the generated HTML documentation.
 
 ENUM_VALUES_PER_LINE   = 4
@@ -881,11 +881,11 @@ ENUM_VALUES_PER_LINE   = 4
 # 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 FRAME, 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 (for instance Mozilla 1.0+, 
-# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
-# probably better off using the HTML help feature. Other possible values 
+# 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 (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature. Other possible values
 # for this tag are: HIERARCHIES, which will generate the Groups, Directories,
 # and Class Hiererachy pages using a tree view instead of an ordered list;
 # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
@@ -895,16 +895,16 @@ ENUM_VALUES_PER_LINE   = 4
 
 GENERATE_TREEVIEW      = NO
 
-# 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 
+# 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.
 
 TREEVIEW_WIDTH         = 250
 
-# Use this tag to change the font size of Latex formulas included 
-# as images in the HTML documentation. The default is 10. Note that 
-# 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 
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# 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.
 
 FORMULA_FONTSIZE       = 16
@@ -913,74 +913,74 @@ FORMULA_FONTSIZE       = 16
 # configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
 # generate Latex output.
 
 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 
+# 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. If left blank `latex' will be used as the default path.
 
-LATEX_OUTPUT           = 
+LATEX_OUTPUT           =
 
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
 # invoked. If left blank `latex' will be used as the default command name.
 
 LATEX_CMD_NAME         = latex
 
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
-# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
 # default command name.
 
 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 
+# 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.
 
 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, a4wide, letter, legal and 
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
 # executive. If left blank a4wide will be used.
 
 PAPER_TYPE             = a4wide
 
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
 # packages that should be included in the LaTeX output.
 
-EXTRA_PACKAGES         = 
+EXTRA_PACKAGES         =
 
-# 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 
+# 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. Notice: only use this tag if you know what you are doing!
 
-LATEX_HEADER           = 
+LATEX_HEADER           =
 
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
-# contain links (just like the HTML output) instead of page references 
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). 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.
 
 PDF_HYPERLINKS         = NO
 
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
-# plain latex in the generated Makefile. Set this option to YES to get a 
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
 # higher quality PDF documentation.
 
 USE_PDFLATEX           = NO
 
-# 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. 
+# 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.
 
 LATEX_BATCHMODE        = NO
 
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
-# include the index chapters (such as File Index, Compound Index, etc.) 
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
 # in the output.
 
 LATEX_HIDE_INDICES     = NO
@@ -989,68 +989,68 @@ LATEX_HIDE_INDICES     = NO
 # 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 very pretty with 
+# 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 very pretty with
 # other RTF readers or editors.
 
 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 
+# 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. If left blank `rtf' will be used as the default path.
 
-RTF_OUTPUT             = 
+RTF_OUTPUT             =
 
-# 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 
+# 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.
 
 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 other 
-# programs which support those fields. 
+# 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 other
+# programs which support those fields.
 # Note: wordpad (write) and others do not support links.
 
 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 
+# 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.
 
-RTF_STYLESHEET_FILE    = 
+RTF_STYLESHEET_FILE    =
 
-# Set optional variables used in the generation of an rtf document. 
+# Set optional variables used in the generation of an rtf document.
 # Syntax is similar to doxygen's config file.
 
-RTF_EXTENSIONS_FILE    = 
+RTF_EXTENSIONS_FILE    =
 
 #---------------------------------------------------------------------------
 # configuration options related to the man page output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
 # generate man pages
 
 GENERATE_MAN           = NO
 
-# 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 
+# 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. If left blank `man' will be used as the default path.
 
-MAN_OUTPUT             = 
+MAN_OUTPUT             =
 
-# The MAN_EXTENSION tag determines the extension that is added to 
+# The MAN_EXTENSION tag determines the extension that is added to
 # the generated man pages (default is the subroutine's section .3)
 
 MAN_EXTENSION          = .3
 
-# 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 
+# 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 is NO.
 
 MAN_LINKS              = NO
@@ -1059,33 +1059,33 @@ 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 
+# 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.
 
 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 
+# 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. If left blank `xml' will be used as the default path.
 
 XML_OUTPUT             = xml
 
-# The XML_SCHEMA tag can be used to specify an XML schema, 
-# which can be used by a validating XML parser to check the 
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
 # syntax of the XML files.
 
-XML_SCHEMA             = 
+#XML_SCHEMA             =
 
-# The XML_DTD tag can be used to specify an XML DTD, 
-# which can be used by a validating XML parser to check the 
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
 # syntax of the XML files.
 
-XML_DTD                = 
+#XML_DTD                =
 
-# 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 
+# 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.
 
 XML_PROGRAMLISTING     = YES
@@ -1094,10 +1094,10 @@ XML_PROGRAMLISTING     = YES
 # configuration options for the AutoGen Definitions output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
-# generate an AutoGen Definitions (see autogen.sf.net) file 
-# that captures the structure of the code including all 
-# documentation. Note that this feature is still experimental 
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see 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.
 
 GENERATE_AUTOGEN_DEF   = NO
@@ -1106,341 +1106,347 @@ 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 
+# 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.
 
 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 
+# 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.
 
 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 
+# 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.
 
 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 
+# 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.
 
-PERLMOD_MAKEVAR_PREFIX = 
+PERLMOD_MAKEVAR_PREFIX =
 
 #---------------------------------------------------------------------------
-# Configuration options related to the preprocessor   
+# Configuration options related to the preprocessor
 #---------------------------------------------------------------------------
 
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
-# evaluate all C-preprocessor directives found in the sources and include 
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
 # files.
 
 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 (the default) only conditional 
-# compilation will be performed. Macro expansion can be done in a controlled 
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
 # way by setting EXPAND_ONLY_PREDEF to YES.
 
 MACRO_EXPANSION        = YES
 
-# 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 
+# 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.
 
 EXPAND_ONLY_PREDEF     = YES
 
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
 # in the INCLUDE_PATH (see below) will be search if a #include is found.
 
 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 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.
 
-INCLUDE_PATH           = 
+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 
+# 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.
 
 INCLUDE_FILE_PATTERNS  = *.h \
                          *.hxx
 
-# 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 
-# 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 
+# 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
+# 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.
 
 PREDEFINED             = DOXYGEN \
                          __cplusplus \
                          VIGRA_EXPORT=
 
-# 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. 
+# 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.
 
 EXPAND_AS_DEFINED      = doxygen_overloaded_function
 
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
-# doxygen's preprocessor will remove all 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 
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all 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.
 
 SKIP_FUNCTION_MACROS   = YES
 
 #---------------------------------------------------------------------------
-# Configuration::additions related to external references   
+# Configuration::additions related to external references
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles. 
-# Optionally an initial location of the external documentation 
-# can be added for each tagfile. 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. If a location is present for each tag, the installdox tool 
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. 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. If a location is present for each tag, the installdox tool
 # does not have to be run to correct the links.
 # Note that 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 
+# 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               = 
+TAGFILES               =
 
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
 # a tag file that is based on the input files it reads.
 
 GENERATE_TAGFILE       = tagfile.tag
 
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
-# in the class index. If set to NO only the inherited external classes 
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
 # will be listed.
 
 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 
+# 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.
 
 EXTERNAL_GROUPS        = YES
 
-# The PERL_PATH should be the absolute path and name of the perl script 
+# The PERL_PATH should be the absolute path and name of the perl script
 # interpreter (i.e. the result of `which perl').
 
-PERL_PATH              = 
+PERL_PATH              =
 
 #---------------------------------------------------------------------------
-# Configuration options related to the dot tool   
+# Configuration options related to the dot tool
 #---------------------------------------------------------------------------
 
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
-# or super classes. Setting the tag to NO turns the diagrams off. Note that 
-# this option is superseded by the HAVE_DOT option below. This is only a 
-# fallback. It is recommended to install and use dot, since it yields more 
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
 # powerful graphs.
 
 CLASS_DIAGRAMS         = 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 
+# 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            = 
+MSCGEN_PATH            =
 
-# If set to YES, the inheritance and collaboration graphs will hide 
-# inheritance and usage relations if the target is undocumented 
+# 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.
 
 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, a graph visualization 
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# 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, 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)
 
 HAVE_DOT               = NO
 
-# By default doxygen will write a font called FreeSans.ttf to the output 
-# directory and reference it in all dot files that doxygen generates. This 
-# font does not include all possible unicode characters however, so when you need 
-# these (or just want a differently looking font) you can specify the font name 
-# using DOT_FONTNAME. You need 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 
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need 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.
 
-DOT_FONTNAME           = FreeSans
+DOT_FONTNAME           =
 
-# By default doxygen will tell dot to use the output directory to look for the 
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
-# different font using DOT_FONTNAME you can set the path where dot 
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
 # can find it using this tag.
 
-DOT_FONTPATH           = 
+DOT_FONTPATH           =
 
-# If the CLASS_GRAPH and HAVE_DOT tags are 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 
+# If the CLASS_GRAPH and HAVE_DOT tags are 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
 # the CLASS_DIAGRAMS tag to NO.
 
 CLASS_GRAPH            = YES
 
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for each documented class showing the direct and 
-# indirect implementation dependencies (inheritance, containment, and 
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are 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.
 
 COLLABORATION_GRAPH    = YES
 
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
 # will generate a graph for groups, showing the direct groups dependencies
 
 GROUP_GRAPHS           = 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 
+# 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.
 
 UML_LOOK               = NO
 
-# If set to YES, the inheritance and collaboration graphs will show the 
+# If set to YES, the inheritance and collaboration graphs will show the
 # relations between templates and their instances.
 
 TEMPLATE_RELATIONS     = NO
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
-# 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 
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# 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.
 
 INCLUDE_GRAPH          = YES
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
-# documented header file showing the documented files that directly or 
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
 # indirectly include this file.
 
 INCLUDED_BY_GRAPH      = YES
 
-# If the CALL_GRAPH and HAVE_DOT options are 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 
+# If the CALL_GRAPH and HAVE_DOT options are 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.
 
 CALL_GRAPH             = NO
 
-# If the CALLER_GRAPH and HAVE_DOT tags are 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 
+# If the CALLER_GRAPH and HAVE_DOT tags are 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.
 
 CALLER_GRAPH           = NO
 
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
 # will graphical hierarchy of all classes instead of a textual one.
 
 GRAPHICAL_HIERARCHY    = YES
 
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
-# then doxygen will show the dependencies a directory has on other directories 
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are 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.
 
 DIRECTORY_GRAPH        = YES
 
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
 # generated by dot. Possible values are png, jpg, or gif
 # If left blank png will be used.
 
 DOT_IMAGE_FORMAT       = png
 
-# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# The tag DOT_PATH 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.
 
-DOT_PATH               = 
+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 
+# 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).
 
-DOTFILE_DIRS           = 
+DOTFILE_DIRS           =
 
-# 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 
+# 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.
 
 DOT_GRAPH_MAX_NODES    = 50
 
-# 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 
+# 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.
 
 MAX_DOT_GRAPH_DEPTH    = 0
 
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
-# background. This is enabled by default, which results in a transparent 
-# background. 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 
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is enabled by default, which results in a transparent
+# background. 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).
 
 DOT_TRANSPARENT        = YES
 
-# Set the DOT_MULTI_TARGETS tag to YES 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) 
+# Set the DOT_MULTI_TARGETS tag to YES 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.
 
 DOT_MULTI_TARGETS      = NO
 
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
-# generate a legend page explaining the meaning of the various boxes and 
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
 # arrows in the dot generated graphs.
 
 GENERATE_LEGEND        = YES
 
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
-# remove the intermediate dot files that are used to generate 
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
 # the various graphs.
 
 DOT_CLEANUP            = YES
 
 #---------------------------------------------------------------------------
-# Configuration::additions related to the search engine   
+# Configuration::additions related to the search engine
 #---------------------------------------------------------------------------
 
-# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# The SEARCHENGINE tag specifies whether or not a search engine should be
 # used. If set to NO the values of all tags below this one will be ignored.
 
 SEARCHENGINE           = NO
+
+# In recent versions of Doxygen, the documentation files with extension .dxx
+# are not recognised any more if we do not also add this option (in addition
+# to the file extension options elsewhere in the file). See here:
+# https://www.stack.nl/~dimitri/doxygen/manual/config.html#cfg_extension_mapping
+EXTENSION_MAPPING = dxx=C++
diff --git a/docsrc/credits_changelog.dxx b/docsrc/credits_changelog.dxx
index 7c41f62..904b2a9 100644
--- a/docsrc/credits_changelog.dxx
+++ b/docsrc/credits_changelog.dxx
@@ -1,4 +1,4 @@
-/** 
+/**
 \page CreditsChangelog Credits and Changelog
 
 <b> Credits</b>
@@ -7,17 +7,17 @@
       <li> <a href="http://hci.iwr.uni-heidelberg.de/people/ukoethe/">Ullrich Köthe</a>
              originated and wrote the library.
 
-      <li> Mikhail Amchislavsky 
+      <li> Mikhail Amchislavsky
       (<a href="mailto:mamchisl at ucdavis.edu">mamchisl at ucdavis.edu</a>)
       contributed code to read and write PNM files.
 
-      <li> Hans Meine 
+      <li> Hans Meine
       (<a href="mailto:hans_meine at gmx.net">hans_meine at gmx.net</a>)
       contributed interface code for the FFTW Fourier transform library,
       the ImageArray class and the Gabor filter code. He also
       collaborated in the implementation of many other modules and contributed various improvements.
 
-      <li> Gunnar Kedenburg 
+      <li> Gunnar Kedenburg
       (<a href="mailto:gunnar at haquebright.de">gunnar at haquebright.de</a>)
       completely rewrote the image import/export library and implemented
       much of the \ref vigra::MultiArray functionality.
@@ -33,18 +33,18 @@
       <li> Kasim Terzic, Florian Heinrich and Benjamin Seppke
       implemented image analysis functionality for 3- and higher-dimensional data.
 
-      <li> Pablo d'Angelo, Douglas Wilkins, Lukas Jirkovsky and other members of the  
+      <li> Pablo d'Angelo, Douglas Wilkins, Lukas Jirkovsky and other members of the
       <a href="http://hugin.sourceforge.net">Hugin team</a> contributed various extensions of the impex
       library (UINT16/UINT32 support, ICC profile support, HDR and OpenEXR file types).
 
       <li> Rahul Nair implemented the \ref vigra::RandomForest classifier and VIGRA Matlab bindings.
-      
+
       <li> Michael Hanselmann and Martin Lindner implemented much of the HDF5 support. Michael Hanselmann
            also contributed his pLSA (probabilistic latent semantic analysis) implementation.
-      
-      <li> Nathan Huesken and Christoph Sommer helped a lot in developing 
+
+      <li> Nathan Huesken and Christoph Sommer helped a lot in developing
            <a href="../vigranumpy/index.html">vigranumpy</a>, the VIGRA Python bindings.
-           
+
       <li> Jens-Malte Gottfried contributed to the cmake-based build system.
 
       <li> Joachim Schleicher implemented a reader for the SIF file format.
@@ -56,268 +56,305 @@
       <li> Frank Lenzen contributed his implementations of total variation filters.
 
       <li> Patrick Fahner helped writing the tutorial.
-      
+
       <li> Stefan Schmidt made major contributions to \ref vigra::GridGraph.
 
-      <li> Numerous people reported bugs and made suggestions.
+      <li> Martin Bidlingmaier extended various image processing function to support block-wise execution on large data.
+
+      <li> Thorsten Beier implemented many \ref GraphDataStructures "graph-based image analysis algorithms" and parallel versions of important image processing functions.
+
+      <li> Benjamin Seppke contributed various \ref Registration "image registration" algorithms.
+
+      <li> Numerous people reported and fixed bugs and made suggestions.
 </ul>
 
 Many thanks to all!
 <p>
 
+<b> Changes from Version 1.10.0 to 1.11.0</b>
+
+<ul>
+      <li> Ported vigranumpy to Python 3.5.
+
+      <li> Added \ref ChunkedArrayClasses to store data larger than RAM as a collection of rectangular blocks.
+
+      <li> Added \ref vigra::ThreadPool and \ref parallel_foreach() for portable algorithm parallelization based on <tt>std::thread</tt>.
+
+      <li> Implemented parallel versions of Gaussian smoothing, Gaussian derivatives, connected components labeling, and union-find watersheds.
+
+      <li> Added graph-based image analysis, e.g. agglomerative clustering
+
+      <li> Included the callback mechanism described in <a href="http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates">"Impossibly Fast C++ Delegates"</a> by Sergey Ryazanov (needed for agglomerative clustering).
+
+      <li> Added many \ref Registration "image registration" functions.
+
+      <li> Extended the collection of \ref MultiArrayDistanceTransform "multi-dimensional distance transform" algorithms by vectorial DT, boundary DT, and eccentricity transform.
+
+      <li> Added \ref skeletonizeImage(), nonLocalMean(), multi-dimensional integral images.
+
+      <li> Added new 2D shape features based on skeletonization and the convex hull.
+
+      <li> Additional arithmetic and algebraic functions for \ref vigra::TinyVector.
+
+      <li> Added \ref vigra::CountingIterator.
+
+      <li> Minor improvements and bug fixes in the code and documentation.
+
+</ul>
+
 <b> Changes from Version 1.9.0 to 1.10.0</b>
 
-<ul>  
+<ul>
       <li> VIGRA got a \ref Tutorial !
-      
+
       <li> Significant simplification of the API: <tt>MultiArrayView</tt> arguments can now be passed to functions directly:
-      
+
       \code
       MultiArray<float> src(Shape2(200,100)), dest(src.shape());
       gaussianSmoothing(src, dest, 2.0);
       \endcode
-      
+
       The old syntax with \ref ArgumentObjectFactories (<tt>srcImageRange()</tt>, <tt>srcMultiArray()</tt> and relatives) remains valid, but is only required when the arguments are old-style <tt>BasicImage</tt>s.
-      
+
       <li> Made <tt>StridedArrayTag</tt> the default for \ref vigra::MultiArrayView .
-      
+
       <li> Added an efficient multi-dimensional \ref vigra::GridGraph class which support both the LEMON and boost::graph APIs.
-      
+
       <li> Generalized various algorithms to arbitrary dimensions (\ref gaussianGradientMultiArray(), \ref hessianOfGaussianMultiArray(), \ref gaussianDivergenceMultiArray(), \ref localMinima(), \ref localMaxima(), \ref labelMultiArray(), \ref watershedsMultiArray()).
-      
+
       <li> Added \ref slicSuperpixels() for arbitrary dimensions.
-      
+
       <li> Added automatic differentiation (see \ref vigra::autodiff::DualVector).
-      
+
       <li> Added \ref nonlinearLeastSquares() using the Levenberg-Marquardt algorithm and automatic differentiation.
-      
+
       <li> Added a function <tt>setCoordinateOffset()</tt> to the feature accumulator classes to enable block-wise computation of coordinate-based features.
-      
+
       <li> Added \ref vigra::MultiCoordinateIterator to enumerate the grid coordinates of a multi-dimensional array.
-      
+
       <li> Fixed thread-safety of <tt>RandomForest::learn()</tt> (random seeding) and <tt>RandomForest::predictLebels()</tt>.
-      
+
       <li> Improved HDF5 I/O for strided <tt>MultiArrayView</tt>s and HDF5 on-the-fly compression.
-      
+
       <li> Added support for multi-page TIFF to \ref importVolume() and \ref exportVolume(). Added support for Andor SIF to \ref importVolume().
-      
+
       <li> Added <tt>VigranumpyConfig.cmake</tt> to simplify cmake-based compilation of custom vigranumpy modules.
-      
-      <li> Minor improvements and bug fixes in the code and documentation. 
+
+      <li> Minor improvements and bug fixes in the code and documentation.
  </ul>
 
 <b> Changes from Version 1.8.0 to 1.9.0</b>
 
-<ul>  
+<ul>
       <li> Flexible incremental computation of image and region statistics via \ref FeatureAccumulators and corresponding Python bindings (see <a href="../vigranumpy/index.html#vigra.analysis.extractFeatures">vigra.analysis.extractFeatures()</a> and <a href="../vigranumpy/index.html#vigra.analysis.extractRegionFeatures">vigra.analysis.extractRegionFeatures()</a>).
-      
+
       <li> Simultaneous iteration over several arrays via \ref vigra::CoupledScanOrderIterator.
-      
+
       <li> Import and export of images with transparency: importImageAlpha() and exportImageAlpha().
-      
+
       <li> Image denoising by total variation filtering, see \ref NonLinearDiffusion and example <a href="total_variation_8cxx-example.html">total_variation.cxx</a>.
-      
+
       <li> Fixed Python bindings of \ref Unsupervised_Decomposition.
-      
+
       <li> Extended \ref vigra::SplineImageView to handle \ref vigra::TinyVector pixels.
-      
+
       <li> Various convenience functions for vigranumpy's <a href="../vigranumpy/index.html#vigra.VigraArray">VigraArray</a>.
-      
-      <li> Minor improvements and bug fixes in the code and documentation. 
+
+      <li> Minor improvements and bug fixes in the code and documentation.
  </ul>
 
 <b> Changes from Version 1.7.1 to 1.8.0</b>
 
-<ul>  
+<ul>
       <li> Various extensions to \ref LocalMinMax (3D algorithms, on-the-fly thresholding).
-      
+
       <li> Added \ref vigra::BucketQueue, \ref vigra::MappedBucketQueue.
-      
+
       <li> Refactored and extended 2D watershed algorithms (especially watershedsRegionGrowing()).
-      
+
       <li> Added the \ref vigra::Quaternion class.
-      
+
       <li> Added \ref Unsupervised_Decomposition.
-      
-      <li> Added mathematical functions (even(), odd(), gamma(), loggamma(), legendre(), besselJ(), besselY(), 
+
+      <li> Added mathematical functions (even(), odd(), gamma(), loggamma(), legendre(), besselJ(), besselY(),
            linearSequence(), indexSort(), inversePermutation(), applyPermutation(), checksum())
-      
-      <li> Implemented wrapper of the <a href="http://www.fftw.org/">FFTW library</a> to support 
+
+      <li> Implemented wrapper of the <a href="http://www.fftw.org/">FFTW library</a> to support
            arbitrary dimensional Fourier transforms (see \ref fourierTransform() and \ref vigra::FFTWPlan)
-           and FFT-based convolution (see \ref convolveFFT() and \ref vigra::FFTWConvolvePlan) and 
+           and FFT-based convolution (see \ref convolveFFT() and \ref vigra::FFTWConvolvePlan) and
            refactored \ref vigra::FFTWComplex.
-     
+
       <li> Added cannyEdgelListThreshold(), cannyEdgelList3x3Threshold().
-      
+
       <li> Added capability to handle subarrays and anisotropic resolution to separableConvolveMultiArray()
            and related Gaussian filters. Added <tt>windowRatio</tt> parameters to \ref vigra::Kernel1D::initGaussian()
            and \ref vigra::Kernel1D::initGaussianDerivative()
-      
+
       <li> Added \ref vigra::StridedScanOrderIterator and corresponding \ref vigra::MultiArrayView::begin().
-      
+
       <li> Extended \ref vigra::MultiArrayView. Added \ref vigra::Shape1 ... \ref vigra::Shape5 convenience typedefs.
-      
+
       <li> Implemented \ref MultiMathModule (arithmetic and algebraic functions for multi-dimensional arrays).
-      
+
       <li> Extended the \ref vigra::HDF5File class.
-      
+
       <li> Improved and documented the \ref TimingMacros.
-      
-      <li> Added support for the <a href="http://www.openexr.com/">OpenEXR image format</a> and multi-page TIFF. Improved 
+
+      <li> Added support for the <a href="http://www.openexr.com/">OpenEXR image format</a> and multi-page TIFF. Improved
            support for the SIF format.
-      
-      <li> <b>vigranumpy</b>: added <a href="../vigranumpy/index.html#axistags-and-the-vigraarray-data-structure">axistags </a> 
+
+      <li> <b>vigranumpy</b>: added <a href="../vigranumpy/index.html#axistags-and-the-vigraarray-data-structure">axistags </a>
            and completly re-implemented VigraArray and the conversion between
            Python and C++ arrays in terms of axistags.
-      
-      <li> Minor improvements and bug fixes in the code and documentation. 
+
+      <li> Minor improvements and bug fixes in the code and documentation.
  </ul>
 
 <b> Changes from Version 1.7.0 to 1.7.1</b>
 
-<ul>  
+<ul>
       <li> Fixed the build process for MacOS X.
-      
-      <li> Re-activated <tt>vigra-config</tt> (script to query VIGRA installation information) 
+
+      <li> Re-activated <tt>vigra-config</tt> (script to query VIGRA installation information)
            and added <tt>VigraConfig.cmake</tt> (query VIGRA installation information from
            within cmake).
-      
+
       <li> Added CDash support (nightly builds and tests).
-      
+
       <li> Added \ref convexHull().
-      
+
       <li> Added \ref vigra::Box.
-      
+
       <li> Added \ref vigra::Sampler class to sample given data in various ways.
-      
-      <li> Added much new functionality to the \ref vigra::RandomForest class 
+
+      <li> Added much new functionality to the \ref vigra::RandomForest class
            (e.g. more split strategies, variable importance measures, feature selection)
-      
+
       <li> Added readSIF() (reader for the Andor SIF file format).
-      
+
       <li> Added \ref vigra::HDF5File for easier navigation in HDF5 files.
-      
-      <li> Added recursive approximation of the Gaussian filter (\ref recursiveGaussianFilterX(), 
+
+      <li> Added recursive approximation of the Gaussian filter (\ref recursiveGaussianFilterX(),
            \ref recursiveGaussianFilterY())
-           
+
       <li> vigranumpy: added Gabor filtering.
-      
+
       <li> Fixed multi-threading bugs at various places.
-     
-      <li> Minor improvements and bug fixes in the code and documentation. 
+
+      <li> Minor improvements and bug fixes in the code and documentation.
  </ul>
 
 <b> Changes from Version 1.6.0 to 1.7.0</b>
 
-<ul>  
-      <li> Incompatible changes: 
+<ul>
+      <li> Incompatible changes:
       <ul>
            <li> Modified angle convention from counter-clockwise to clockwise
-                (see e.g. \ref vigra::Edgel). This fits better with the left-handed coordinate system 
+                (see e.g. \ref vigra::Edgel). This fits better with the left-handed coordinate system
                  we use.
-            
+
             <li> \ref symmetricEigensystem(): sort eigenvalues by decreasing value
                  (was: decreasing abs value)
       </ul>
-      
+
       <li> Implemented a new build system on the basis of <a href="http://www.cmake.org/">cmake</a>.
-      
+
       <li> Added \ref vigra::NumpyAnyArray and \ref vigra::NumpyArray, improved \ref vigra::MultiArrayView.
-      
+
       <li> Added <b><a href="../vigranumpy/index.html">vigranumpy</a></b> (VIGRA Python bindings).
-      
+
       <li> Added \ref VigraMatlab.
-      
+
       <li> Added support for <a href="http://www.hdfgroup.org/HDF5/">HDF5</a> import/export of arrays
            (see \ref VigraHDF5Impex).
-      
+
       <li> Added \ref vigra::RandomForest classifier.
-          
-      <li> Added constrained optimization functions: \ref nonnegativeLeastSquares(), 
+
+      <li> Added constrained optimization functions: \ref nonnegativeLeastSquares(),
            \ref quadraticProgramming(), \ref leastAngleRegression() (LASSO and non-negative LASSO).
-          
+
       <li> Added \ref choleskySolve() and improved \ref choleskyDecomposition() (in-place capability).
-      
+
       <li> Added \ref symmetric2x2Eigenvalues() and \ref symmetric3x3Eigenvalues() for
            fast eigenvalue computation on small matrices.
-      
+
       <li> Added \ref meshGrid().
-      
+
       <li> Added \ref vigra::FixedPoint16.
-      
-      <li> Minor improvements and bug fixes in the code and documentation. 
+
+      <li> Minor improvements and bug fixes in the code and documentation.
 </ul>
 
 <b> Changes from Version 1.5.0 to 1.6.0</b>
 
-<ul>  
-      <li> Added functions for arrays of arbitrary dimensions: 
+<ul>
+      <li> Added functions for arrays of arbitrary dimensions:
       <ul>
           <li> \ref MultiArrayDistanceTransform "Euclidean distance transform"
           <li> \ref MultiArrayMorphology "separable morphology"
           <li> \ref resizeMultiArraySplineInterpolation()
-      </ul>    
-      
-      <li> Added functionality for 3D image analysis: \ref labelVolume(), \ref seededRegionGrowing3D(), 
+      </ul>
+
+      <li> Added functionality for 3D image analysis: \ref labelVolume(), \ref seededRegionGrowing3D(),
            \ref watersheds3D(), \ref VoxelNeighborhood
-          
+
       <li> Added \ref RandomNumberGeneration
-          
-      <li> Added \ref affineWarpImage() and  and factory functions for 
+
+      <li> Added \ref affineWarpImage() and  and factory functions for
            affine transformation matrices
-          
-      <li> Added linear algebra functionality: \ref choleskyDecomposition(), \ref singularValueDecomposition(), 
-           \ref determinant(), \ref logDeterminant(), 
+
+      <li> Added linear algebra functionality: \ref choleskyDecomposition(), \ref singularValueDecomposition(),
+           \ref determinant(), \ref logDeterminant(),
            \ref leastSquares(), \ref weightedLeastSquares(), \ref ridgeRegression()
-          
-      <li> Extended \ref linearSolve(), \ref qrDecomposition(), and \ref inverse() to handle 
+
+      <li> Extended \ref linearSolve(), \ref qrDecomposition(), and \ref inverse() to handle
            rectangular matrices (complete reimplementation of these functions).
-          
-      <li> Added matrix functionality: \ref joinVertically(), \ref joinHorizontally(), 
+
+      <li> Added matrix functionality: \ref joinVertically(), \ref joinHorizontally(),
            \ref columnStatistics(), \ref rowStatistics(), \ref prepareColumns(), \ref prepareRows()
-          
+
       <li> Added/fixed \ref vigra::MultiArray and \ref vigra::linalg::Matrix computed assignments
-      
-      <li> Extended MultiArrayView::norm() to compute L1, L2 and Linfinity, added MultiArrayView::swapData(), 
+
+      <li> Extended MultiArrayView::norm() to compute L1, L2 and Linfinity, added MultiArrayView::swapData(),
            MultiArrayView::permuteDimensions(), MultiArrayView::transpose(), and other minor improvements
            to MultiArrayView
-          
+
       <li> Added typedef \ref vigra::MultiArrayIndex to fix signed/unsigned mismatch problems
-          
+
       <li> Added \ref vigra::ImagePyramid
-          
+
       <li> Minor improvements in \ref VigraImpex
-          
+
       <li> Added sRGB to \ref ColorConversions
-          
+
       <li> Added weighted operator()s to FindAverage[AndVariance] functors.
-          
+
       <li> Added \ref log2i() (integer base-2 logarithm), \ref floorPower2(), and \ref ceilPower2()
-          
+
       <li> Added \ref argMin(), \ref argMax(), \ref argMinIf(), \ref argMaxIf()
-          
+
       <li> Changed default border treatment of Gaussian filters and derivatives to BORDER_TREATMENT_REFLECT
-          
+
       <li> Promoted documentation to Doxygen 1.5.6
-          
-      <li> Minor improvements and bug fixes in the code and documentation. 
+
+      <li> Minor improvements and bug fixes in the code and documentation.
 </ul>
 
 <b> Changes from Version 1.4.0 to 1.5.0</b>
 
-<ul>      
+<ul>
       <li> Added \ref NoiseNormalization
-      
+
       <li> Added \ref SlantedEdgeMTF
-      
+
       <li> Added \ref gaussianGradientMagnitude()
-      
+
       <li> Added \ref fourierTransform() and \ref fourierTransformInverse()
-      
+
       <li> Added \ref cannyEdgelList3x3()
-      
+
       <li> Added srcImage(), srcImageRange() etc. with ROI (see \ref ArgumentObjectFactories)
-      
+
       <li> Improved the \ref VigraImpex (thanks to Pablo d'Angelo, Douglas Wilkins and others):
       <ul>
          <li> Added UINT16 and UINT32 pixel types.
@@ -329,58 +366,58 @@ Many thanks to all!
          <li> Added support for deflate compression (PNG + TIFF).
          <li> Added support for .hdr file format (high dynamic range).
       </ul>
-      
-      <li> Improved support of 64-bit compilers. 
-      
+
+      <li> Improved support of 64-bit compilers.
+
       <li> Added mathematical functions:  elliptic integrals (\ref ellipticIntegralF(), \ref ellipticIntegralE()),
              chi-squared distribution (\ref chi2(), \ref chi2CDF(), \ref noncentralChi2(), \ref noncentralChi2CDF())
-      
+
       <li> Dropped "vigra/" from \#includes in headers (so compiler will first look in the same directory).
-      
+
       <li> Switched to relative paths in the MSVC project files. Compile vigraimpex into a DLL.
-      
-      <li> Bug fixes in the code and documentation. 
+
+      <li> Bug fixes in the code and documentation.
 </ul>
 
 <b> Changes from Version 1.3.3 to 1.4.0</b>
 
-<ul>      
+<ul>
       <li> Switched to the MIT X11 License.
-      
-      <li> Introduced \ref FixedSizeInt (UInt8, Int16 etc.) and made VIGRA compile on 
-           64-bit compilers. Thanks to Hans Ekkehard Plesser 
+
+      <li> Introduced \ref FixedSizeInt (UInt8, Int16 etc.) and made VIGRA compile on
+           64-bit compilers. Thanks to Hans Ekkehard Plesser
            <a href="mailto:hans.ekkehard.plesser at umb.no">hans.ekkehard.plesser at umb.no</a>)
-           for bug reports and other help. Added corresponding typedefs UInt8Image, 
+           for bug reports and other help. Added corresponding typedefs UInt8Image,
            Int16RGBImage etc.
-      
-      <li> Added NumericTraits::isSigned. Thanks to Pablo D'Angelo 
+
+      <li> Added NumericTraits::isSigned. Thanks to Pablo D'Angelo
            <a href="mailto:pablo.dangelo at web.de">pablo.dangelo at web.de</a>)
            for a patch.
-      
+
       <li> Added watersheds().
-      
+
       <li> Added \ref cross() (cross product).
-      
+
       <li> Added \ref cannyEdgeImageWithThinning().
-      
-      <li> Added the possibility to choose between 4- and 
+
+      <li> Added the possibility to choose between 4- and
            8-neighborhood in \ref localMinima() and \ref localMaxima().
-      
+
       <li> Added \ref vigra::FixedPoint.
-      
+
       <li> Added \ref SquareRootTraits and sqrti().
-      
+
       <li> Added \ref vigra::RestrictedNeighborhoodCirculator.
-      
+
       <li> Extended \ref vigra::SplineImageView to support access outside the image
            border according to reflective boundary conditions. Added partial
            specializations for orders 0 and 1 to speed up computations.
-      
+
       <li> Extended \ref vigra::RGBValue to have arbitrarily ordered color channels
-           (e.g. BGR). Thanks to Paul Furgale 
+           (e.g. BGR). Thanks to Paul Furgale
            (<a href="mailto:umfurga1 at cc.umanitoba.ca">umfurga1 at cc.umanitoba.ca</a>) for the
            suggestion and a first implementation.
-      
+
       <li> Bug fixes in the code and documentation. Thanks to Holger Friedrich
            (<a href="mailto:holger.friedrich at vsi.cs.uni-frankfurt.de">holger.friedrich at vsi.cs.uni-frankfurt.de</a>)
            for patches.
@@ -388,43 +425,43 @@ Many thanks to all!
 
 <b> Changes from Version 1.3.2 to 1.3.3</b>
 
-<ul>      
+<ul>
       <li> Added \ref NormTraits, norm(), squaredNorm().
-      
+
       <li> Added \ref gradientEnergyTensor()
-      
-      <li> Added the test suite to the distribution 
+
+      <li> Added the test suite to the distribution
           (see <a href="Installation.html">installation</a> section)
-      
+
       <li> Bug fixes in the code and documentation.
 </ul>
 
 <b> Changes from Version 1.3.1 to 1.3.2</b>
 
-<ul>      
+<ul>
       <li> Added \ref vigra::linalg::Matrix "Matrix class".
-      
+
       <li> Added \ref LinearAlgebraFunctions "Matrix algebra,
            solution of linear systems, eigenvalue computation".
-      
+
       <li> Bug fixes in the code and documentation.
 </ul>
 
 <b> Changes from Version 1.3.0 to 1.3.1</b>
 
-<ul>      
+<ul>
       <li> Fixed syntax for dependent types in templates to make VIGRA
            compile with g++ 3.4 (which is very strict in enforcing
            dependent type rules).
-      
+
       <li> Added \ref vigra::FunctorTraits.
-      
+
       <li> Added \ref vigra::ReduceFunctor.
-      
-      <li> Added reduce and expand modes to the 
+
+      <li> Added reduce and expand modes to the
            \link MultiPointoperators multi-dimensional point operators\endlink.
-      
-      <li> Bug fixes in the code and documentation.       
+
+      <li> Bug fixes in the code and documentation.
 </ul>
 
 <b> Changes from Version 1.2.0 to 1.3.0</b>
@@ -433,123 +470,123 @@ Many thanks to all!
       <li> Added algorithms for \ref MultiDimensionalArrays :
            \ref MultiPointoperators and \ref MultiArrayConvolutionFilters
            and the \link vigra::MultiArrayNavigator navigator utility\endlink.
-      
+
       <li> Extended \ref convolveImage() (non-separable convolution)
            to support all \link BorderTreatmentMode border treatment modes\endlink.
-           
+
       <li> Added \ref vigra::Rational
-           
+
       <li> Added \ref vigra::Polynomial and \ref polynomialRoots().
-           
+
       <li> Added more \link MathFunctions mathematical functions and functors\endlink.
-           
+
       <li> Added \ref vigra::SplineImageView.
-      
+
       <li> Added \link TensorImaging tensor image processing and analysis\endlink
-      
+
       <li> Added 2nd order \ref recursiveFilterX() and \ref recursiveFilterY()
-      
-      <li> Added \ref ResamplingConvolutionFilters and reimplemented 
+
+      <li> Added \ref ResamplingConvolutionFilters and reimplemented
            \ref resizeImageSplineInterpolation() in terms of them.
-      
+
       <li> Added \link MultiArrayToImage multiarray to image wrappers\endlink.
-      
+
       <li> Added \link GeometricTransformations image mirroring and rotation\endlink.
-      
+
       <li> Added \link FourierTransform fftw3.hxx to support FFTW version 3\endlink
            (unfortunately, this is incompatible to FFTW 2, which is still supported in
            <tt>fftw.hxx</tt> but should no longer be used within VIGRA).
-           
+
       <li> Added \ref vigra::ArrayVector as a <tt>std::vector</tt> alternative
            whose memory is guaranteed to be one contiguous piece and whose
            iterator is guaranteed to be a <tt>value_type *</tt>.
-      
+
       <li> Added an <tt>allocator</tt> template parameters to all classes
            that allocate dynamic memory.
-      
-      <li> Bug fixes in the code and documentation.       
+
+      <li> Bug fixes in the code and documentation.
 </ul>
 
 <b> Changes from Version 1.1.6 to 1.2.0</b>
 
 <ul>
-      <li> Complete redesign of the image import/export library. 
-      
-      <li> Added support for Microsoft Visual C++ 7.1 (.net 2003). 
+      <li> Complete redesign of the image import/export library.
+
+      <li> Added support for Microsoft Visual C++ 7.1 (.net 2003).
            This is the first Microsoft compiler that compiles VIGRA without
            special configurations and work-arounds. Work-arounds for older
            MS compilers will probably no longer be maintained.
-           
+
       <li> Added support for PNG image format.
-           
+
       <li> Added cygwin support to the build system.
-           
-      <li> Added \link PixelNeighborhood pixel neighborhood utilities \endlink 
+
+      <li> Added \link PixelNeighborhood pixel neighborhood utilities \endlink
            and \ref vigra::NeighborhoodCirculator.
-      
+
       <li> Added \ref vigra::CrackContourCirculator
-      
+
       <li> Added \ref recursiveFilterX() and \ref recursiveFilterY() that
            support negative filter coefficients and all
            \link BorderTreatmentMode BorderTreatmenModes \endlink
-      
+
       <li> Changed \ref gaussianSmoothing() to use BORDER_TREATMENT_REFLECT
-      
+
       <li> Added \ref simpleSharpening() and \ref gaussianSharpening()
-      
+
       <li> Added \ref vigra::Size2D, \ref vigra::Point2D, \ref vigra::Rect2D
-      
+
       <li> Added \ref vigra::BasicImageView
-      
-      <li> Split "utilities.hxx" into "diff2d.hxx", 
-          "interpolating_accessor.hxx", "iteratortags.hxx", "mathutil.hxx", 
-          "metaprogramming.hxx", "tuple.hxx". "utilities.hxx" now includes 
+
+      <li> Split "utilities.hxx" into "diff2d.hxx",
+          "interpolating_accessor.hxx", "iteratortags.hxx", "mathutil.hxx",
+          "metaprogramming.hxx", "tuple.hxx". "utilities.hxx" now includes
           these other files.
-      
+
       <li> Added \ref MultiDimensionalArrays and \ref VolumeImpex
-      
-      <li> Redesigned \ref vigra::TinyVector, added \ref vigra::TinyVectorView       
+
+      <li> Redesigned \ref vigra::TinyVector, added \ref vigra::TinyVectorView
 </ul>
 
 <b> Changes from Version 1.1.5 to 1.1.6</b>
 
 <ul>
       <li> Restored VIGRA compatibility with Microsoft Visual C++ 6.0
-           (in addition to C++.net)       
+           (in addition to C++.net)
 </ul>
 
 <b> Changes from Version 1.1.4 to 1.1.5</b>
 
 <ul>
       <li> Added \ref vigra::ImageArray.
-           
+
       <li> Added more corner detectors (see \ref CornerDetection).
-           
+
       <li> Added local symmetry detector (see \ref SymmetryDetection).
-           
+
       <li> Added Gabor filter code (see \ref GaborFilter).
-           
+
       <li> Extended \link FunctorExpressions functor expression library \endlink.
-           
+
       <li> Added \ref initImageWithFunctor().
-           
+
       <li> Improved Gaussian derivative filters (higher accuracy, correct sign,
            see \ref vigra#Kernel1D#initGaussianDerivative()).
-           
+
       <li> Ported VIGRA to Microsoft VisualC++.net (however, this compiler
            still doesn't support all VIGRA features, because it still
            doesn't implement partial template specialization and
            partial function ordering).
-           
+
       <li> Finished the new build system.
-           
-      <li> Improved the documentation.       
+
+      <li> Improved the documentation.
 </ul>
 
 <b> Changes from Version 1.1.3 to 1.1.4</b>
 
 <ul>
-      <li> Added \ref FourierTransform "Fourier transform" support, 
+      <li> Added \ref FourierTransform "Fourier transform" support,
            and \ref vigra::FFTWComplex "FFTWComplex" complex number type.
 
       <li> Added convolution convenience functions (see \ref CommonConvolutionFilters).
@@ -561,16 +598,16 @@ Many thanks to all!
            row and column iterators for images.
 
       <li> Added rowIterator() and columnIterator() functions
-           returning optimized iterator adapters to all 2D iterators 
-           (e.g. vigra::ImageIterator). Changed algorithms to make use 
+           returning optimized iterator adapters to all 2D iterators
+           (e.g. vigra::ImageIterator). Changed algorithms to make use
            of these new members.
-           
+
       <li> Added rounding and clipping to accessor functions when
            floating point values are converted to intergral numbers.
-           
-      <li> Added STL-compatible typedefs to all functors, iterators and 
+
+      <li> Added STL-compatible typedefs to all functors, iterators and
            vigra::BasicImage.
-           
+
       <li> Removed ConstRowIterator and ConstColumnsIterator. Thanks
            to the new typedefs, RowIterator and ColumnIterator are
            automatically const when the underlying iterator was const. Thus,
@@ -578,38 +615,38 @@ Many thanks to all!
 
       <li> Major performance tuning. Many algorithms now actually perform
            as fast as their inflexible C counterparts. Thanks to
-           <a href="mailto:viola at merl.com">Paul Viola</a> for doing benchmarks.       
+           <a href="mailto:viola at merl.com">Paul Viola</a> for doing benchmarks.
 </ul>
 
 <b> Changes from Version 1.1.2 to 1.1.3</b>
 
 <ul>
-      <li> Switched from obsolete 
+      <li> Switched from obsolete
            <a href="http://www.zib.de/Visual/software/doc++/index.html">doc++</a>
            documentation generator to
-           <a href="http://www.doxygen.org">doxygen</a>. 
-      
+           <a href="http://www.doxygen.org">doxygen</a>.
+
       <li> Improved documentation.
-      
+
       <li> Minor changes to the code to quiet compiler warnings if compiling with
            "<TT>g++ -Wall -pedantic</TT>".
-           
+
       <li> Dropped support for rint() as this was not portable enough.
-      
+
       <li> In error.hxx: replaced snprintf() with sprintf() for portability.
-      
+
       <li> Renamed CellGridImage into CrackEdgeImage in \ref EdgeDetection.
-      
+
       <li> Added \ref vigra::TinyVector and made vigra::RGBValue derive from it.
-      
+
       <li> Added typedefs for TinyVector images.
-     
+
       <li> Added \ref ColorConversions.
-     
+
       <li> Added \ref vigra::VectorComponentAccessor.
-     
+
       <li> Extended \ref vigra::FindMinMax to work with RGB images.
-      
+
       <li> Minor improvements and bug fixes.
 </ul>
 
@@ -617,27 +654,27 @@ Many thanks to all!
 
 <ul>
       <li> Made VIGRA compile under MS Visual C++ 6.0.
-      
+
       <li> Added \ref vigra::BrightnessContrastFunctor.
-      
-      <li> Added \ref gradientBasedTransform() and related 
+
+      <li> Added \ref gradientBasedTransform() and related
             \ref vigra::MagnitudeFunctor and \ref vigra::RGBGradientMagnitudeFunctor.
-      
+
       <li> Added \ref nonlinearDiffusion().
-      
+
       <li> Added more smoothing methods to <a href="ExampleList.html">smooth</a> example.
-      
+
       <li> Added <a href="ExampleList.html">resize</a> example.
-      
-      <li> Minor corrections and bug fixes.  
+
+      <li> Minor corrections and bug fixes.
 </ul>
 
 <b> Changes from Version 1.1.0 to 1.1.1</b>
 
 <ul>
       <li> Fixed bug with PNM import code.
-      
-      <li> added Canny edge detection algorithm (code adapted from 
+
+      <li> added Canny edge detection algorithm (code adapted from
       C implementation by <a href="mailto:utcke at informatik.uni-hamburg.de">Sven Utcke</a>)
 </ul>
 
@@ -645,33 +682,33 @@ Many thanks to all!
 
 <ul>
       <li> Put everything in namespace "vigra".
-      
+
       <li> Renamed <br>
             VigraStdException => StdException.<br>
             vigraImpexListFormats() => impexListFormats()
-      
-      
+
+
       <li> Added expression templates for \ref FunctorExpressions "automated functor creation".
 
       <li> Added support for input/output of the PNM image file format
-       (contributed by  
+       (contributed by
         <a href="mailto:mamchisl at ucdavis.edu">Mikhail Amchislavsky</a>).
 
       <li> Improved support for the \ref TIFFImpex "TIFF image format".
-            VIGRA can now read and create TIFF with various pixel types 
+            VIGRA can now read and create TIFF with various pixel types
             (unsigned byte, short and long int, float, double).
-            
-      <li> Renamed Dist2D into \ref vigra::Diff2D, since it represents a difference vector 
-            rather than a distance. Extended Diff2D so that it can also act as a 
-            \ref vigra::CoordinateIterator. Note that this 
-            required renaming <TT>Dist2D::width</TT> and <TT>Dist2D::height</TT> into <TT>Diff2D::x</TT> 
+
+      <li> Renamed Dist2D into \ref vigra::Diff2D, since it represents a difference vector
+            rather than a distance. Extended Diff2D so that it can also act as a
+            \ref vigra::CoordinateIterator. Note that this
+            required renaming <TT>Dist2D::width</TT> and <TT>Dist2D::height</TT> into <TT>Diff2D::x</TT>
             and <TT>Diff2D::y</TT> respectively.
-            
+
       <li> Changed the documentation layout.
-      
-      <li> Improved \ref labelImage() according to ideas of Prof. 
+
+      <li> Improved \ref labelImage() according to ideas of Prof.
             Vladimir Kovalevsky.
-      
+
       <li> Several minor changes and bug fixes.
 </ul>
 
diff --git a/docsrc/examples.dxx b/docsrc/examples.dxx
index 8b25671..395d67a 100644
--- a/docsrc/examples.dxx
+++ b/docsrc/examples.dxx
@@ -13,147 +13,157 @@
     
     <li> Convert an image file into another file type:
     <a href="convert_8cxx-example.html">convert.cxx</a> <br>
-    Usage: <TT>convert infile outfile</TT>
+    Usage: <TT>example_convert infile outfile</TT>
     
     <li> Read an image file and write out a subimage:
     <a href="subimage_8cxx-example.html">subimage.cxx</a> <br>
-    Usage: <TT>subimage infile outfile</TT>
+    Usage: <TT>example_subimage infile outfile</TT>
     
     <li> Invert an image file (create a negative) using the function 
     \ref transformImage():
     <a href="invert_8cxx-example.html">invert.cxx</a> <br>
-    Usage: <TT>invert infile outfile</TT>
+    Usage: <TT>example_invert infile outfile</TT>
     
     <li> Invert an image file (create a negative) by coding the loop
     explicitly:
     <a href="invert_explicitly_8cxx-example.html">invert_explicitly.cxx</a> <br>
-    Usage: <TT>invert_explicitly infile outfile</TT>
+    Usage: <TT>example_invert_explicitly infile outfile</TT>
     
     <li> Resize an image using \ref resizeImageSplineInterpolation():
     <a href="resize_8cxx-example.html">resize.cxx</a> <br>
-    Usage: <TT>resize infile outfile</TT>
+    Usage: <TT>example_resize infile outfile</TT>
     
     <li> Smooth an image using \ref RecursiveConvolution functions:
     <a href="smooth_8cxx-example.html">smooth.cxx</a> <br>
-    Usage: <TT>smooth infile outfile</TT>
+    Usage: <TT>example_smooth infile outfile</TT>
     
     <li> Find the gray value profile along the image diagonal 
     by means of a \ref vigra::LineIterator :
     <a href="profile_8cxx-example.html">profile.cxx</a> <br>
-    Usage: <TT>profile infile</TT>, generates <TT>profile.gif</TT>
+    Usage: <TT>example_profile infile</TT>, generates <TT>profile.gif</TT>
 
     <li> Create series of slices through different color spaces.:
     <a href="palette_8cxx-example.html">palette.cxx</a> <br>
-    Usage: <TT>palette lab</TT>, generates <TT>lab_*.gif</TT> (44 images)
+    Usage: <TT>example_palette lab</TT>, generates <TT>lab_*.gif</TT> (44 images)
 
     <li> Reduce image size by mean of a Gaussian pyramid:
     <a href="pyramid_8cxx-example.html">pyramid.cxx</a> <br>
-    Usage: <TT>pyramid infile outfile</TT>
+    Usage: <TT>example_pyramid infile outfile</TT>
     
     <li> Find edges by means of a 
     \ref differenceOfExponentialEdgeImage():
     <a href="edge_8cxx-example.html">edge.cxx</a> <br>
-    Usage: <TT>edge infile outfile</TT>
+    Usage: <TT>example_edge infile outfile</TT>
     <li> Segment image by means of the watershed algorithm, using 
     \ref seededRegionGrowing():
     <a href="watershed_8cxx-example.html">watershed.cxx</a> <br>
-    Usage: <TT>watershed infile outfile</TT>
+    Usage: <TT>example_watershed infile outfile</TT>
     
     <li> Generate a Voronoi diagram, using \ref distanceTransform() and
     \ref seededRegionGrowing():
     <a href="voronoi_8cxx-example.html">voronoi.cxx</a> <br>
-    Usage: <TT>voronoi</TT>, generates: <TT>distances.gif</TT> (Euclidean distance transform) and <TT>voronoi.gif</TT>
+    Usage: <TT>example_voronoi</TT>, generates: <TT>distances.gif</TT> (Euclidean distance transform) and <TT>voronoi.gif</TT>
     (Voronoi diagram)
         
     <li> Measure boundary and corner strengths with the 
     \ref boundaryTensor():
-    <a href="boundarytensor_8cxx-example.html">boundarytensor.cxx</a> <br>
+    <a href="example_boundarytensor_8cxx-example.html">boundarytensor.cxx</a> <br>
     Usage: <TT>boundarytensor infile</TT>, creates <tt>boundarystrength.tif</tt> and <tt>cornerstrength.tif</tt>
     
     <li> Total Variation (TV) Regularization
     <a href="total_variation_8cxx-example.html">total_variation.cxx</a> <br>
-    Usage: <TT>total_variation parameterfile</TT>
+    Usage: <TT>example_total_variation parameterfile</TT>
     (cf. example parameter files *.par for standard TV regularization, anisotropic and second order TV)
     
+    <li> Non-negative least-squares regression
+    <a href="nnlsq_8cxx-example.html">nnlsq.cxx</a> <br>
+    Usage: <TT>example_nnlsq</TT> (no parameters - example data are defined in nnlsq.cxx)
+    
     </ul>
 */
 
 /** \example convert.cxx
     Convert an image file into another file type
     <br>
-    Usage: <TT>convert infile outfile</TT>
+    Usage: <TT>example_convert infile outfile</TT>
 */
 
 /** \example subimage.cxx
     Read an image file and write out a subimage
     <br>
-    Usage: <TT>subimage infile outfile</TT>
+    Usage: <TT>example_subimage infile outfile</TT>
 */
     
 /** \example invert.cxx
     Invert an image file (create a negative) using the function 
     \ref transformImage()
     <br>
-    Usage: <TT>invert infile outfile</TT>
+    Usage: <TT>example_invert infile outfile</TT>
 */
     
 /** \example invert_explicitly.cxx
     Invert an image file (create a negative) by coding the loop
     explicitly
     <br>
-    Usage: <TT>invert_explicitly infile outfile</TT>
+    Usage: <TT>example_invert_explicitly infile outfile</TT>
 */
     
 /** \example resize.cxx
     Resize an image using \ref resizeImageSplineInterpolation()<br>
-    Usage: <TT>resize infile outfile</TT>
+    Usage: <TT>example_resize infile outfile</TT>
 */
     
 /** \example smooth.cxx
     Smooth an image using \ref RecursiveConvolution functions:
     <a href="smooth.cxx-example.html">smooth.cxx</a> <br>
-    Usage: <TT>smooth infile outfile</TT>
+    Usage: <TT>example_smooth infile outfile</TT>
 */
     
 /** \example profile.cxx
     Find the gray value profile along the image diagonal 
-    by means of a \ref vigra::LineIterator<br>
-    Usage: <TT>profile infile</TT>, generates <TT>profile.gif</TT>
+    by means of a \ref vigra::LineIterator <br>
+    Usage: <TT>example_profile infile</TT>, generates <TT>profile.gif</TT>
 */
 
 /** \example palette.cxx
     Create series of slices through different color spaces.
-    Usage: <TT>palette luv</TT>, generates <TT>luv_*.gif</TT> (44 images)
+    Usage: <TT>example_palette luv</TT>, generates <TT>luv_*.gif</TT> (44 images)
 */
 
 /** \example pyramid.cxx
     Reduce image size by mean of a Gaussian pyramid<br>
-    Usage: <TT>pyramid infile outfile</TT>
+    Usage: <TT>example_pyramid infile outfile</TT>
 */
     
 /** \example edge.cxx
     Find edges by means of a 
     \ref differenceOfExponentialEdgeImage()<br>
-    Usage: <TT>edge infile outfile</TT>
+    Usage: <TT>example_edge infile outfile</TT>
 */
     
 /** \example watershed.cxx
     Segment image by means of the watershed algorithm, using 
     \ref seededRegionGrowing()<br>
-    Usage: <TT>watershed infile outfile</TT>
+    Usage: <TT>example_watershed infile outfile</TT>
 */
     
 /** \example voronoi.cxx
     Generate a Voronoi diagram, using \ref distanceTransform() and
     \ref seededRegionGrowing()<br>
-    Usage: <TT>voronoi</TT>, generates: <TT>distances.gif</TT> (Euclidean distance transform) and <TT>voronoi.gif</TT> (Voronoi diagram)
+    Usage: <TT>example_voronoi</TT>, generates: <TT>distances.gif</TT> (Euclidean distance transform) and <TT>voronoi.gif</TT> (Voronoi diagram)
 */
 
 /** \example boundarytensor.cxx        
     Measure boundary and corner strengths with the 
     \ref boundaryTensor():
     <a href="boundarytensor.cxx-example.html">boundarytensor.cxx</a> <br>
-    Usage: <TT>boundarytensor infile</TT>, creates <tt>boundarystrength.tif</tt> and <tt>cornerstrength.tif</tt>
+    Usage: <TT>example_boundarytensor infile</TT>, creates <tt>boundarystrength.tif</tt> and <tt>cornerstrength.tif</tt>
+*/
+
+/** \example nnlsq.cxx
+       Solve a non-negative least-squares problem with the LARS algorithm (see \ref nonnegativeLeastSquares())
+       or the Goldfarb-Idnani algorithm (see \ref quadraticProgramming())<br>
+       Usage: <TT>example_nnlsq</TT> (no parameters - example data are defined in nnlsq.cxx)
 */
 
 /** \example total_variation.cxx
diff --git a/docsrc/image_processing.dxx b/docsrc/image_processing.dxx
index f5d7cd9..57557ad 100644
--- a/docsrc/image_processing.dxx
+++ b/docsrc/image_processing.dxx
@@ -41,7 +41,7 @@
     float det = linalg::determinant(matrix);
     \endcode
     
-    For historical reasons, VIGRA also supports two alternative APIs in terms of iterators. These APIs used to considerably faster, but meanwhile compilers and processors have improved to the point where the much simpler MultiArrayView API no longer imposes a significant abstraction penalty. While there are no plans to remove support for the old APIs, they should not be used in new code.
+    For historical reasons, VIGRA also supports two alternative APIs in terms of iterators. These APIs used to be considerably faster, but meanwhile compilers and processors have improved to the point where the much simpler MultiArrayView API no longer imposes a significant abstraction penalty. While there are no plans to remove support for the old APIs, they should not be used in new code.
     
     <ul>
     <li> Functions on 2-dimensional images may support an \ref ImageIterators API. These iterators are best passed to the functions via the convenience functions <tt>srcImageRange(array)</tt>, <tt>srcImage(array)</tt>, and <tt>destImage(array)</tt>. A detailed description of the convenience functions can be found in section \ref ArgumentObjectFactories. Example:
diff --git a/docsrc/index.dxx b/docsrc/index.dxx
index 109aea1..c3b1b6b 100644
--- a/docsrc/index.dxx
+++ b/docsrc/index.dxx
@@ -20,15 +20,18 @@
     <LI> \ref MultiDimensionalArrays
         <BR>   <em>Arrays, iterators, and supporting types and functions
              for arbitrary dimensions</em>
+    <LI> \ref ChunkedArrayClasses
+        <BR>   <em>Store big data (potentially larger than RAM) as a collection of rectangular blocks</em>
     <LI> \ref GraphDataStructures
-        <BR>   <em>Grid graphs and supporting types and functions
-             for arbitrary dimensions</em>
+        <BR>   <em>Graph-based algorithms (e.g. segmentation) and underlying graph classes (e.g. grid graphs for arbitrary dimensions)</em>
     <LI> \ref ImportExport
         <BR>   <em>Conversion from and to other image data types</em>
     <LI> \ref ColorConversions
         <BR>   <em>Convert between RGB and other color spaces, such as L*u*v*, Y'PbPr</em>
     <LI> \ref ImageProcessing
         <BR>   <em>Point operators, image arithmetic, convolution, morphology</em>
+    <LI> \ref Registration
+         <BR>   <em>Transforming different images into a common coordinate system</em>
     <LI> \ref ImageAnalysis
         <BR>   <em>Segmentation and feature extraction algorithms</em>
     <LI> \ref MachineLearning
@@ -109,7 +112,7 @@
     </DL>
 */
 
-/** \page MathFunctionality Mathematical tools
+/** \page MathFunctionality Mathematical Tools
 
     <b>Number types, mathematical constants, special functions, linear algebra</b>
     <p>
@@ -250,9 +253,9 @@
          <BR>   <em>Fast Fourier transform for arrays of arbitrary dimension</em>
     <LI> \ref resizeMultiArraySplineInterpolation()
          <BR>   <em>Interpolation of arrays in arbitrary dimensions</em>
-    <LI> \ref MultiArrayDistanceTransform 
+    <LI> \ref MultiArrayDistanceTransform
          <BR>   <em>Separable distance transform for arrays of arbitrary dimension</em>
-    <LI> \ref MultiArrayMorphology 
+    <LI> \ref MultiArrayMorphology
          <BR>   <em>Separable morphology with parabola structuring function for arrays of arbitrary dimension</em>
     <LI> \ref labelVolume(), \ref seededRegionGrowing3D(), \ref watersheds3D(), \ref localMinima3D(), \ref localMaxima3D(),
          <BR>   <em>3-dimensional image (i.e. volume) analysis</em>
@@ -272,8 +275,8 @@
          <BR>   <em>VIGRA's highlevel image import/export interface</em>
     <LI> \ref VolumeImpex
          <BR>   <em>Import/export interface for volume data</em>
-    <LI> \ref VigraHDF5Impex 
-         <BR>   <em>Import/export of images and arrays in 
+    <LI> \ref VigraHDF5Impex
+         <BR>   <em>Import/export of images and arrays in
          <a href="http://www.hdfgroup.org/HDF5/">HDF5</a> format</em>
     <LI> \ref TIFFImpex
          <BR>   <em>image import/export interface if you want to call libtiff functions directly</em>
@@ -284,8 +287,8 @@
     <b>If you already have an image data type in your system:</b>
 
     Then I recommend using VIGRA's algorithms directly on top of your data type.
-    To do this, you simply wrap your data in an \ref vigra::ImageIterator and/or 
-    \ref vigra::MultiArrayView (depending on the functions you want to call). If 
+    To do this, you simply wrap your data in an \ref vigra::ImageIterator and/or
+    \ref vigra::MultiArrayView (depending on the functions you want to call). If
     your data have some exotic properties, that prevent this solution from working,
     you can still implement your own versions or subclasses of the interface classe,
     which isn't very difficult.
@@ -317,6 +320,10 @@
          <BR>   <em>1D, 2D, and nD filters, including separable and recursive convolution</em>
     <LI> \ref NonLinearDiffusion
          <BR>   <em>Edge-preserving smoothing and denoising</em>
+    <LI> \ref Correlation
+         <BR>   <em>Fast and slow algorithms to estimate the correlation between images</em>
+    <LI> \ref Registration
+         <BR>   <em>Transforming different images into a common coordinate system</em>
     <LI> \ref FourierTransform
          <BR>   <em>forward and backward FFT, cosine transform, and related
                  functionality</em>
@@ -548,39 +555,39 @@ of \ref AlgebraicField and \ref DivisionAlgebra.
 
 /** \page VigraMatlab Vigra Matlab
 
-    Matlab bindings (mex-files) for the most important VIGRA functions are located 
-    <tt>[vigra_src_dir]/src/matlab</tt>. To compile and install them, start Matlab, 
+    Matlab bindings (mex-files) for the most important VIGRA functions are located
+    <tt>[vigra_src_dir]/src/matlab</tt>. To compile and install them, start Matlab,
     go into that directory and call the function buildVigraExtensions:
-    
+
     \code
     buildVigraExtensions('install_path')
     \endcode
-    
-    If the compilation fails because includes or libraries are not found, you can 
+
+    If the compilation fails because includes or libraries are not found, you can
     provide additional search directories like this:
-    
+
     \code
     buildVigraExtensions('install_path', 'all', struct('flags', '-I/path/to/includes -L/path/to/libs'))
     \endcode
-    
+
     Additional compiler flags are specified in the same way. Suggestions about typical settings on Linux and
     Windows can be found in the individual .cpp files. For example, on Windows we usually need
-    
+
     \code
     buildVigraExtensions('install_path', 'all', ...
      struct('flags', '-I[HDF5PATH]/include -L[HDF5PATH]/lib -lhdf5dll -lhdf5_hldll -D_HDF5USEDLL_ -DHDF5CPP_USEDLL'))
     \endcode
-   
+
     After successful compilation, you can obtain a list of the available VIGRA functions by calling
 
     \code
     help vigraIndex
     \endcode
-    
-    In the same way, you get documentation for the individual functions. More 
-    information about the glue code behind the bindings is available in 
+
+    In the same way, you get documentation for the individual functions. More
+    information about the glue code behind the bindings is available in
     <a href="http://hci.iwr.uni-heidelberg.de/vigra/documents/tutorial_reference.pdf">this report</a>.
-    
+
 */
 
 /** \namespace vigra
diff --git a/docsrc/makeFunctionIndex.py b/docsrc/makeFunctionIndex.py
index 81c0cc0..3b1e784 100644
--- a/docsrc/makeFunctionIndex.py
+++ b/docsrc/makeFunctionIndex.py
@@ -7,7 +7,7 @@ import xml.etree.ElementTree as ET
 from itertools import chain
 
 if len(sys.argv) != 2:
-    print 'usage: python makeFunctionIndex.py directory'
+    print('usage: python makeFunctionIndex.py directory')
     sys.exit(1)
 
 path = str(sys.argv[1])
@@ -27,7 +27,7 @@ def getClassList():
             namespace = long_name[:long_name.rfind('::')]
             class_list.append([html, short_name, namespace])
 
-    class_list.sort(lambda a,b: cmp(a[1], b[1]))
+    class_list.sort(key = lambda a: a[1])
     return class_list
 
 
@@ -54,19 +54,19 @@ def getFunctionList():
 
     unique = set()
     set_add = unique.add
-    function_list = [ x for x in function_list if x not in unique and not set_add(x)]    
-    function_list.sort(lambda a,b: cmp(a[1], b[1]))
+    function_list = [ x for x in function_list if x not in unique and not set_add(x)]
+    function_list.sort(key = lambda a: a[1])
     function_list = disambiguateOverloadedFunctions(function_list)
     return function_list
 
-def addHeading(index, initial):    
+def addHeading(index, initial):
     index = index + '<p><a name="index_' + initial + \
     '"><table class="function_index"><tr><th> ' + initial.upper() + \
     ' </th><td align="right" width="100%">VIGRA_NAVIGATOR_PLACEHOLDER</td></tr></table><p>\n'
     return index
 
 def disambiguateOverloadedFunctions(functionList):
-    for i in xrange(len(functionList)):
+    for i in range(len(functionList)):
         overloaded = False
         functionName = functionList[i][1]
         if i > 0:
@@ -84,7 +84,7 @@ def disambiguateOverloadedFunctions(functionList):
         else:
             group = ""
         functionList[i] = functionList[i] + (group,)
-    
+
     return functionList
 
 
@@ -103,7 +103,7 @@ def generateFunctionIndex(functionList):
         else:
             initials.append(initial)
             index = addHeading(index, initial)
-            
+
         index = index + '<a href="'+ link + '">' + functionName + '</a>()'
         overloadDisambiguation = functionList[i][2]
         if overloadDisambiguation != "":
@@ -139,28 +139,36 @@ classList = getClassList()
 functionList = getFunctionList()
 generateFunctionIndex(functionList)
 
-# Export class and function list to c_api_replaces.txt for 
+# Export class and function list to c_api_replaces.txt for
 # crosslinking of vigranumpy documentation.
-# Note that '::' are not allowed in reStructuedText link names, 
+# Note that '::' are not allowed in reStructuedText link names,
 # so we have to use '.' instead.
-replaces=open("../vigranumpy/docsrc/c_api_replaces.txt","w")
-for i in range(len(functionList)):
-    functionName = functionList[i][1]
-    overloadDisambiguation = functionList[i][2]
-    if i > 0 and functionName == functionList[i-1][1] and \
-                   overloadDisambiguation == functionList[i-1][2]:
-        continue
-    if overloadDisambiguation != "":
-        functionName = overloadDisambiguation +'.' + functionName
-    link = functionList[i][0]
-    replaces.write(functionName+":"+link+"\n")
-for i in range(len(classList)):
-    className = classList[i][1]
-    namespace = classList[i][2]
-    if (i > 0 and className == classList[i-1][1]) or \
-       (i < len(classList)-1 and className == classList[i+1][1]):
-        namespace = namespace.replace('::', '.')
-        className = namespace +'.' + className
-    link = classList[i][0]
-    replaces.write(className+":"+link+"\n")
-replaces.close()
+try:
+    replaces=open("../vigranumpy/docsrc/c_api_replaces.txt","w")
+except IOError:
+    print("Cannot open the 'c_api_replaces.txt' file, skipping.")
+else:
+    lowercase_names = set()
+    for i in range(len(functionList)):
+        functionName = functionList[i][1]
+        overloadDisambiguation = functionList[i][2]
+        if i > 0 and functionName == functionList[i-1][1] and \
+                    overloadDisambiguation == functionList[i-1][2]:
+            continue
+        if overloadDisambiguation != "":
+            functionName = overloadDisambiguation +'.' + functionName
+        link = functionList[i][0]
+        replaces.write(functionName+":"+link+"\n")
+        lowercase_names.add(functionName.lower())
+    for i in range(len(classList)):
+        className = classList[i][1]
+        namespace = classList[i][2]
+        if (i > 0 and className == classList[i-1][1]) or \
+        (i < len(classList)-1 and className == classList[i+1][1]):
+            namespace = namespace.replace('::', '.')
+            className = namespace +'.' + className
+        if className.lower() in lowercase_names:
+            className = className + 'Class'
+        link = classList[i][0]
+        replaces.write(className+":"+link+"\n")
+    replaces.close()
diff --git a/docsrc/post.py b/docsrc/post.py
index de3d39f..494beba 100644
--- a/docsrc/post.py
+++ b/docsrc/post.py
@@ -5,7 +5,7 @@ import glob
 import sys
 
 if len(sys.argv) != 3:
-    print 'usage: python post.py directory versionNumber'
+    print('usage: python post.py directory versionNumber')
     sys.exit(1)
 
 path = str(sys.argv[1])
@@ -157,8 +157,11 @@ def insertMissingTemplateDeclarations(text):
     return text
 
 def processFile(fileName):
-    print fileName          # log message
-    f = open(fileName)
+    print(fileName)          # log message
+    if sys.version_info[0] < 3:
+        f = open(fileName)
+    else:
+        f = open(fileName,encoding = "ISO-8859-1")
     text = f.read()
     f.close()
     
@@ -167,9 +170,9 @@ def processFile(fileName):
     if re.search('.*/index.html', fileName) or re.search('.*\\index.html', fileName):
         text = re.sub(r'<h3 (align="center"|class="version")>\d+\.\d+\.\d+ </h3>', '', text)
         text = indexPageHeading.sub(indexPageHeadingReplacement, text)
-        
+
     text = convertHeadings(text)
-    
+
     text = insertMissingTemplateDeclarations(text)
 
     f = open(fileName, 'w+')
diff --git a/docsrc/tutorial.dxx b/docsrc/tutorial.dxx
index 02a73be..fe43cf9 100644
--- a/docsrc/tutorial.dxx
+++ b/docsrc/tutorial.dxx
@@ -23,7 +23,7 @@
     <li> \ref MultiArrayArithmeticTutorial
         <BR>   <em>mathematical operations on MultiArrays</em>
         <ul style="list-style-image:url(documents/bullet.gif)">
-        <li> \ref MultiMathModule "Array Experessions"
+        <li> \ref MultiMathModule "Array Expressions"
         <li> \ref LinearAlgebraModule "Linear Algebra"
         <li> \ref MultiPointoperators "STL-style transformation algorithms"
         <li> \ref FeatureAccumulators
@@ -175,7 +175,7 @@
         image(1,i) = 13;
     \endcode
 
-    On first sight, individual coordinates may be necessary to iterator of the image or parts of it. But the following example shows that the same effect can be achieved with a shape object that is allocated outside the loop:
+    On first sight, individual coordinates may seem to be necessary for iterating over the image or parts of it. But the following example shows that the same effect can be achieved with a shape object that is allocated outside the loop:
     3rd column of a 8x4-matrix (initialized with 5) to 7.
 
     \code
@@ -876,14 +876,16 @@
     }
     \endcode
     
-    These simple tricks already get you a long way in the advanced use of VIGRA. You will notice, that many existing VIGRA functions are not implemented in temrs of \ref vigra::MultiArrayView, but in terms of \ref ImageIterators "image iterators" and \ref MultiIteratorGroup "hierarchical iterators". However, these iterators are quite difficult to use, so the MultiArrayView approach is recommended for new code.
+    These simple tricks already get you a long way in the advanced use of VIGRA. You will notice, that many existing VIGRA functions are not implemented in temrs of \ref vigra::MultiArrayView, but in terms of \ref ImageIterators "image iterators" and \ref MultiIteratorGroup "hierarchical iterators". However, these iterators are more difficult to use, so the MultiArrayView approach is recommended for new code.
 */
 
 /** \page PythonBindingsTutorial VIGRA Python Bindings
     
+    See also the full <a href="../vigranumpy/index.html">vigranumpy reference</a>!
+    
     When you configure VIGRA with the option <tt>-DWITH_VIGRANUMPY=1</tt> while running cmake, a Python module <tt>vigra</tt> will be compiled and installed. It exposes most of VIGRA's functionality for easy scripting and prototyping in Python. Most importantly, VIGRA's Python bindings are fully integrated with the popular 'numpy' package so that you can call vigra functions directly with numpy <tt>ndarrays</tt>. No explicit or implicit conversion of data formats is required.
     
-    The syntax of the Python version is usually very similar to the C++ syntax, with one important difference: You do not have to pass pre-allocated result images to the functions. That is, while in C++ you write
+    The syntax of the Python version is usually very similar to the C++ syntax, with one important difference: You do not have to pass pre-allocated result arrays to the functions. That is, while the call to <tt>gaussianSmoothing()</tt> in C++ is written like this
     
     \code
     MultiArray<2, float> inputImage(Shape2(width, height)), 
@@ -903,31 +905,71 @@
     >>> inputImage = numpy.zeros((width, height), dtype=numpy.float32)
     ...  # fill inputImage
     
-    # smooth image with Gaussian filter with sigma=1.5
-    # (resultImage is automatically allocated and returned) 
     >>> resultImage = vigra.filters.gaussianSmoothing(inputImage, 1.5);
     \endcode
     
-    However, it is still possible to pass a result array of appropriate shape explicitly by means of the <tt>out</tt> parameter:
+    The result image is automatically allocated and returned by the function. Nonetheless, it is still possible to pass a result array of appropriate shape explicitly by means of the <tt>out</tt> parameter:
     
     \code
     >>> resultImage = numpy.zeros(inputImage.shape, dtype=numpy.float32)
     >>> vigra.filters.gaussianSmoothing(inputImage, 1.5, out=resultImage)
     \endcode
     
-    If the C++ function provides options, they are exposed on the Python side as keyword arguments:
+    This is, for example, useful when the same result image should be reused in several calls of the same function to avoid the repeated creation of new result arrays. Another possible use is the application of a function to only a rectangular region-of-interest: When the full result array is already allocated, you can pass a view of the approriate subarray to the <tt>out</tt> parameter in order to fill just the desired ROI.
+    
+    When a C++ function provides options, they are exposed on the Python side as keyword arguments:
     
     \code
     >>> labeling, max_label = vigra.analysis.watersheds(inputImage, seeds=seedImage, method='UnionFind')
     \endcode
     
-    In general, the correspondence between a Python function and its C++ counterpart is straightforward, and the Python documentation frequently refers to the C++ documentation for details. However, there is an important caveat: the default axis interpretation is different in VIGRA's <tt>MultiArray</tt> (which uses 'Fortran order') and in numpy's <tt>ndarray</tt> (which uses 'C-order). To help you deal with this difficulty, vigranumpy provides a subclass <a href="../vigranumpy/index.html [...]
+    In general, the correspondence between a Python function and its C++ counterpart is straightforward, and the Python documentation frequently refers to the C++ documentation for details. However, there is a crucial difference: the default axis interpretation is different in VIGRA's <tt>MultiArray</tt> (which interpretes axes as x, y, z, so called 'Fortran' order) and in numpy's <tt>ndarray</tt> (which interpretes them as z, y, x, so called 'C'-order). To help you deal with this diffic [...]
     
-    The full Python documentation is available via <a href="../vigranumpy/index.html">HTML</a> or can be obtained directly from the Python prompt by the <tt>help()</tt> command:
+    The full <a href="../vigranumpy/index.html">vigranumpy reference</a> is available via HTML or can be obtained directly at the Python prompt by the <tt>help()</tt> command:
     
     \code
     >>> help(vigra.filters.gaussianSmoothing)
     \endcode
     
-    An important
+    Another important difference between C++ and Python is that vigranumpy exposes most functions only for a restricted set of pixel types. This restriction is necessary because support for all possible type combinations would result in a combinatorial explosion and unreasonably large Python modules. In general, all functions are implemented for <tt>float</tt> pixel types (called <tt>numpy.float32</tt> on the Python side), and some provide <tt>uint8</tt> and/or <tt>uint32</tt> versions i [...]
+    
+    \code
+    >>> a = vigra.ScalarImage((20,20), dtype=numpy.float64)
+
+    >>> vigra.gaussianSmoothing(a, 1) # doesn't support numpy.float64
+    ArgumentError: Python argument types in
+        vigra.filters.gaussianSmoothing(numpy.ndarray, int)
+    did not match C++ signature:
+        gaussianSmoothing(class vigra::NumpyArray<3,struct vigra::Multiband<float>,struct vigra::StridedArrayTag> array, class boost::python::api::object sigma, class vigra::NumpyArray<3,struct vigra::Multiband<float>,struct vigra::StridedArrayTag> out=None, class boost::python::api::object sigma_d=0.0, class boost::python::api::object step_size=1.0, double window_size=0.0, class boost::python::api::object roi=None)    
+
+        gaussianSmoothing(class vigra::NumpyArray<4,struct vigra::Multiband<float>,struct vigra::StridedArrayTag> array, class boost::python::api::object sigma, class vigra::NumpyArray<4,struct vigra::Multiband<float>,struct vigra::StridedArrayTag> out=None, class boost::python::api::object sigma_d=0.0, class boost::python::api::object step_size=1.0, double window_size=0.0, class boost::python::api::object roi=None)
+    \endcode
+    
+    The error message is automatically generated by boost::python and therefore rather technical. It says that <tt>%gaussianSmoothing()</tt> supports 3- and 4-dimensional arrays where the rightmost dimension is interpreted as a channel axis, and the pixel type must be <tt>float</tt> (these properties are indicated by the type specifications <tt>NumpyArray<3,struct vigra::Multiband<float></tt> and <tt>NumpyArray<4,struct vigra::Multiband<float></tt> respectively). Thus, the input array mu [...]
+    
+    <a href="../vigranumpy/index.html#more-on-the-motivation-and-use-of-axistags">Axistags</a> allow vigranumpy to distinguish if a given 3-dimensional array is to be interpreted as a 2D image with multiple channels, or as a 3D volume with only a single channel. If no axistags are attached to the array, it is unspecified which version of an algorithm will be called. Axistags are automatically specified when arrays are created with one of the factory functions in the <tt>vigra</tt> module [...]
+    
+    \code
+    >>> a = vigra.ScalarImage((30, 20))
+    >>> print "%s \n %r" % (a.shape, a.axistags)
+    (30L, 20L)
+     x y
+
+    >>> a = vigra.RGBImage((30, 20))
+    >>> print "%s \n %r" % (a.shape, a.axistags)
+    (30L, 20L, 3L)
+     x y c
+
+    >>> a = vigra.ScalarVolume((30, 20, 10))
+    >>> print "%s \n %r" % (a.shape, a.axistags)
+    (30L, 20L, 10L)
+     x y z
+
+    >>> a = vigra.RGBVolume((30, 20, 10))
+    >>> print "%s \n %r" % (a.shape, a.axistags)
+    (30L, 20L, 10L, 3L)
+     x y z c
+    \endcode
+    
+    Axistags are encoded 'x', 'y', 'z' for the three spatial axes, 'c' for a channel axis, and 't' for a time axis. If the channel axis is missing, vigranumpy will assume that the array has only a single channel. That is, arrays with shape (30, 20, 1) and axistags 'x y c' are equivalent to arrays with shape (30, 20) and axistags 'x y'. Functions that change the order of the axes (such as <tt>%array.transpose()</tt>) or reduce the number of axes (e.g. <tt>array[:, 1, :]</tt>) also modify  [...]
 */
diff --git a/include/vigra/accessor.hxx b/include/vigra/accessor.hxx
index 60c15b6..e71589c 100644
--- a/include/vigra/accessor.hxx
+++ b/include/vigra/accessor.hxx
@@ -51,7 +51,7 @@ an iterator points to. When we access the data directly, we
 are bound to what <TT>operator*()</TT> returns, if this method exists at
 all. Encapsulating access in an accessor enables a better
 decoupling of data structures and algorithms.
-<a href="http://hci.iwr.uni-heidelberg.de/vigra/documents/DataAccessors.ps">This paper</a> contains
+<a href="http://ukoethe.github.io/vigra/doc/vigra/documents/DataAccessors.ps">This paper</a> contains
 a detailed description of the concept. Here is a brief list of the basic
 accessor requirements:
 
@@ -146,8 +146,8 @@ class StandardAccessor
 
         /** read the data item at an offset (can be 1D or 2D or higher order difference).
         */
-    template <class ITERATOR, class DIFFERENCE>
-    VALUETYPE const & operator()(ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class ITERATOR, class OFFSET>
+    VALUETYPE const & operator()(ITERATOR const & i, OFFSET const & diff) const
     {
         return i[diff];
     }
@@ -170,8 +170,8 @@ class StandardAccessor
             in <TT>value</TT> is automatically converted to <TT>VALUETYPE</TT>.
             In case of a conversion floating point -> integral this includes rounding and clipping.
         */
-    template <class V, class ITERATOR, class DIFFERENCE>
-    void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class V, class ITERATOR, class OFFSET>
+    void set(V const & value, ITERATOR const & i, OFFSET const & diff) const
     {
         i[diff]= detail::RequiresExplicitCast<VALUETYPE>::cast(value);
     }
@@ -215,8 +215,8 @@ class StandardValueAccessor
             is automatically converted to <TT>VALUETYPE</TT>.
             In case of a conversion floating point -> integral this includes rounding and clipping.
         */
-    template <class ITERATOR, class DIFFERENCE>
-    VALUETYPE operator()(ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class ITERATOR, class OFFSET>
+    VALUETYPE operator()(ITERATOR const & i, OFFSET const & diff) const
     {
         return detail::RequiresExplicitCast<VALUETYPE>::cast(i[diff]);
     }
@@ -238,8 +238,8 @@ class StandardValueAccessor
             in <TT>value</TT> is automatically converted to <TT>VALUETYPE</TT>.
             In case of a conversion floating point -> integral this includes rounding and clipping.
         */
-    template <class V, class ITERATOR, class DIFFERENCE>
-    void set(V value, ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class V, class ITERATOR, class OFFSET>
+    void set(V value, ITERATOR const & i, OFFSET const & diff) const
     {
         i[diff]= detail::RequiresExplicitCast<VALUETYPE>::cast(value);
     }
@@ -279,8 +279,8 @@ class StandardConstAccessor
 
         /** read the data item at an offset (can be 1D or 2D or higher order difference).
         */
-    template <class ITERATOR, class DIFFERENCE>
-    VALUETYPE const & operator()(ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class ITERATOR, class OFFSET>
+    VALUETYPE const & operator()(ITERATOR const & i, OFFSET const & diff) const
     {
         return i[diff];
     }
@@ -322,8 +322,8 @@ class StandardConstValueAccessor
             is automatically converted to <TT>VALUETYPE</TT>.
             In case of a conversion floating point -> integral this includes rounding and clipping.
         */
-    template <class ITERATOR, class DIFFERENCE>
-    VALUETYPE operator()(ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class ITERATOR, class OFFSET>
+    VALUETYPE operator()(ITERATOR const & i, OFFSET const & diff) const
     {
         return detail::RequiresExplicitCast<VALUETYPE>::cast(i[diff]);
     }
@@ -384,8 +384,8 @@ class VectorComponentAccessor
 
         /** read the data item at an offset (can be 1D or 2D or higher order difference).
         */
-    template <class ITERATOR, class DIFFERENCE>
-    value_type const & operator()(ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class ITERATOR, class OFFSET>
+    value_type const & operator()(ITERATOR const & i, OFFSET const & diff) const
     {
         return i[diff][index_];
     }
@@ -405,8 +405,8 @@ class VectorComponentAccessor
             in <TT>value</TT> is automatically converted to <TT>value_type</TT>.
             In case of a conversion floating point -> integral this includes rounding and clipping.
         */
-    template <class V, class ITERATOR, class DIFFERENCE>
-    void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) const 
+    template <class V, class ITERATOR, class OFFSET>
+    void set(V const & value, ITERATOR const & i, OFFSET const & diff) const 
     { 
         i[diff][index_]= detail::RequiresExplicitCast<value_type>::cast(value); 
     }
@@ -474,8 +474,8 @@ class VectorComponentValueAccessor
             is automatically converted to <TT>value_type</TT>.
             In case of a conversion floating point -> integral this includes rounding and clipping.
         */
-    template <class ITERATOR, class DIFFERENCE>
-    value_type operator()(ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class ITERATOR, class OFFSET>
+    value_type operator()(ITERATOR const & i, OFFSET const & diff) const
     { 
         return detail::RequiresExplicitCast<value_type>::cast(i[diff][index_]); 
     }
@@ -495,8 +495,8 @@ class VectorComponentValueAccessor
             in <TT>value</TT> is automatically converted to <TT>value_type</TT>.
             In case of a conversion floating point -> integral this includes rounding and clipping.
         */
-    template <class V, class ITERATOR, class DIFFERENCE>
-    void set(V value, ITERATOR const & i, DIFFERENCE const & diff) const 
+    template <class V, class ITERATOR, class OFFSET>
+    void set(V value, ITERATOR const & i, OFFSET const & diff) const 
     { 
         i[diff][index_]= detail::RequiresExplicitCast<value_type>::cast(value); 
     }
@@ -560,8 +560,8 @@ class VectorElementAccessor
     
         /** read the data item at an offset (can be 1D or 2D or higher order difference).
         */
-    template <class ITERATOR, class DIFFERENCE>
-    value_type const & operator()(ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class ITERATOR, class OFFSET>
+    value_type const & operator()(ITERATOR const & i, OFFSET const & diff) const
     { 
         return a_.getComponent(i, diff, index_); 
     }
@@ -581,8 +581,8 @@ class VectorElementAccessor
             in <TT>value</TT> is automatically converted to <TT>value_type</TT>.
             In case of a conversion floating point -> integral this includes rounding and clipping.
         */
-    template <class V, class ITERATOR, class DIFFERENCE>
-    void set(V const & value, ITERATOR const & i, DIFFERENCE const & diff) const 
+    template <class V, class ITERATOR, class OFFSET>
+    void set(V const & value, ITERATOR const & i, OFFSET const & diff) const 
     { 
        a_.setComponent(detail::RequiresExplicitCast<value_type>::cast(value), i, diff, index_); 
     }
@@ -668,8 +668,8 @@ class SequenceAccessor
         /** get begin iterator for sequence at an offset
             of given iterator position
         */
-    template <class ITERATOR, class DIFFERENCE>
-    iterator begin(ITERATOR const & i, DIFFERENCE const & diff)  const
+    template <class ITERATOR, class OFFSET>
+    iterator begin(ITERATOR const & i, OFFSET const & diff)  const
     {
         return i[diff].begin();
     }
@@ -677,8 +677,8 @@ class SequenceAccessor
         /** get end iterator for sequence at a 2D difference vector
             of given iterator position
         */
-    template <class ITERATOR, class DIFFERENCE>
-    iterator end(ITERATOR const & i, DIFFERENCE const & diff)  const
+    template <class ITERATOR, class OFFSET>
+    iterator end(ITERATOR const & i, OFFSET const & diff)  const
     {
         return i[diff].end();
     }
@@ -690,8 +690,8 @@ class SequenceAccessor
 
         /** get size of sequence at 2D difference vector of given iterator position
         */
-    template <class ITERATOR, class DIFFERENCE>
-    unsigned int size(ITERATOR const & i, DIFFERENCE const & diff) const
+    template <class ITERATOR, class OFFSET>
+    unsigned int size(ITERATOR const & i, OFFSET const & diff) const
     { return i[diff].size(); }
 };
 
@@ -804,8 +804,8 @@ class VectorAccessor
         /** Read the component data at given vector index
             at an offset of given iterator position
         */
-    template <class ITERATOR, class DIFFERENCE>
-    component_type const & getComponent(ITERATOR const & i, DIFFERENCE const & diff, int idx) const
+    template <class ITERATOR, class OFFSET>
+    component_type const & getComponent(ITERATOR const & i, OFFSET const & diff, int idx) const
     {
         return i[diff][idx];
     }
@@ -815,9 +815,9 @@ class VectorAccessor
         in <TT>value</TT> is automatically converted to <TT>component_type</TT>.
             In case of a conversion floating point -> integral this includes rounding and clipping.
     */
-    template <class V, class ITERATOR, class DIFFERENCE>
+    template <class V, class ITERATOR, class OFFSET>
     void
-    setComponent(V const & value, ITERATOR const & i, DIFFERENCE const & diff, int idx) const
+    setComponent(V const & value, ITERATOR const & i, OFFSET const & diff, int idx) const
     {
         i[diff][idx] = detail::RequiresExplicitCast<component_type>::cast(value);
     }
@@ -885,16 +885,16 @@ class MultiImageAccessor2
 
         /** read the current data item
         */
-    template <class DIFFERENCE>
-    value_type operator()(DIFFERENCE const & d) const
+    template <class OFFSET>
+    value_type operator()(OFFSET const & d) const
     {
         return std::make_pair(a1_(i1_, d), a2_(i2_, d));
     }
 
         /** read the data item at an offset
         */
-    template <class DIFFERENCE1, class DIFFERENCE2>
-    value_type operator()(DIFFERENCE1 d1, DIFFERENCE2 const & d2) const
+    template <class OFFSET1, class OFFSET2>
+    value_type operator()(OFFSET1 d1, OFFSET2 const & d2) const
     {
         d1 += d2;
         return std::make_pair(a1_(i1_, d1), a2_(i2_, d1));
diff --git a/include/vigra/accumulator-grammar.hxx b/include/vigra/accumulator-grammar.hxx
index b66e334..e520d9e 100644
--- a/include/vigra/accumulator-grammar.hxx
+++ b/include/vigra/accumulator-grammar.hxx
@@ -72,8 +72,10 @@ template <int BinCount> class UserRangeHistogram;    // set min/max explicitly a
 template <int BinCount> class AutoRangeHistogram;    // get min/max from accumulators
 template <int BinCount> class GlobalRangeHistogram;  // like AutoRangeHistogram, but use global min/max rather than region min/max
 
+class FirstSeen;                               // remember the first value seen
 class Minimum;                                 // minimum
 class Maximum;                                 // maximum
+class Range;                                   // minimum and maximum as a <tt>std::pair</tt>
 template <class Hist> class StandardQuantiles; // compute (min, 10%, 25%, 50%, 75%, 90%, max) quantiles from 
                                                // min/max accumulators and given histogram
 
@@ -95,6 +97,13 @@ template <int INDEX>  class WeightArg;         // specifiy the index of the weig
 template <int INDEX>  class LabelArg;          // specifiy the index of the label member in a CoupledHandle
 template <int INDEX>  class CoordArg;          // specifiy the index of the coord member in a CoupledHandle
 
+class RegionContour;                           // compute the contour of a 2D region
+class RegionPerimeter;                         // compute the perimeter of a 2D region
+class RegionCircularity;                       // compare perimeter of a 2D region with a circle of same area
+class RegionEccentricity;                      // ecentricity of a 2D region from major and minor axis
+
+class ConvexHull;                              // base class for convex hull features
+
 /* 
 Quantiles other than minimum and maximum require more thought:
 --------------------------------------------------------------
@@ -202,6 +211,11 @@ typedef Central<AbsSum>                             SumOfAbsDifferences;
 /** \brief Alias. Mean absolute deviation. */
 typedef DivideByCount<SumOfAbsDifferences>          MeanAbsoluteDeviation;
 
+/** \brief Alias. Rectangle enclosing the region, as a <tt>std::pair</tt> of coordinates. */
+typedef Coord<Range>                                BoundingBox;
+/** \brief Alias. Anchor point (first point of the region seen by scan-order traversal. */
+typedef Coord<FirstSeen>                            RegionAnchor;
+
 /** \brief Alias. Region center. */
 typedef Coord<Mean>                                 RegionCenter;
 /** \brief Alias. Region radii. */
@@ -211,8 +225,12 @@ typedef Coord<Principal<CoordinateSystem> >         RegionAxes;
 
 /** \brief Alias. Center of mass. */
 typedef Weighted<RegionCenter>                      CenterOfMass;
+/** \brief Alias. Region center weighted by the region intensity (center of mass). */
+typedef Weighted<RegionCenter>                      WeightedRegionCenter;
 /** \brief Alias. Moments of inertia. */
 typedef Weighted<Coord<Principal<Variance> > >      MomentsOfInertia;
+/** \brief Alias. Region radius weighted by region intensity (square root of the moments of inertia). */
+typedef Weighted<RegionRadii>                       WeightedRegionRadii;
 /** \brief Alias. Axes of inertia. */
 typedef Weighted<RegionAxes>                        AxesOfInertia;
 
@@ -469,6 +487,14 @@ VIGRA_REDUCE_MODFIER(VIGRA_VOID, Principal<PrincipalProjection>, PrincipalProjec
 VIGRA_REDUCE_MODFIER(VIGRA_VOID, Whitened<PrincipalProjection>, Whiten)
 VIGRA_REDUCE_MODFIER(VIGRA_VOID, Whitened<Whiten>, Whiten)
 
+    // ignore all modifiers of RegionContour and related features
+VIGRA_REDUCE_MODFIER(template <class> class A, A<RegionContour>, RegionContour)
+VIGRA_REDUCE_MODFIER(template <class> class A, A<ConvexHull>, ConvexHull)
+VIGRA_REDUCE_MODFIER(template <class> class A, A<RegionPerimeter>, RegionPerimeter)
+VIGRA_REDUCE_MODFIER(template <class> class A, A<RegionCircularity>, RegionCircularity)
+VIGRA_REDUCE_MODFIER(template <class> class A, A<RegionEccentricity>, RegionEccentricity)
+VIGRA_REDUCE_MODFIER(VIGRA_VOID, Weighted<RegionEccentricity>, Weighted<RegionEccentricity>)
+
     // reduce even absolute powers to plain powers
 template <unsigned N>
 struct ModifierRule<AbsPowerSum<N> >
diff --git a/include/vigra/accumulator.hxx b/include/vigra/accumulator.hxx
index 56cbc04..a09c713 100644
--- a/include/vigra/accumulator.hxx
+++ b/include/vigra/accumulator.hxx
@@ -52,20 +52,23 @@
 #include "multi_math.hxx"
 #include "eigensystem.hxx"
 #include "histogram.hxx"
+#include "polygon.hxx"
+#include "functorexpression.hxx"
+#include "labelimage.hxx"
 #include <algorithm>
 #include <iostream>
 
 namespace vigra {
-  
+
 /** \defgroup FeatureAccumulators Feature Accumulators
 
 The namespace <tt>vigra::acc</tt> provides the function \ref vigra::acc::extractFeatures() along with associated statistics functors and accumulator classes. Together, they provide a framework for efficient compution of a wide variety of statistical features, both globally for an entire image, and locally for each region defined by a label array. Many different statistics can be composed out of a small number of fundamental statistics and suitable modifiers. The user simply selects the d [...]
 
-The function \ref acc::extractFeatures() "extractFeatures()" scans the data in as few passes as the selected statstics permit (usually one or two passes are sufficient). Statistics are computed by accurate incremental algorithms, whose internal state is maintained by accumulator objects. The state is updated by passing data to the accumulator one sample at a time. Accumulators are grouped within an accumulator chain. Dependencies between accumulators in the accumulator chain are automati [...]
+The function \ref acc::extractFeatures() "extractFeatures()" scans the data in as few passes as the selected statstics permit (usually one or two passes are sufficient). Statistics are computed by accurate incremental algorithms, whose internal state is maintained by accumulator objects. The state is updated by passing data to the accumulator one sample at a time. Accumulators are grouped within an accumulator chain. Dependencies between accumulators in the accumulator chain are automati [...]
 
 <b>\#include</b> \<vigra/accumulator.hxx\>
 
-    
+
 <b>Basic statistics:</b>
     - PowerSum<N> (computes @f$ \sum_i x_i^N @f$)
     - AbsPowerSum<N> (computes @f$ \sum_i |x_i|^N @f$)
@@ -77,7 +80,7 @@ The function \ref acc::extractFeatures() "extractFeatures()" scans the data in a
     - StandardQuantiles (0%, 10%, 25%, 50%, 75%, 90%, 100%)
     - ArgMinWeight, ArgMaxWeight (store data or coordinate where weight assumes its minimal or maximal value)
     - CoordinateSystem (identity matrix of appropriate size)
-    
+
     <b>Modifiers:</b> (S is the statistc to be modified)
     - Normalization
       <table border="0">
@@ -85,7 +88,7 @@ The function \ref acc::extractFeatures() "extractFeatures()" scans the data in a
       <tr><td> RootDivideByCount<S>    </td><td>  sqrt( S/Count )     </td></tr>
       <tr><td> DivideUnbiased<S>       </td><td>  S/(Count-1)       </td></tr>
       <tr><td> RootDivideUnbiased<S>      </td><td>  sqrt( S/(Count-1) ) </td></tr>
-      </table>    
+      </table>
     - Data preparation:
       <table border="0">
       <tr><td>  Central<S>   </td><td> substract mean before computing S </td></tr>
@@ -95,9 +98,9 @@ The function \ref acc::extractFeatures() "extractFeatures()" scans the data in a
       <tr><td>  Weighted<S>     </td><td> compute weighted version of S   </td></tr>
       <tr><td>  Global<S>       </td><td> compute S globally rather than per region (per region is default if labels are given)   </td></tr>
       </table>
-      
+
     Aliases for many important features are implemented (mainly as <tt>typedef FullName Alias</tt>). The alias names are equivalent to full names. Below are some examples for supported alias names. A full list of all available statistics and alias names can be found in the namespace reference <tt>vigra::acc</tt>. These examples also show how to compose statistics from the fundamental statistics and modifiers:
-    
+
     <table border="0">
     <tr><th> Alias           </th><th>   Full Name                 </th></tr>
     <tr><td> Count           </td><td>  PowerSum<0>                </td></tr>
@@ -112,10 +115,10 @@ The function \ref acc::extractFeatures() "extractFeatures()" scans the data in a
     <tr><td> RegionCenter    </td><td>  Coord<Mean>                </td></tr>
     <tr><td> CenterOfMass    </td><td>  Weighted<Coord<Mean>>      </td></tr>
     </table>
-    
+
     There are a few <b>rules for composing statistics</b>:
     - modifiers can be specified in any order, but are internally transformed to standard order: Global<Weighted<Coord<normalization<data preparation<basic statistic
-    - only one normalization modifier and one data preparation modifier (Central or Principal or Whitened) is permitted 
+    - only one normalization modifier and one data preparation modifier (Central or Principal or Whitened) is permitted
     - Count ignores all modifiers except Global and Weighted
     - Sum ignores Central and Principal, because sum would be zero
     - ArgMinWeight and ArgMaxWeight are automatically Weighted
@@ -131,19 +134,19 @@ The function \ref acc::extractFeatures() "extractFeatures()" scans the data in a
     typedef double DataType;
     int size = 1000;
     vigra::MultiArray<2, DataType> data(vigra::Shape2(size, size));
-   
-    AccumulatorChain<DataType, 
+
+    AccumulatorChain<DataType,
         Select<Variance, Mean, StdDev, Minimum, Maximum, RootMeanSquares, Skewness, Covariance> >
         a;
-        
+
     std::cout << "passes required: " << a.passesRequired() << std::endl;
-    extractFeatures(data.begin(), data.end(), a); 
-    
+    extractFeatures(data.begin(), data.end(), a);
+
     std::cout << "Mean: " << get<Mean>(a) << std::endl;
     std::cout << "Variance: " << get<Variance>(a) << std::endl;
     \endcode
-    
-    The \ref acc::AccumulatorChain object contains the selected statistics and their dependencies. Statistics have to be wrapped with \ref acc::Select. The statistics are computed with the acc::extractFeatures function and the statistics can be accessed with acc::get . 
+
+    The \ref acc::AccumulatorChain object contains the selected statistics and their dependencies. Statistics have to be wrapped with \ref acc::Select. The statistics are computed with the acc::extractFeatures function and the statistics can be accessed with acc::get .
 
     Rules and notes:
     - order of statistics in Select<> is arbitrary
@@ -154,7 +157,7 @@ The function \ref acc::extractFeatures() "extractFeatures()" scans the data in a
     - each accumulator only sees data in the appropriate pass (its "working pass")
 
     The Accumulators can also be used with vector-valued data (vigra::RGBValue, vigra::TinyVector, vigra::MultiArray or vigra::MultiArrayView):
-    
+
     \code
     typedef vigra::RGBValue<double> DataType;
     AccumulatorChain<DataType, Select<...> > a;
@@ -162,15 +165,15 @@ The function \ref acc::extractFeatures() "extractFeatures()" scans the data in a
     \endcode
 
     To compute <b>weighted statistics</b> (Weighted<>) or <b>statistics over coordinates</b> (Coord<>), the accumulator chain can be used with several coupled arrays, one for the data and another for the weights and/or the labels. "Coupled" means that statistics are computed over the corresponding elements of the involved arrays. This is internally done by means of \ref CoupledScanOrderIterator and \ref vigra::CoupledHandle which provide simultaneous access to several arrays (e.g. weight [...]
-    
-    \code 
+
+    \code
     vigra::MultiArray<3, RGBValue<unsigned char> > data(...);
     vigra::MultiArray<3, double>                   weights(...);
-    
+
     AccumulatorChain<CoupledArrays<3, RGBValue<unsigned char>, double>,
                      Select<...> > a;
     \endcode
-    
+
 This works likewise for label images which are needed for region statistics (see below). The indxx of the array holding data, weights, or labels respectively can be specified inside the Select wrapper. These <b>index specifiers</b> are: (INDEX is of type int)
     - DataArg<INDEX>: data are in array 'INDEX' (default INDEX=1)
     - LabelArg<INDEX>: labels are in array 'INDEX' (default INDEX=2)
@@ -180,34 +183,34 @@ Pixel coordinates are always at index 0. To collect statistics, you simply pass
     \code
     using namespace vigra::acc;
     vigra::MultiArray<3, double> data(...), weights(...);
-    
+
     AccumulatorChain<CoupledArrays<3, double, double>, // two 3D arrays for data and weights
         Select<DataArg<1>, WeightArg<2>,           // in which array to look (coordinates are always arg 0)
-               Mean, Variance,                     //statistics over values  
+               Mean, Variance,                     //statistics over values
                Coord<Mean>, Coord<Variance>,       //statistics over coordinates,
                Weighted<Mean>, Weighted<Variance>, //weighted values,
                Weighted<Coord<Mean> > > >          //weighted coordinates.
         a;
-     
+
     extractFeatures(data, weights, a);
     \endcode
-    
+
     This even works for a single array, which is useful if you want to combine values with coordinates. For example, to find the location of the minimum element in an array, you interpret the data as weights and select the <tt>Coord<ArgMinWeight></tt> statistic (note that the version of <tt>extractFeatures()</tt> below only works in conjunction with <tt>CoupledArrays</tt>, despite the fact that there is only one array involved):
-    \code 
+    \code
     using namespace vigra::acc;
     vigra::MultiArray<3, double> data(...);
-    
+
     AccumulatorChain<CoupledArrays<3, double>,
                      Select<WeightArg<1>,           // we interprete the data as weights
                             Coord<ArgMinWeight> > > // and look for the coordinate with minimal weight
         a;
-        
+
     extractFeatures(data, a);
     std::cout << "minimum is at " << get<Coord<ArgMinWeight> >(a) << std::endl;
     \endcode
-    
+
     To compute <b>region statistics</b>, you use \ref acc::AccumulatorChainArray. Regions are defined by means of a label array whose elements specify the region ID of the corresponding point. Therefore, you will always need at least two arrays here, which are again best specified using the <tt>CoupledArrays</tt> helper:
-    
+
     \code
     using namespace vigra::acc;
     vigra::MultiArray<3, double> data(...);
@@ -228,23 +231,23 @@ Pixel coordinates are always at index 0. To collect statistics, you simply pass
     std::cout << get<Mean>(a, regionlabel) << std::endl; //get Mean of region with label 'regionlabel'
     \endcode
 
-   
+
     In some application it will be known only at run-time which statistics have to be computed. An Accumulator with <b>run-time activation</b> is provided by the \ref acc::DynamicAccumulatorChain class. One specifies a set of statistics at compile-time and from this set one can activate the needed statistics at run-time:
-  
+
     \code
     using namespace vigra::acc;
     vigra::MultiArray<2, double> data(...);
-    DynamicAccumulatorChain<double, 
+    DynamicAccumulatorChain<double,
         Select<Mean, Minimum, Maximum, Variance, StdDev> > a; // at compile-time
     activate<Mean>(a);      //at run-time
     a.activate("Minimum");  //same as activate<Minimum>(a) (alias names are not recognized)
-    
+
     extractFeatures(data.begin(), data.end(), a);
     std::cout << "Mean: " << get<Mean>(a) << std::endl;       //ok
     //std::cout << "Maximum: " << get<Maximum>(a) << std::endl; // run-time error because Maximum not activated
     \endcode
-      
-    Likewise, for run-time activation of region statistics, use \ref acc::DynamicAccumulatorChainArray. 
+
+    Likewise, for run-time activation of region statistics, use \ref acc::DynamicAccumulatorChainArray.
 
     <b>Accumulator merging</b> (e.g. for parallelization or hierarchical segmentation) is possible for many accumulators:
 
@@ -266,66 +269,66 @@ Pixel coordinates are always at index 0. To collect statistics, you simply pass
     vigra::MultiArray<2, double> data(...);
     AccumulatorChain<double, Select<Mean, Variance> > a;
 
-    extractFeatures(data.begin(), data.begin()+data.size()/2, a); // this works because 
+    extractFeatures(data.begin(), data.begin()+data.size()/2, a); // this works because
     extractFeatures(data.begin()+data.size()/2, data.end(), a);   // all statistics only need pass 1
     \endcode
-    
+
     More care is needed to merge coordinate-based statistics. By default, all coordinate statistics are computed in the local coordinate system of the current region of interest. That is, the upper left corner of the ROI has the coordinate (0, 0) by default. This behavior is not desirable when you want to merge coordinate statistics from different ROIs: then, all accumulators should use the same coordinate system, usually the global system of the entire dataset. This can be achieved by t [...]
 
     \code
     using namespace vigra;
     using namespace vigra::acc;
-    
+
     MultiArray<2, double> data(width, height);
     MultiArray<2, int>    labels(width, height);
-    
+
     AccumulatorChainArray<CoupledArrays<2, double, int>,
-                          Select<DataArg<1>, LabelArg<2>, 
+                          Select<DataArg<1>, LabelArg<2>,
                                  RegionCenter> >
     a1, a2;
-    
-    // a1 is responsible for the left half of the image. The local coordinate system of this ROI 
+
+    // a1 is responsible for the left half of the image. The local coordinate system of this ROI
     // happens to be identical to the global coordinate system, so the offset is zero.
     Shape2 origin(0,0);
     a1.setCoordinateOffset(origin);
-    extractFeatures(data.subarray(origin, Shape2(width/2, height)), 
+    extractFeatures(data.subarray(origin, Shape2(width/2, height)),
                     labels.subarray(origin, Shape2(width/2, height)),
                     a1);
-                    
+
     // a2 is responsible for the right half, so the offset of the local coordinate system is (width/2, 0)
     origin = Shape2(width/2, 0);
     a2.setCoordinateOffset(origin);
-    extractFeatures(data.subarray(origin, Shape2(width, height)), 
+    extractFeatures(data.subarray(origin, Shape2(width, height)),
                     labels.subarray(origin, Shape2(width, height)),
                     a2);
-   
+
     // since both accumulators worked in the same global coordinate system, we can safely merge them
     a1.merge(a2);
     \endcode
-    
+
     When you compute region statistics in ROIs, it is sometimes desirable to use a local region labeling in each ROI. In this way, the labels of each ROI cover a consecutive range of numbers starting with 0. This can save a lot of memory, because <tt>AccumulatorChainArray</tt> internally uses dense arrays -- accumulators will be allocated for all labels from 0 to the maxmimum label, even when many of them are unused. This is avoided by a local labeling. However, this means that label 1 ( [...]
-    
+
     \code
     std::vector<int> labelMapping(2);
     labelMapping[0] = 0;   // background keeps label 0
     labelMapping[1] = 2;   // local region 1 becomes global region 2
-    
+
     a1.merge(a2, labelMapping);
     \endcode
 
     \anchor histogram
     Four kinds of <b>histograms</b> are currently implemented:
-    
+
     <table border="0">
       <tr><td> IntegerHistogram      </td><td>   Data values are equal to bin indices   </td></tr>
       <tr><td> UserRangeHistogram    </td><td>  User provides lower and upper bounds for linear range mapping from values to indices.    </td></tr>
       <tr><td> AutoRangeHistogram    </td><td>  Range mapping bounds are defiend by minimum and maximum of the data (2 passes needed!)    </td></tr>
       <tr><td> GlobalRangeHistogram    </td><td>  Likewise, but use global min/max rather than region min/max as AutoRangeHistogram will </td></tr>
-      </table>    
-  
+      </table>
 
-       
-    - The number of bins is specified at compile time (as template parameter int BinCount) or at run-time (if BinCount is zero at compile time). In the first case the return type of the accumulator is TinyVector<double, BinCount> (number of bins cannot be changed). In the second case, the return type is MultiArray<1, double> and the number of bins must be set before seeing data (see example below). 
+
+
+    - The number of bins is specified at compile time (as template parameter int BinCount) or at run-time (if BinCount is zero at compile time). In the first case the return type of the accumulator is TinyVector<double, BinCount> (number of bins cannot be changed). In the second case, the return type is MultiArray<1, double> and the number of bins must be set before seeing data (see example below).
     - If UserRangeHistogram is used, the bounds for the linear range mapping from values to indices must be set before seeing data (see below).
     - Options can be set by passing an instance of HistogramOptions to the accumulator chain (same options for all histograms in the chain) or by directly calling the appropriate member functions of the accumulators.
     - Merging is supported if the range mapping of the histograms is the same.
@@ -338,20 +341,20 @@ Pixel coordinates are always at index 0. To collect statistics, you simply pass
     using namespace vigra::acc;
     typedef double DataType;
     vigra::MultiArray<2, DataType> data(...);
-    
+
     typedef UserRangeHistogram<40> SomeHistogram;   //binCount set at compile time
     typedef UserRangeHistogram<0> SomeHistogram2; // binCount must be set at run-time
     typedef AutoRangeHistogram<0> SomeHistogram3;
     typedef StandardQuantiles<SomeHistogram3> Quantiles3;
-    
+
     AccumulatorChain<DataType, Select<SomeHistogram, SomeHistogram2, SomeHistogram3, Quantiles3> > a;
-    
+
     //set options for all histograms in the accumulator chain:
-    vigra::HistogramOptions histogram_opt;         
-    histogram_opt = histogram_opt.setBinCount(50); 
-    //histogram_opt = histogram_opt.setMinMax(0.1, 0.9); // this would set min/max for all three histograms, but range bounds 
+    vigra::HistogramOptions histogram_opt;
+    histogram_opt = histogram_opt.setBinCount(50);
+    //histogram_opt = histogram_opt.setMinMax(0.1, 0.9); // this would set min/max for all three histograms, but range bounds
                                                          // shall be set automatically by min/max of data for SomeHistogram3
-    a.setHistogramOptions(histogram_opt);  
+    a.setHistogramOptions(histogram_opt);
 
     // set options for a specific histogram in the accumulator chain:
     getAccumulator<SomeHistogram>(a).setMinMax(0.1, 0.9); // number of bins must be set before setting min/max
@@ -366,7 +369,7 @@ Pixel coordinates are always at index 0. To collect statistics, you simply pass
     \endcode
 
 
-    
+
 */
 
 
@@ -388,17 +391,17 @@ template <class T01=void, class T02=void, class T03=void, class T04=void, class
           class T16=void, class T17=void, class T18=void, class T19=void, class T20=void>
 struct Select
 : public MakeTypeList<
-    typename StandardizeTag<T01>::type, typename StandardizeTag<T02>::type, typename StandardizeTag<T03>::type, 
-    typename StandardizeTag<T04>::type, typename StandardizeTag<T05>::type, typename StandardizeTag<T06>::type, 
-    typename StandardizeTag<T07>::type, typename StandardizeTag<T08>::type, typename StandardizeTag<T09>::type, 
-    typename StandardizeTag<T10>::type, typename StandardizeTag<T11>::type, typename StandardizeTag<T12>::type, 
-    typename StandardizeTag<T13>::type, typename StandardizeTag<T14>::type, typename StandardizeTag<T15>::type, 
-    typename StandardizeTag<T16>::type, typename StandardizeTag<T17>::type, typename StandardizeTag<T18>::type, 
+    typename StandardizeTag<T01>::type, typename StandardizeTag<T02>::type, typename StandardizeTag<T03>::type,
+    typename StandardizeTag<T04>::type, typename StandardizeTag<T05>::type, typename StandardizeTag<T06>::type,
+    typename StandardizeTag<T07>::type, typename StandardizeTag<T08>::type, typename StandardizeTag<T09>::type,
+    typename StandardizeTag<T10>::type, typename StandardizeTag<T11>::type, typename StandardizeTag<T12>::type,
+    typename StandardizeTag<T13>::type, typename StandardizeTag<T14>::type, typename StandardizeTag<T15>::type,
+    typename StandardizeTag<T16>::type, typename StandardizeTag<T17>::type, typename StandardizeTag<T18>::type,
     typename StandardizeTag<T19>::type, typename StandardizeTag<T20>::type
     >
 {};
 
-    // enable nesting of Select<> expressions 
+    // enable nesting of Select<> expressions
 template <class T01, class T02, class T03, class T04, class T05,
           class T06, class T07, class T08, class T09, class T10,
           class T11, class T12, class T13, class T14, class T15,
@@ -406,7 +409,7 @@ template <class T01, class T02, class T03, class T04, class T05,
 struct StandardizeTag<Select<T01, T02, T03, T04, T05,
                              T06, T07, T08, T09, T10,
                              T11, T12, T13, T14, T15,
-                             T16, T17, T18, T19, T20>, 
+                             T16, T17, T18, T19, T20>,
                       Select<T01, T02, T03, T04, T05,
                              T06, T07, T08, T09, T10,
                              T11, T12, T13, T14, T15,
@@ -421,14 +424,14 @@ struct StandardizeTag<Select<T01, T02, T03, T04, T05,
 struct AccumulatorBegin
 {
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "AccumulatorBegin (internal)";
        // static const std::string n("AccumulatorBegin (internal)");
        // return n;
     }
-    
+
     template <class T, class BASE>
     struct Impl
     : public BASE
@@ -443,9 +446,12 @@ struct LabelArgTag;
 struct CoordArgTag;
 struct LabelDispatchTag;
 
+template <class T, class TAG, class CHAIN>
+struct HandleArgSelector;  // find the correct handle in a CoupledHandle
+
 struct Error__Global_statistics_are_only_defined_for_AccumulatorChainArray;
 
-/** \brief Specifies index of labels in CoupledHandle. 
+/** \brief Specifies index of labels in CoupledHandle.
 
     LabelArg<INDEX> tells the acc::AccumulatorChainArray which index of the Handle contains the labels. (Note that coordinates are always index 0)
  */
@@ -454,14 +460,14 @@ class LabelArg
 {
   public:
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("LabelArg<") + asString(INDEX) + "> (internal)";
         // static const std::string n = std::string("LabelArg<") + asString(INDEX) + "> (internal)";
         // return n;
     }
-    
+
     template <class T, class BASE>
     struct Impl
     : public BASE
@@ -480,14 +486,14 @@ class CoordArg
 {
   public:
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("CoordArg<") + asString(INDEX) + "> (internal)";
         // static const std::string n = std::string("CoordArg<") + asString(INDEX) + "> (internal)";
         // return n;
     }
-    
+
     template <class T, class BASE>
     struct Impl
     : public BASE
@@ -530,7 +536,7 @@ namespace acc_detail {
 /*                                                                          */
 /****************************************************************************/
 
-    // we must make sure that Arg<INDEX> tags are at the end of the chain because 
+    // we must make sure that Arg<INDEX> tags are at the end of the chain because
     // all other tags potentially depend on them
 template <class T>
 struct PushArgTagToTail
@@ -553,7 +559,7 @@ VIGRA_PUSHARGTAG(LabelArg)
 #undef VIGRA_PUSHARGTAG
 
     // Insert the dependencies of the selected functors into the TypeList and sort
-    // the list such that dependencies come after the functors using them. Make sure 
+    // the list such that dependencies come after the functors using them. Make sure
     // that each functor is contained only once.
 template <class T>
 struct AddDependencies;
@@ -589,7 +595,7 @@ struct ActivateDependencies<TypeList<HEAD, TAIL> >
         LookupTag<HEAD, Chain>::type::activateImpl(flags);
         ActivateDependencies<TAIL>::template exec<Chain>(flags);
     }
-    
+
     template <class Chain, class ActiveFlags, class GlobalFlags>
     static void exec(ActiveFlags & flags, GlobalFlags & gflags)
     {
@@ -615,7 +621,7 @@ struct ActivateDependencies<void>
     template <class Chain, class ActiveFlags>
     static void exec(ActiveFlags &)
     {}
-    
+
     template <class Chain, class ActiveFlags, class GlobalFlags>
     static void exec(ActiveFlags &, GlobalFlags &)
     {}
@@ -652,7 +658,7 @@ template <int INDEX, class TAIL>
 struct SeparateGlobalAndRegionTags<TypeList<LabelArg<INDEX>, TAIL> >
 {
     typedef SeparateGlobalAndRegionTags<TAIL>           Inner;
-    typedef typename Inner::RegionTags                  RegionTags;
+    typedef TypeList<LabelArg<INDEX>, typename Inner::RegionTags>  RegionTags;
     typedef TypeList<LabelArg<INDEX>, typename Inner::GlobalTags>  GlobalTags;
 };
 
@@ -752,7 +758,7 @@ struct ActivateTag_Visitor
 struct TagIsActive_Visitor
 {
     mutable bool result;
-    
+
     template <class TAG, class Accu>
     void exec(Accu & a) const
     {
@@ -872,20 +878,20 @@ template <unsigned LEVEL, class GlobalAccumulatorHandle>
 struct AccumulatorEndImpl
 {
     typedef typename GlobalAccumulatorHandle::type  GlobalAccumulatorType;
-    
+
     typedef AccumulatorEnd     Tag;
     typedef void               value_type;
     typedef bool               result_type;
     typedef BitArray<LEVEL>    AccumulatorFlags;
-    
-    static const unsigned int  workInPass = 0; 
+
+    static const unsigned int  workInPass = 0;
     static const int           index = -1;
     static const unsigned      level = LEVEL;
-    
+
     AccumulatorFlags            active_accumulators_;
     mutable AccumulatorFlags    is_dirty_;
     GlobalAccumulatorHandle     globalAccumulator_;
-        
+
     template <class GlobalAccumulator>
     void setGlobalAccumulator(GlobalAccumulator const * a)
     {
@@ -896,60 +902,60 @@ struct AccumulatorEndImpl
     {
         return "AccumulatorEnd (internal)";
     }
-        
+
     bool operator()() const { return false; }
     bool get() const { return false; }
-    
+
     template <unsigned, class U>
-    void pass(U const &) 
+    void pass(U const &)
     {}
-    
+
     template <unsigned, class U>
-    void pass(U const &, double) 
+    void pass(U const &, double)
     {}
-    
+
     template <class U>
-    void mergeImpl(U const &) 
+    void mergeImpl(U const &)
     {}
-    
+
     template <class U>
-    void resize(U const &) 
+    void resize(U const &)
     {}
-        
+
     template <class U>
     void setCoordinateOffsetImpl(U const &)
     {}
-    
-    void activate() 
+
+    void activate()
     {}
-    
-    bool isActive() const 
-    { 
+
+    bool isActive() const
+    {
         return false;
     }
-    
+
     template <class Flags>
     static void activateImpl(Flags &)
     {}
-    
+
     template <class Accu, class Flags1, class Flags2>
     static void activateImpl(Flags1 &, Flags2 &)
     {}
-    
+
     template <class Flags>
     static bool isActiveImpl(Flags const &)
     {
         return true;
     }
-    
+
     void applyHistogramOptions(HistogramOptions const &)
     {}
-    
+
     static unsigned int passesRequired()
     {
         return 0;
     }
-    
+
     static unsigned int passesRequired(AccumulatorFlags const &)
     {
         return 0;
@@ -960,19 +966,19 @@ struct AccumulatorEndImpl
         active_accumulators_.clear();
         is_dirty_.clear();
     }
-        
+
     template <int which>
     void setDirtyImpl() const
     {
         is_dirty_.template set<which>();
     }
-    
+
     template <int which>
     void setCleanImpl() const
     {
         is_dirty_.template reset<which>();
     }
-    
+
     template <int which>
     bool isDirtyImpl() const
     {
@@ -1001,7 +1007,7 @@ struct DecoratorImpl<A, CurrentPass, false, CurrentPass>
     {
         a.update(t);
     }
-    
+
     template <class T>
     static void exec(A & a, T const & t, double weight)
     {
@@ -1023,7 +1029,7 @@ struct DecoratorImpl<A, CurrentPass, false, CurrentPass>
     {
         a.reshape(t);
     }
-    
+
     static void applyHistogramOptions(A & a, HistogramOptions const & options)
     {
         ApplyHistogramOptions<typename A::Tag>::exec(a, options);
@@ -1043,7 +1049,7 @@ struct DecoratorImpl<A, CurrentPass, true, CurrentPass>
     {
         return A::isActiveImpl(getAccumulator<AccumulatorEnd>(a).active_accumulators_);
     }
-    
+
     template <class T>
     static void exec(A & a, T const & t)
     {
@@ -1081,13 +1087,13 @@ struct DecoratorImpl<A, CurrentPass, true, CurrentPass>
         if(isActive(a))
             a.reshape(t);
     }
-    
+
     static void applyHistogramOptions(A & a, HistogramOptions const & options)
     {
         if(isActive(a))
             ApplyHistogramOptions<typename A::Tag>::exec(a, options);
     }
-    
+
     template <class ActiveFlags>
     static unsigned int passesRequired(ActiveFlags const & flags)
     {
@@ -1125,13 +1131,13 @@ void copyShapeImpl(T const &, U const &)   // to be used for scalars and static
 {}
 
 template <unsigned int N, class T, class Alloc, class U>
-void copyShapeImpl(MultiArray<N, T, Alloc> const & from, U & to) 
+void copyShapeImpl(MultiArray<N, T, Alloc> const & from, U & to)
 {
     to.reshape(from.shape());
 }
 
 template <class T, class Alloc, class U>
-void copyShapeImpl(Matrix<T, Alloc> const & from, U & to) 
+void copyShapeImpl(Matrix<T, Alloc> const & from, U & to)
 {
     to.reshape(from.shape());
 }
@@ -1143,12 +1149,12 @@ bool hasDataImpl(T const &)   // to be used for scalars and static arrays
 }
 
 template <unsigned int N, class T, class Stride>
-bool hasDataImpl(MultiArrayView<N, T, Stride> const & a) 
+bool hasDataImpl(MultiArrayView<N, T, Stride> const & a)
 {
     return a.hasData();
 }
 
-    // generic functions to create suitable shape objects from various input data types 
+    // generic functions to create suitable shape objects from various input data types
 template <unsigned int N, class T, class Stride>
 inline typename MultiArrayShape<N>::type
 shapeOf(MultiArrayView<N, T, Stride> const & a)
@@ -1208,72 +1214,48 @@ struct LabelDispatch
     typedef RegionAccumulators RegionAccumulatorChain;
     typedef typename LookupTag<AccumulatorEnd, RegionAccumulatorChain>::type::AccumulatorFlags ActiveFlagsType;
     typedef ArrayVector<RegionAccumulatorChain> RegionAccumulatorArray;
-        
+
     typedef LabelDispatch type;
     typedef LabelDispatch & reference;
     typedef LabelDispatch const & const_reference;
     typedef GlobalAccumulatorChain InternalBaseType;
-    
+
     typedef T const & argument_type;
     typedef argument_type first_argument_type;
     typedef double second_argument_type;
     typedef RegionAccumulatorChain & result_type;
-    
+
     static const int index = GlobalAccumulatorChain::index + 1;
-    
+
     template <class IndexDefinition, class TagFound=typename IndexDefinition::Tag>
     struct CoordIndexSelector
     {
-        static const int value = 0; // default: CoupledHandle holds coordinates at index 0 
+        static const int value = 0; // default: CoupledHandle holds coordinates at index 0
     };
-    
+
     template <class IndexDefinition>
     struct CoordIndexSelector<IndexDefinition, CoordArgTag>
     {
         static const int value = IndexDefinition::value;
     };
-    
+
     static const int coordIndex = CoordIndexSelector<typename LookupTag<CoordArgTag, GlobalAccumulatorChain>::type>::value;
     static const int coordSize  = CoupledHandleCast<coordIndex, T>::type::value_type::static_size;
     typedef TinyVector<double, coordSize> CoordinateType;
-    
+
     GlobalAccumulatorChain next_;
     RegionAccumulatorArray regions_;
     HistogramOptions region_histogram_options_;
     MultiArrayIndex ignore_label_;
     ActiveFlagsType active_region_accumulators_;
     CoordinateType coordinateOffset_;
-    
-    template <class IndexDefinition, class TagFound=typename IndexDefinition::Tag>
-    struct LabelIndexSelector
-    {
-        static const int value = 2; // default: CoupledHandle holds labels at index 2
-
-        template <class U, class NEXT>
-        static MultiArrayIndex exec(CoupledHandle<U, NEXT> const & t)
-        {
-            return (MultiArrayIndex)get<value>(t); 
-        }
-    };
-    
-    template <class IndexDefinition>
-    struct LabelIndexSelector<IndexDefinition, LabelArgTag>
-    {
-        static const int value = IndexDefinition::value;
 
-        template <class U, class NEXT>
-        static MultiArrayIndex exec(CoupledHandle<U, NEXT> const & t)
-        {
-            return (MultiArrayIndex)get<value>(t);
-        }
-    };
-    
     template <class TAG>
     struct ActivateImpl
     {
         typedef typename LookupTag<TAG, type>::type TargetAccumulator;
-        
-        static void activate(GlobalAccumulatorChain & globals, RegionAccumulatorArray & regions, 
+
+        static void activate(GlobalAccumulatorChain & globals, RegionAccumulatorArray & regions,
                              ActiveFlagsType & flags)
         {
             TargetAccumulator::template activateImpl<LabelDispatch>(
@@ -1281,13 +1263,13 @@ struct LabelDispatch
             for(unsigned int k=0; k<regions.size(); ++k)
                 getAccumulator<AccumulatorEnd>(regions[k]).active_accumulators_ = flags;
         }
-        
+
         static bool isActive(GlobalAccumulatorChain const &, ActiveFlagsType const & flags)
         {
             return TargetAccumulator::isActiveImpl(flags);
         }
     };
-    
+
     template <class TAG>
     struct ActivateImpl<Global<TAG> >
     {
@@ -1295,27 +1277,25 @@ struct LabelDispatch
         {
             LookupTag<TAG, GlobalAccumulatorChain>::type::activateImpl(getAccumulator<AccumulatorEnd>(globals).active_accumulators_);
         }
-        
+
         static bool isActive(GlobalAccumulatorChain const & globals, ActiveFlagsType const &)
         {
             return LookupTag<TAG, GlobalAccumulatorChain>::type::isActiveImpl(getAccumulator<AccumulatorEnd>(globals).active_accumulators_);
         }
     };
-    
+
     template <int INDEX>
     struct ActivateImpl<LabelArg<INDEX> >
     {
         static void activate(GlobalAccumulatorChain &, RegionAccumulatorArray &, ActiveFlagsType &)
         {}
-        
+
         static bool isActive(GlobalAccumulatorChain const & globals, ActiveFlagsType const &)
         {
             return getAccumulator<LabelArg<INDEX> >(globals).isActive();
         }
     };
-    
-    typedef typename LookupTag<LabelArgTag, GlobalAccumulatorChain>::type FindLabelIndex;
-    
+
     LabelDispatch()
     : next_(),
       regions_(),
@@ -1323,7 +1303,7 @@ struct LabelDispatch
       ignore_label_(-1),
       active_region_accumulators_()
     {}
-    
+
     LabelDispatch(LabelDispatch const & o)
     : next_(o.next_),
       regions_(o.regions_),
@@ -1336,12 +1316,12 @@ struct LabelDispatch
             getAccumulator<AccumulatorEnd>(regions_[k]).setGlobalAccumulator(&next_);
         }
     }
-    
+
     MultiArrayIndex maxRegionLabel() const
     {
         return (MultiArrayIndex)regions_.size() - 1;
     }
-    
+
     void setMaxRegionLabel(unsigned maxlabel)
     {
         if(maxRegionLabel() == (MultiArrayIndex)maxlabel)
@@ -1356,18 +1336,24 @@ struct LabelDispatch
             regions_[k].setCoordinateOffsetImpl(coordinateOffset_);
         }
     }
-    
+
     void ignoreLabel(MultiArrayIndex l)
     {
         ignore_label_ = l;
     }
-    
+
+    MultiArrayIndex ignoredLabel() const
+    {
+        return ignore_label_;
+    }
+
     void applyHistogramOptions(HistogramOptions const & options)
     {
         applyHistogramOptions(options, options);
     }
-    
-    void applyHistogramOptions(HistogramOptions const & regionoptions, HistogramOptions const & globaloptions)
+
+    void applyHistogramOptions(HistogramOptions const & regionoptions,
+                               HistogramOptions const & globaloptions)
     {
         region_histogram_options_ = regionoptions;
         for(unsigned int k=0; k<regions_.size(); ++k)
@@ -1376,7 +1362,7 @@ struct LabelDispatch
         }
         next_.applyHistogramOptions(globaloptions);
     }
-    
+
     void setCoordinateOffsetImpl(CoordinateType const & offset)
     {
         coordinateOffset_ = offset;
@@ -1386,18 +1372,25 @@ struct LabelDispatch
         }
         next_.setCoordinateOffsetImpl(coordinateOffset_);
     }
-    
+
+    void setCoordinateOffsetImpl(MultiArrayIndex k, CoordinateType const & offset)
+    {
+        vigra_precondition(0 <= k && k < (MultiArrayIndex)regions_.size(),
+             "Accumulator::setCoordinateOffset(k, offset): region k does not exist.");
+        regions_[k].setCoordinateOffsetImpl(offset);
+    }
+
     template <class U>
     void resize(U const & t)
     {
         if(regions_.size() == 0)
         {
-            static const int labelIndex = LabelIndexSelector<FindLabelIndex>::value;
-            typedef typename CoupledHandleCast<labelIndex, T>::type LabelHandle;
+            typedef HandleArgSelector<U, LabelArgTag, GlobalAccumulatorChain> LabelHandle;
             typedef typename LabelHandle::value_type LabelType;
-            typedef MultiArrayView<LabelHandle::dimensions, LabelType, StridedArrayTag> LabelArray;
-            LabelArray labelArray(t.shape(), cast<labelIndex>(t).strides(), const_cast<LabelType *>(cast<labelIndex>(t).ptr()));
-            
+            typedef MultiArrayView<LabelHandle::size, LabelType, StridedArrayTag> LabelArray;
+            LabelArray labelArray(t.shape(), LabelHandle::getHandle(t).strides(),
+                                  const_cast<LabelType *>(LabelHandle::getHandle(t).ptr()));
+
             LabelType minimum, maximum;
             labelArray.minmax(&minimum, &maximum);
             setMaxRegionLabel(maximum);
@@ -1407,55 +1400,57 @@ struct LabelDispatch
         for(unsigned int k=0; k<regions_.size(); ++k)
             regions_[k].resize(t);
     }
-    
+
     template <unsigned N>
     void pass(T const & t)
     {
-        if(LabelIndexSelector<FindLabelIndex>::exec(t) != ignore_label_)
+        typedef HandleArgSelector<T, LabelArgTag, GlobalAccumulatorChain> LabelHandle;
+        if(LabelHandle::getValue(t) != ignore_label_)
         {
             next_.template pass<N>(t);
-            regions_[LabelIndexSelector<FindLabelIndex>::exec(t)].template pass<N>(t);
+            regions_[LabelHandle::getValue(t)].template pass<N>(t);
         }
     }
-    
+
     template <unsigned N>
     void pass(T const & t, double weight)
     {
-        if(LabelIndexSelector<FindLabelIndex>::exec(t) != ignore_label_)
+        typedef HandleArgSelector<T, LabelArgTag, GlobalAccumulatorChain> LabelHandle;
+        if(LabelHandle::getValue(t) != ignore_label_)
         {
             next_.template pass<N>(t, weight);
-            regions_[LabelIndexSelector<FindLabelIndex>::exec(t)].template pass<N>(t, weight);
+            regions_[LabelHandle::getValue(t)].template pass<N>(t, weight);
         }
     }
-    
+
     static unsigned int passesRequired()
     {
         return std::max(GlobalAccumulatorChain::passesRequired(), RegionAccumulatorChain::passesRequired());
     }
-    
+
     unsigned int passesRequiredDynamic() const
     {
-        return std::max(GlobalAccumulatorChain::passesRequired(getAccumulator<AccumulatorEnd>(next_).active_accumulators_), 
+        return std::max(GlobalAccumulatorChain::passesRequired(getAccumulator<AccumulatorEnd>(next_).active_accumulators_),
                         RegionAccumulatorChain::passesRequired(active_region_accumulators_));
     }
-    
+
     void reset()
     {
         next_.reset();
-        
+
         active_region_accumulators_.clear();
         RegionAccumulatorArray().swap(regions_);
         // FIXME: or is it better to just reset the region accumulators?
         // for(unsigned int k=0; k<regions_.size(); ++k)
             // regions_[k].reset();
     }
-    
+
     template <class TAG>
     void activate()
     {
         ActivateImpl<TAG>::activate(next_, regions_, active_region_accumulators_);
     }
-    
+
     void activateAll()
     {
         getAccumulator<AccumulatorEnd>(next_).active_accumulators_.set();
@@ -1463,27 +1458,27 @@ struct LabelDispatch
         for(unsigned int k=0; k<regions_.size(); ++k)
             getAccumulator<AccumulatorEnd>(regions_[k]).active_accumulators_.set();
     }
-    
+
     template <class TAG>
     bool isActive() const
     {
         return ActivateImpl<TAG>::isActive(next_, active_region_accumulators_);
     }
-    
+
     void mergeImpl(LabelDispatch const & o)
     {
         for(unsigned int k=0; k<regions_.size(); ++k)
             regions_[k].mergeImpl(o.regions_[k]);
         next_.mergeImpl(o.next_);
     }
-    
+
     void mergeImpl(unsigned i, unsigned j)
     {
         regions_[i].mergeImpl(regions_[j]);
         regions_[j].reset();
         getAccumulator<AccumulatorEnd>(regions_[j]).active_accumulators_ = active_region_accumulators_;
     }
-    
+
     template <class ArrayLike>
     void mergeImpl(LabelDispatch const & o, ArrayLike const & labelMapping)
     {
@@ -1529,14 +1524,14 @@ struct AccumulatorFactory
     typedef typename FindNextTag<TAG, typename CONFIG::TagList>::type NextTag;
     typedef typename AccumulatorFactory<NextTag, CONFIG, LEVEL+1>::type NextType;
     typedef typename CONFIG::InputType InputType;
-    
+
     template <class T>
     struct ConfigureTag
     {
         typedef TAG type;
     };
-    
-        // When InputType is a CoupledHandle, some tags need to be wrapped into 
+
+        // When InputType is a CoupledHandle, some tags need to be wrapped into
         // DataFromHandle<> and/or Weighted<> modifiers. The following code does
         // this when appropriate.
     template <class T, class NEXT>
@@ -1546,10 +1541,10 @@ struct AccumulatorFactory
         typedef typename IfBool<(!HasModifierPriority<WrappedTag, WeightingPriority>::value && ShouldBeWeighted<WrappedTag>::value),
                                  Weighted<WrappedTag>, WrappedTag>::type type;
     };
-    
+
     typedef typename ConfigureTag<InputType>::type UseTag;
-    
-        // base class of the decorator hierarchy: default (possibly empty) 
+
+        // base class of the decorator hierarchy: default (possibly empty)
         // implementations of all members
     struct AccumulatorBase
     {
@@ -1561,17 +1556,17 @@ struct AccumulatorFactory
         typedef argument_type                first_argument_type;
         typedef double                       second_argument_type;
         typedef void                         result_type;
-        
+
         static const unsigned int            workInPass = 1;
         static const int                     index = InternalBaseType::index + 1;
-        
+
         InternalBaseType next_;
-        
+
         static std::string name()
         {
             return TAG::name();
         }
-        
+
         template <class ActiveFlags>
         static void activateImpl(ActiveFlags & flags)
         {
@@ -1579,7 +1574,7 @@ struct AccumulatorFactory
             typedef typename StandardizeDependencies<Tag>::type StdDeps;
             acc_detail::ActivateDependencies<StdDeps>::template exec<ThisType>(flags);
         }
-        
+
         template <class Accu, class ActiveFlags, class GlobalFlags>
         static void activateImpl(ActiveFlags & flags, GlobalFlags & gflags)
         {
@@ -1587,68 +1582,68 @@ struct AccumulatorFactory
             typedef typename StandardizeDependencies<Tag>::type StdDeps;
             acc_detail::ActivateDependencies<StdDeps>::template exec<Accu>(flags, gflags);
         }
-        
+
         template <class ActiveFlags>
         static bool isActiveImpl(ActiveFlags & flags)
         {
             return flags.template test<index>();
         }
-        
+
         void setDirty() const
         {
             next_.template setDirtyImpl<index>();
         }
-        
+
         template <int INDEX>
         void setDirtyImpl() const
         {
             next_.template setDirtyImpl<INDEX>();
         }
-        
+
         void setClean() const
         {
             next_.template setCleanImpl<index>();
         }
-        
+
         template <int INDEX>
         void setCleanImpl() const
         {
             next_.template setCleanImpl<INDEX>();
         }
-        
+
         bool isDirty() const
         {
             return next_.template isDirtyImpl<index>();
         }
-        
+
         template <int INDEX>
         bool isDirtyImpl() const
         {
             return next_.template isDirtyImpl<INDEX>();
         }
-        
+
         void reset()
         {}
-        
+
         template <class Shape>
         void setCoordinateOffset(Shape const &)
         {}
-        
+
         template <class Shape>
         void reshape(Shape const &)
         {}
-        
+
         void operator+=(AccumulatorBase const &)
         {}
-        
+
         template <class U>
         void update(U const &)
         {}
-        
+
         template <class U>
         void update(U const &, double)
         {}
-        
+
         template <class TargetTag>
         typename LookupDependency<TargetTag, ThisType>::result_type
         call_getDependency() const
@@ -1659,7 +1654,7 @@ struct AccumulatorFactory
 
         // The middle class(es) of the decorator hierarchy implement the actual feature computation.
     typedef typename UseTag::template Impl<InputType, AccumulatorBase> AccumulatorImpl;
-    
+
         // outer class of the decorator hierarchy. It has the following functionalities
         //  * ensure that only active accumulators are called in a dynamic accumulator chain
         //  * ensure that each accumulator is only called in its desired pass as defined in A::workInPass
@@ -1671,66 +1666,66 @@ struct AccumulatorFactory
         typedef Accumulator & reference;
         typedef Accumulator const & const_reference;
         typedef AccumulatorImpl A;
-        
+
         static const unsigned int workInPass = A::workInPass;
         static const bool allowRuntimeActivation = CONFIG::allowRuntimeActivation;
-        
+
         template <class T>
         void resize(T const & t)
         {
             this->next_.resize(t);
             DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::resize(*this, t);
         }
-        
+
         void reset()
         {
             this->next_.reset();
             A::reset();
         }
-        
+
         typename A::result_type get() const
         {
             return DecoratorImpl<A, workInPass, allowRuntimeActivation>::get(*this);
         }
-        
+
         template <unsigned N, class T>
         void pass(T const & t)
         {
             this->next_.template pass<N>(t);
             DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*this, t);
         }
-        
+
         template <unsigned N, class T>
         void pass(T const & t, double weight)
         {
             this->next_.template pass<N>(t, weight);
             DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*this, t, weight);
         }
-        
+
         void mergeImpl(Accumulator const & o)
         {
             DecoratorImpl<Accumulator, Accumulator::workInPass, allowRuntimeActivation>::mergeImpl(*this, o);
             this->next_.mergeImpl(o.next_);
         }
-        
+
         void applyHistogramOptions(HistogramOptions const & options)
         {
             DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::applyHistogramOptions(*this, options);
             this->next_.applyHistogramOptions(options);
         }
-        
+
         template <class SHAPE>
         void setCoordinateOffsetImpl(SHAPE const & offset)
         {
             this->setCoordinateOffset(offset);
             this->next_.setCoordinateOffsetImpl(offset);
         }
-        
+
         static unsigned int passesRequired()
         {
             return DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::passesRequired();
         }
-        
+
         template <class ActiveFlags>
         static unsigned int passesRequired(ActiveFlags const & flags)
         {
@@ -1750,11 +1745,11 @@ struct AccumulatorFactory<void, CONFIG, LEVEL>
 struct InvalidGlobalAccumulatorHandle
 {
     typedef Error__Global_statistics_are_only_defined_for_AccumulatorChainArray type;
-    
+
     InvalidGlobalAccumulatorHandle()
     : pointer_(0)
     {}
-    
+
     type const * pointer_;
 };
 
@@ -1775,7 +1770,7 @@ struct ConfigureAccumulatorChain<T, TypeList<HEAD, TAIL>, dynamic, GlobalHandle>
     typedef T InputType;
     static const bool allowRuntimeActivation = dynamic;
     typedef GlobalHandle GlobalAccumulatorHandle;
- 
+
     typedef typename AccumulatorFactory<HEAD, ConfigureAccumulatorChain>::type type;
 };
 
@@ -1798,20 +1793,20 @@ struct ConfigureAccumulatorChainArray<T, TypeList<HEAD, TAIL>, dynamic>
     struct GlobalAccumulatorHandle
     {
         typedef GlobalAccumulatorChain type;
-        
+
         GlobalAccumulatorHandle()
         : pointer_(0)
         {}
-        
+
         type const * pointer_;
     };
-    
+
     typedef typename ConfigureAccumulatorChain<T, RegionTags, dynamic, GlobalAccumulatorHandle>::type RegionAccumulatorChain;
-    
+
     typedef LabelDispatch<T, GlobalAccumulatorChain, RegionAccumulatorChain> type;
 };
 
-} // namespace acc_detail 
+} // namespace acc_detail
 
 /****************************************************************************/
 /*                                                                          */
@@ -1831,7 +1826,7 @@ class AccumulatorChainImpl
     typedef typename InternalBaseType::second_argument_type  second_argument_type;
     typedef void                                             value_type;
     typedef typename InternalBaseType::result_type           result_type;
-    
+
     static const int staticSize = InternalBaseType::index;
 
     InternalBaseType next_;
@@ -1839,7 +1834,7 @@ class AccumulatorChainImpl
     /** \brief Current pass of the accumulator chain.
     */
     unsigned int current_pass_;
-    
+
     AccumulatorChainImpl()
     : current_pass_(0)
     {}
@@ -1850,7 +1845,7 @@ class AccumulatorChainImpl
     {
         next_.applyHistogramOptions(options);
     }
-    
+
 
     /** Set regional and global options for all histograms in the accumulator chain.
     */
@@ -1858,19 +1853,19 @@ class AccumulatorChainImpl
     {
         next_.applyHistogramOptions(regionoptions, globaloptions);
     }
-    
+
     /** Set an offset for <tt>Coord<...></tt> statistics.
-    
+
         If the offset is non-zero, coordinate statistics such as <tt>RegionCenter</tt> are computed
         in the global coordinate system defined by the \a offset. Without an offset, these statistics
         are computed in the local coordinate system of the current region of interest.
-    */    
+    */
     template <class SHAPE>
     void setCoordinateOffset(SHAPE const & offset)
     {
         next_.setCoordinateOffsetImpl(offset);
     }
-    
+
     /** Reset current_pass_ of the accumulator chain to 'reset_to_pass'.
     */
     void reset(unsigned int reset_to_pass = 0)
@@ -1879,7 +1874,7 @@ class AccumulatorChainImpl
         if(reset_to_pass == 0)
             next_.reset();
     }
-    
+
     template <unsigned N>
     void update(T const & t)
     {
@@ -1901,7 +1896,7 @@ class AccumulatorChainImpl
             vigra_precondition(false, message);
         }
     }
-    
+
     template <unsigned N>
     void update(T const & t, double weight)
     {
@@ -1923,14 +1918,14 @@ class AccumulatorChainImpl
             vigra_precondition(false, message);
        }
     }
-    
+
     /** Equivalent to merge(o) .
     */
     void operator+=(AccumulatorChainImpl const & o)
     {
         merge(o);
     }
-    
+
     /** Merge the accumulator chain with accumulator chain 'o'. This only works if all selected statistics in the accumulator chain support the '+=' operator. See the documentations of the particular statistics for support information.
     */
     void merge(AccumulatorChainImpl const & o)
@@ -1947,7 +1942,7 @@ class AccumulatorChainImpl
     {
         update<1>(t);
     }
-    
+
     void operator()(T const & t, double weight)
     {
         update<1>(t, weight);
@@ -1957,13 +1952,13 @@ class AccumulatorChainImpl
     {
         update<2>(t);
     }
-    
+
     void updatePass2(T const & t, double weight)
     {
         update<2>(t, weight);
     }
 
-    /** Upate all accumulators in the accumulator chain that work in pass N with data t. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset() first.  
+    /** Upate all accumulators in the accumulator chain that work in pass N with data t. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset() first.
     */
     void updatePassN(T const & t, unsigned int N)
     {
@@ -1979,8 +1974,8 @@ class AccumulatorChainImpl
                      "AccumulatorChain::updatePassN(): 0 < N < 6 required.");
         }
     }
-    
-    /** Upate all accumulators in the accumulator chain that work in pass N with data t and weight. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset() first. 
+
+    /** Upate all accumulators in the accumulator chain that work in pass N with data t and weight. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset() first.
     */
     void updatePassN(T const & t, double weight, unsigned int N)
     {
@@ -1996,7 +1991,7 @@ class AccumulatorChainImpl
                      "AccumulatorChain::updatePassN(): 0 < N < 6 required.");
         }
     }
-  
+
     /** Return the number of passes required to compute all statistics in the accumulator chain.
     */
     unsigned int passesRequired() const
@@ -2011,15 +2006,16 @@ class AccumulatorChainImpl
 
 /** \brief Create an accumulator chain containing the selected statistics and their dependencies.
 
-    AccumulatorChain is used to compute global statistics which have to be selected at compile time. 
+    AccumulatorChain is used to compute global statistics which have to be selected at compile time.
 
     The template parameters are as follows:
     - T: The input type
         - either element type of the data(e.g. double, int, RGBValue, ...)
         - or type of CoupledHandle (for simultaneous access to coordinates and/or weights)
     - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
-    
-    Usage:
+
+    <b>Usage:</b>
+
     \code
     typedef double DataType;
     AccumulatorChain<DataType, Select<Variance, Mean, Minimum, ...> > accumulator;
@@ -2045,7 +2041,7 @@ class AccumulatorChain
   public:
   // \brief TypeList of Tags in the accumulator chain (?).
     typedef typename acc_detail::ConfigureAccumulatorChain<T, Selected, dynamic>::TagList AccumulatorTags;
-  
+
     /** Before having seen data (current_pass_==0), the shape of the data can be changed... (?)
     */
     template <class U, int N>
@@ -2056,7 +2052,7 @@ class AccumulatorChain
         this->next_.resize(s);
         this->current_pass_ = 1;
     }
-     
+
     /** Return the names of all tags in the accumulator chain (selected statistics and their dependencies).
     */
     static ArrayVector<std::string> const & tagNames()
@@ -2067,44 +2063,44 @@ class AccumulatorChain
 
 
 #ifdef DOXYGEN // hide AccumulatorChainImpl from documentation
-  
+
   /** Set options for all histograms in the accumulator chain. See histogram accumulators for possible options. The function is ignored if there is no histogram in the accumulator chain.
    */
   void setHistogramOptions(HistogramOptions const & options);
-    
+
   /** Set an offset for <tt>Coord<...></tt> statistics.
-  
+
       If the offset is non-zero, coordinate statistics such as <tt>RegionCenter</tt> are computed
       in the global coordinate system defined by the \a offset. Without an offset, these statistics
       are computed in the local coordinate system of the current region of interest.
-  */    
+  */
   template <class SHAPE>
   void setCoordinateOffset(SHAPE const & offset);
-    
+
   /** Reset current_pass_ of the accumulator chain to 'reset_to_pass'. */
   void reset(unsigned int reset_to_pass = 0);
 
   /** Equivalent to merge(o) . */
   void operator+=(AccumulatorChainImpl const & o);
-  
+
   /** Merge the accumulator chain with accumulator chain 'o'. This only works if all selected statistics in the accumulator chain support the '+=' operator. See the documentations of the particular statistics for support information.
    */
   void merge(AccumulatorChainImpl const & o);
-  
-  /** Upate all accumulators in the accumulator chain that work in pass N with data t. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset first.  
+
+  /** Upate all accumulators in the accumulator chain that work in pass N with data t. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset first.
    */
   void updatePassN(T const & t, unsigned int N);
-  
-  /** Upate all accumulators in the accumulator chain that work in pass N with data t and weight. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset first. 
+
+  /** Upate all accumulators in the accumulator chain that work in pass N with data t and weight. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset first.
    */
   void updatePassN(T const & t, double weight, unsigned int N);
-  
+
   /** Return the number of passes required to compute all statistics in the accumulator chain.
    */
   unsigned int passesRequired() const;
-  
-#endif   
- 
+
+#endif
+
   private:
     static ArrayVector<std::string> collectTagNames()
     {
@@ -2113,7 +2109,7 @@ class AccumulatorChain
         std::sort(n.begin(), n.end());
         return n;
     }
-}; 
+};
 
 template <unsigned int N, class T1, class T2, class T3, class T4, class T5, class Selected, bool dynamic>
 class AccumulatorChain<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected, dynamic>
@@ -2132,8 +2128,9 @@ class AccumulatorChain<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected, dynamic>
         - either element type of the data(e.g. double, int, RGBValue, ...)
         - or type of CoupledHandle (for access to coordinates and/or weights)
     - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
-    
-    Usage:
+
+    <b>Usage:</b>
+
     \code
     typedef double DataType;
     DynamicAccumulatorChain<DataType, Select<Variance, Mean, Minimum, ...> > accumulator;
@@ -2157,7 +2154,7 @@ class DynamicAccumulatorChain
   public:
     typedef typename AccumulatorChain<T, Selected, true>::InternalBaseType InternalBaseType;
     typedef typename DynamicAccumulatorChain::AccumulatorTags AccumulatorTags;
-       
+
     /** Activate statistic 'tag'. Alias names are not recognized. If the statistic is not in the accumulator chain a PreconditionViolation is thrown.
     */
     void activate(std::string tag)
@@ -2165,7 +2162,7 @@ class DynamicAccumulatorChain
         vigra_precondition(activateImpl(tag),
             std::string("DynamicAccumulatorChain::activate(): Tag '") + tag + "' not found.");
     }
-    
+
     /** %activate\<TAG\>() activates statistic 'TAG'. If the statistic is not in the accumulator chain it is ignored. (?)
     */
     template <class TAG>
@@ -2173,7 +2170,7 @@ class DynamicAccumulatorChain
     {
         LookupTag<TAG, DynamicAccumulatorChain>::type::activateImpl(getAccumulator<AccumulatorEnd>(*this).active_accumulators_);
     }
-    
+
     /** Activate all statistics in the accumulator chain.
     */
     void activateAll()
@@ -2189,7 +2186,7 @@ class DynamicAccumulatorChain
             std::string("DynamicAccumulatorChain::isActive(): Tag '") + tag + "' not found.");
         return v.result;
     }
-    
+
     /** %isActive\<TAG\>() returns true if statistic 'TAG' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statistic is not in the accumulator chain, true is returned. (?)
     */
     template <class TAG>
@@ -2208,22 +2205,22 @@ class DynamicAccumulatorChain
                 res.push_back(DynamicAccumulatorChain::tagNames()[k]);
         return res;
     }
-    
+
     /** Return number of passes required to compute the active statistics in the accumulator chain.
     */
     unsigned int passesRequired() const
     {
         return InternalBaseType::passesRequired(getAccumulator<AccumulatorEnd>(*this).active_accumulators_);
     }
-    
+
   protected:
-  
+
     bool activateImpl(std::string tag)
     {
-        return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this, 
+        return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this,
                                          normalizeString(tag), acc_detail::ActivateTag_Visitor());
     }
-    
+
     bool isActiveImpl(std::string tag, acc_detail::TagIsActive_Visitor & v) const
     {
         return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this, normalizeString(tag), v);
@@ -2237,74 +2234,197 @@ class DynamicAccumulatorChain<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected>
 
 
 
-/** \brief Create an array of accumulator chains containing the selected per-region and global statistics and their dependencies.
+/** \brief Create an accumulator chain that works independently of a MultiArray.
 
-    AccumulatorChainArray is used to compute per-region statistics (as well as global statistics). The statistics are selected at compile-time. An array of accumulator chains (one per region) for region statistics is created and one accumulator chain for global statistics. The region labels always start at 0. Use the Global modifier to compute global statistics (by default per-region statistics are computed). 
+    Instead of a CoupledHandle (the internal type of the MultiArray iterator),
+    you simply pass a data item of type T and a coordinate object of size N
+    (<tt>MultiArrayShape<N>::type</tt>) explicitly.
 
-    The template parameters are as follows:
-    - T: The input type, type of CoupledHandle (for access to coordinates, labels and weights)
-    - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
+    <b>Usage:</b>
 
-    Usage:
     \code
-    const int dim = 3; //dimension of MultiArray
     typedef double DataType;
-    typedef double WeightType;
-    typedef unsigned int LabelType;
-    typedef vigra::CoupledIteratorType<dim, DataType, WeightType, LabelType>::HandleType Handle;
-    AccumulatorChainArray<Handle, Select<DataArg<1>, WeightArg<2>, LabelArg<3>, Mean, Variance, ...> > a;
+    const int dim = 3;
+    StandAloneAccumulatorChain<dim, DataType, Select<Variance, Mean, Minimum, ...> > accumulator;
+
+    int pass = 1;
+    for( all items )
+    {
+        typename MultiArrayShape<dim>::type coord = ...;
+        DataType value = ...;
+        accumulator.updatePassN(value, coord, pass);
+    }
     \endcode
 
     See \ref FeatureAccumulators for more information and examples of use.
 */
-template <class T, class Selected, bool dynamic=false>
-class AccumulatorChainArray
-#ifndef DOXYGEN //hide AccumulatorChainImpl vom documentation
-: public AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic>::type>
-#endif
+template<unsigned int N, class T, class SELECT>
+class StandAloneAccumulatorChain
+: public AccumulatorChain<typename CoupledHandleType<N, T>::type,
+                          SELECT>
 {
   public:
-    typedef typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic> Creator;
-    typedef typename Creator::TagList AccumulatorTags;
-    typedef typename Creator::GlobalTags GlobalTags;
-    typedef typename Creator::RegionTags RegionTags;
-    
-    /** Statistics will not be computed for label l. Note that only one label can be ignored.
+    typedef typename CoupledHandleType<N, T>::type  HandleType;
+    typedef typename HandleType::base_type          CoordHandle;
+    typedef typename CoordHandle::value_type        CoordType;
+    typedef SELECT SelectType;
+    typedef AccumulatorChain<HandleType, SelectType>  BaseType;
+
+    StandAloneAccumulatorChain()
+    :   BaseType(),
+        handle_((T const *)0, CoordType(), CoordHandle(CoordType()))
+    {}
+
+    void updatePassN(const T & val, const CoordType & coord, unsigned int p)
+    {
+        cast<0>(handle_).internal_reset(coord);
+        cast<1>(handle_).internal_reset(&val);
+        BaseType::updatePassN(handle_, p);
+    }
+
+  private:
+    HandleType handle_;
+};
+
+/** \brief Create an accumulator chain that works independently of a MultiArray.
+
+    Instead of a CoupledHandle (the internal type of the MultiArray iterator),
+    you just pass a coordinate object of size N (<tt>MultiArrayShape<N>::type</tt>)
+    explicitly.
+
+    <b>Usage:</b>
+
+    \code
+    const int dim = 3;
+    StandAloneDataFreeAccumulatorChain<dim, Select<Variance, Mean, Minimum, ...> > accumulator;
+
+    int pass = 1;
+    for( all items )
+    {
+        typename MultiArrayShape<dim>::type coord = ...;
+        accumulator.updatePassN(coord, pass);
+    }
+    \endcode
+
+    See \ref FeatureAccumulators for more information and examples of use.
+*/
+template<unsigned int N, class SELECT>
+class StandAloneDataFreeAccumulatorChain
+: public AccumulatorChain<typename CoupledHandleType<N>::type,
+                          SELECT>
+{
+  public:
+    typedef typename CoupledHandleType<N>::type  HandleType;
+    typedef typename HandleType::value_type      CoordType;
+
+    typedef SELECT SelectType;
+    typedef AccumulatorChain<HandleType, SelectType>  BaseType;
+
+    StandAloneDataFreeAccumulatorChain()
+    :   BaseType(),
+        handle_(CoordType())
+    {}
+
+    template<class IGNORED_DATA>
+    void
+    updatePassN(const IGNORED_DATA & ignoreData,
+                const CoordType & coord,
+                unsigned int p)
+    {
+        this->updatePassN(coord, p);
+    }
+
+
+    void updatePassN(const CoordType & coord, unsigned int p)
+    {
+        handle_.internal_reset(coord);
+        BaseType::updatePassN(handle_, p);
+    }
+
+  private:
+    HandleType handle_;
+};
+
+
+
+
+
+/** \brief Create an array of accumulator chains containing the selected per-region and global statistics and their dependencies.
+
+    AccumulatorChainArray is used to compute per-region statistics (as well as global statistics). The statistics are selected at compile-time. An array of accumulator chains (one per region) for region statistics is created and one accumulator chain for global statistics. The region labels always start at 0. Use the Global modifier to compute global statistics (by default per-region statistics are computed).
+
+    The template parameters are as follows:
+    - T: The input type, type of CoupledHandle (for access to coordinates, labels and weights)
+    - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
+
+    Usage:
+    \code
+    const int dim = 3; //dimension of MultiArray
+    typedef double DataType;
+    typedef double WeightType;
+    typedef unsigned int LabelType;
+    typedef vigra::CoupledIteratorType<dim, DataType, WeightType, LabelType>::HandleType Handle;
+    AccumulatorChainArray<Handle, Select<DataArg<1>, WeightArg<2>, LabelArg<3>, Mean, Variance, ...> > a;
+    \endcode
+
+    See \ref FeatureAccumulators for more information and examples of use.
+*/
+template <class T, class Selected, bool dynamic=false>
+class AccumulatorChainArray
+#ifndef DOXYGEN //hide AccumulatorChainImpl vom documentation
+: public AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic>::type>
+#endif
+{
+  public:
+    typedef AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic>::type> base_type;
+    typedef typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic> Creator;
+    typedef typename Creator::TagList AccumulatorTags;
+    typedef typename Creator::GlobalTags GlobalTags;
+    typedef typename Creator::RegionTags RegionTags;
+
+    /** Statistics will not be computed for label l. Note that only one label can be ignored.
     */
     void ignoreLabel(MultiArrayIndex l)
     {
         this->next_.ignoreLabel(l);
     }
-    
+
+    /** Ask for a label to be ignored. Default: -1 (meaning that no label is ignored).
+    */
+    MultiArrayIndex ignoredLabel() const
+    {
+        return this->next_.ignoredLabel();
+    }
+
     /** Set the maximum region label (e.g. for merging two accumulator chains).
     */
     void setMaxRegionLabel(unsigned label)
     {
         this->next_.setMaxRegionLabel(label);
     }
-    
-    /** %Maximum region label. (equal to regionCount() - 1)
+
+    /** Maximum region label. (equal to regionCount() - 1)
     */
     MultiArrayIndex maxRegionLabel() const
     {
         return this->next_.maxRegionLabel();
     }
-    
+
     /** Number of Regions. (equal to maxRegionLabel() + 1)
     */
     unsigned int regionCount() const
     {
         return this->next_.regions_.size();
     }
-    
+
     /** Equivalent to <tt>merge(o)</tt>.
     */
     void operator+=(AccumulatorChainArray const & o)
     {
         merge(o);
     }
-    
-    /** Merge region i with region j. 
+
+    /** Merge region i with region j.
     */
     void merge(unsigned i, unsigned j)
     {
@@ -2312,7 +2432,7 @@ class AccumulatorChainArray
             "AccumulatorChainArray::merge(): region labels out of range.");
         this->next_.mergeImpl(i, j);
     }
-    
+
     /** Merge with accumulator chain o. maxRegionLabel() of the two accumulators must be equal.
     */
     void merge(AccumulatorChainArray const & o)
@@ -2342,6 +2462,19 @@ class AccumulatorChainArray
         return n;
     }
 
+    using base_type::setCoordinateOffset;
+
+    /** Set an offset for <tt>Coord<...></tt> statistics for region \a k.
+
+        If the offset is non-zero, coordinate statistics such as <tt>RegionCenter</tt> are computed
+        in the global coordinate system defined by the \a offset. Without an offset, these statistics
+        are computed in the local coordinate system of the current region of interest.
+    */
+    template <class SHAPE>
+    void setCoordinateOffset(MultiArrayIndex k, SHAPE const & offset)
+    {
+        this->next_.setCoordinateOffsetImpl(k, offset);
+    }
 
 #ifdef DOXYGEN // hide AccumulatorChainImpl from documentation
 
@@ -2351,26 +2484,26 @@ class AccumulatorChainArray
   /** Set regional and global options for all histograms in the accumulator chain.
    */
   void setHistogramOptions(HistogramOptions const & regionoptions, HistogramOptions const & globaloptions);
-    
+
   /** \copydoc vigra::acc::AccumulatorChain::setCoordinateOffset(SHAPE const &)
-  */    
+  */
   template <class SHAPE>
   void setCoordinateOffset(SHAPE const & offset)
-  
+
   /** \copydoc vigra::acc::AccumulatorChain::reset() */
   void reset(unsigned int reset_to_pass = 0);
 
   /** \copydoc vigra::acc::AccumulatorChain::operator+=() */
   void operator+=(AccumulatorChainImpl const & o);
-    
+
   /** \copydoc vigra::acc::AccumulatorChain::updatePassN(T const &,unsigned int) */
   void updatePassN(T const & t, unsigned int N);
-  
+
   /** \copydoc vigra::acc::AccumulatorChain::updatePassN(T const &,double,unsigned int) */
   void updatePassN(T const & t, double weight, unsigned int N);
-  
+
 #endif
-    
+
   private:
     static ArrayVector<std::string> collectTagNames()
     {
@@ -2420,20 +2553,20 @@ class DynamicAccumulatorChainArray
         vigra_precondition(activateImpl(tag),
             std::string("DynamicAccumulatorChainArray::activate(): Tag '") + tag + "' not found.");
     }
-    
+
     /** \copydoc DynamicAccumulatorChain::activate() */
     template <class TAG>
     void activate()
     {
         this->next_.template activate<TAG>();
     }
-    
+
     /** \copydoc DynamicAccumulatorChain::activateAll() */
     void activateAll()
     {
         this->next_.activateAll();
     }
-    
+
     /** Return true if the statistic 'tag' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statistic is not in the accumulator chain a PreconditionViolation is thrown. (Note that alias names are not recognized.)
      */
     bool isActive(std::string tag) const
@@ -2443,7 +2576,7 @@ class DynamicAccumulatorChainArray
             std::string("DynamicAccumulatorChainArray::isActive(): Tag '") + tag + "' not found.");
         return v.result;
     }
-    
+
     /** %isActive\<TAG\>() returns true if statistic 'TAG' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statistic is not in the accumulator chain, true is returned. (?)
      */
     template <class TAG>
@@ -2451,7 +2584,7 @@ class DynamicAccumulatorChainArray
     {
         return this->next_.template isActive<TAG>();
     }
-    
+
     /** \copydoc DynamicAccumulatorChain::activeNames() */
     ArrayVector<std::string> activeNames() const
     {
@@ -2461,7 +2594,7 @@ class DynamicAccumulatorChainArray
                 res.push_back(DynamicAccumulatorChainArray::tagNames()[k]);
         return res;
     }
-    
+
     /** \copydoc DynamicAccumulatorChain::passesRequired() */
     unsigned int passesRequired() const
     {
@@ -2469,13 +2602,13 @@ class DynamicAccumulatorChainArray
     }
 
   protected:
-  
+
     bool activateImpl(std::string tag)
     {
-        return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->next_, 
+        return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->next_,
                                          normalizeString(tag), acc_detail::ActivateTag_Visitor());
     }
-    
+
     bool isActiveImpl(std::string tag, acc_detail::TagIsActive_Visitor & v) const
     {
         return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->next_, normalizeString(tag), v);
@@ -2499,7 +2632,7 @@ struct Error__Attempt_to_access_inactive_statistic;
 namespace acc_detail {
 
     // accumulator lookup rules: find the accumulator that implements TAG
-    
+
     // When A does not implement TAG, continue search in A::InternalBaseType.
 template <class TAG, class A, class FromTag=typename A::Tag>
 struct LookupTagImpl
@@ -2538,7 +2671,7 @@ struct LookupTagImpl<TAG, A const, TAG>
     typedef typename LookupTagImpl<TAG, A, TAG>::type const * pointer;
 };
 
-    // Recursion termination: when we end up in AccumulatorEnd without finding a 
+    // Recursion termination: when we end up in AccumulatorEnd without finding a
     // suitable A, we stop and report an error
 template <class TAG, class A>
 struct LookupTagImpl<TAG, A, AccumulatorEnd>
@@ -2564,8 +2697,8 @@ struct LookupTagImpl<AccumulatorEnd, A, AccumulatorEnd>
 };
 
     // ... or we are looking for a global statistic, in which case
-    // we continue the serach via A::GlobalAccumulatorType, but remember that 
-    // we are actually looking for a global tag. 
+    // we continue the serach via A::GlobalAccumulatorType, but remember that
+    // we are actually looking for a global tag.
 template <class TAG, class A>
 struct LookupTagImpl<Global<TAG>, A, AccumulatorEnd>
 : public LookupTagImpl<TAG, typename A::GlobalAccumulatorType>
@@ -2581,7 +2714,7 @@ struct LookupTagImpl<TAG, A, LabelDispatchTag>
 {};
 
     // ... except when we are looking for a global statistic, in which case
-    // we continue via LabelDispatch::GlobalAccumulatorChain, but remember that 
+    // we continue via LabelDispatch::GlobalAccumulatorChain, but remember that
     // we are actually looking for a global tag.
 template <class TAG, class A>
 struct LookupTagImpl<Global<TAG>, A, LabelDispatchTag>
@@ -2619,11 +2752,11 @@ struct LookupDependency
 : public acc_detail::LookupTagImpl<
        typename TransferModifiers<TargetTag, typename StandardizeTag<Tag>::type>::type, A>
 {};
- 
+
 
 namespace acc_detail {
 
-    // CastImpl applies the same rules as LookupTagImpl, but returns a reference to an 
+    // CastImpl applies the same rules as LookupTagImpl, but returns a reference to an
     // accumulator instance rather than an accumulator type
 template <class Tag, class FromTag, class reference>
 struct CastImpl
@@ -2633,7 +2766,7 @@ struct CastImpl
     {
         return CastImpl<Tag, typename A::InternalBaseType::Tag, reference>::exec(a.next_);
     }
-    
+
     template <class A>
     static reference exec(A & a, MultiArrayIndex label)
     {
@@ -2649,11 +2782,11 @@ struct CastImpl<Tag, Tag, reference>
     {
         return const_cast<reference>(a);
     }
-    
+
     template <class A>
     static reference exec(A & a, MultiArrayIndex)
     {
-        vigra_precondition(false, 
+        vigra_precondition(false,
             "getAccumulator(): region accumulators can only be queried for AccumulatorChainArray.");
         return a;
     }
@@ -2667,7 +2800,7 @@ struct CastImpl<Tag, AccumulatorEnd, reference>
     {
         return a;
     }
-    
+
     template <class A>
     static reference exec(A & a, MultiArrayIndex)
     {
@@ -2693,7 +2826,7 @@ struct CastImpl<AccumulatorEnd, AccumulatorEnd, reference>
     {
         return a;
     }
-    
+
     template <class A>
     static reference exec(A & a, MultiArrayIndex)
     {
@@ -2707,11 +2840,11 @@ struct CastImpl<Tag, LabelDispatchTag, reference>
     template <class A>
     static reference exec(A & a)
     {
-        vigra_precondition(false, 
+        vigra_precondition(false,
             "getAccumulator(): a region label is required when a region accumulator is queried.");
         return CastImpl<Tag, typename A::RegionAccumulatorChain::Tag, reference>::exec(a.regions_[0]);
     }
-    
+
     template <class A>
     static reference exec(A & a, MultiArrayIndex label)
     {
@@ -2745,11 +2878,11 @@ struct CastImpl<LabelDispatchTag, LabelDispatchTag, reference>
 /** Get a reference to the accumulator 'TAG' in the accumulator chain 'a'. This can be useful for example to update a certain accumulator with data, set individual options or get information about a certain accumulator.\n
 Example of use (set options):
 \code
-    vigra::MultiArray<2, double> data(...);   
+    vigra::MultiArray<2, double> data(...);
     typedef UserRangeHistogram<40> SomeHistogram;   //binCount set at compile time
     typedef UserRangeHistogram<0> SomeHistogram2; // binCount must be set at run-time
     AccumulatorChain<DataType, Select<SomeHistogram, SomeHistogram2> > a;
-    
+
     getAccumulator<SomeHistogram>(a).setMinMax(0.1, 0.9);
     getAccumulator<SomeHistogram2>(a).setMinMax(0.0, 1.0);
 
@@ -2793,7 +2926,7 @@ Example of use:
 \code
     vigra::MultiArray<2, double> data(...);
     AccumulatorChain<DataType, Select<Variance, Mean, StdDev> > a;
-    extractFeatures(data.begin(), data.end(), a); 
+    extractFeatures(data.begin(), data.end(), a);
     double mean = get<Mean>(a);
 \endcode
 See \ref FeatureAccumulators for more information about feature computation via accumulators.
@@ -2814,7 +2947,7 @@ Example of use:
     typedef vigra::CoupledIteratorType<2, double, int>::type Iterator;
     typedef Iterator::value_type Handle;
 
-    AccumulatorChainArray<Handle, 
+    AccumulatorChainArray<Handle,
         Select<DataArg<1>, LabelArg<2>, Mean, Variance> > a;
 
     Iterator start = createCoupledIterator(data, labels);
@@ -2893,7 +3026,7 @@ The <tt>ITERATOR</tt> can be any STL-conforming <i>forward iterator</i> (includi
     extractFeatures(start, end, a);
 \endcode
 Similarly, you can use MultiArray's scan-order iterator:
-\code    
+\code
     AccumulatorChain<TinyVector<float, 2>, Select<Mean, Variance> > a;
 
     MultiArray<3, TinyVector<float, 2> > data(...);
@@ -2917,9 +3050,9 @@ namespace vigra { namespace acc {
 
     template <unsigned int N, class T1, class S1,
               class ACCUMULATOR>
-    void extractFeatures(MultiArrayView<N, T1, S1> const & a1, 
+    void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
                          ACCUMULATOR & a);
-                         
+
     ...
 
     template <unsigned int N, class T1, class S1,
@@ -2928,11 +3061,11 @@ namespace vigra { namespace acc {
                               class T4, class S4,
                               class T5, class S5,
               class ACCUMULATOR>
-    void extractFeatures(MultiArrayView<N, T1, S1> const & a1, 
-                         MultiArrayView<N, T2, S2> const & a2, 
-                         MultiArrayView<N, T3, S3> const & a3, 
-                         MultiArrayView<N, T4, S4> const & a4, 
-                         MultiArrayView<N, T5, S5> const & a5, 
+    void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
+                         MultiArrayView<N, T2, S2> const & a2,
+                         MultiArrayView<N, T3, S3> const & a3,
+                         MultiArrayView<N, T4, S4> const & a4,
+                         MultiArrayView<N, T5, S5> const & a5,
                          ACCUMULATOR & a);
 }}
 \endcode
@@ -2953,7 +3086,7 @@ void extractFeatures(ITERATOR start, ITERATOR end, ACCUMULATOR & a)
 
 template <unsigned int N, class T1, class S1,
           class ACCUMULATOR>
-void extractFeatures(MultiArrayView<N, T1, S1> const & a1, 
+void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
                      ACCUMULATOR & a)
 {
     typedef typename CoupledIteratorType<N, T1>::type Iterator;
@@ -2965,8 +3098,8 @@ void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
 template <unsigned int N, class T1, class S1,
                           class T2, class S2,
           class ACCUMULATOR>
-void extractFeatures(MultiArrayView<N, T1, S1> const & a1, 
-                     MultiArrayView<N, T2, S2> const & a2, 
+void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
+                     MultiArrayView<N, T2, S2> const & a2,
                      ACCUMULATOR & a)
 {
     typedef typename CoupledIteratorType<N, T1, T2>::type Iterator;
@@ -2979,9 +3112,9 @@ template <unsigned int N, class T1, class S1,
                           class T2, class S2,
                           class T3, class S3,
           class ACCUMULATOR>
-void extractFeatures(MultiArrayView<N, T1, S1> const & a1, 
-                     MultiArrayView<N, T2, S2> const & a2, 
-                     MultiArrayView<N, T3, S3> const & a3, 
+void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
+                     MultiArrayView<N, T2, S2> const & a2,
+                     MultiArrayView<N, T3, S3> const & a3,
                      ACCUMULATOR & a)
 {
     typedef typename CoupledIteratorType<N, T1, T2, T3>::type Iterator;
@@ -2995,10 +3128,10 @@ template <unsigned int N, class T1, class S1,
                           class T3, class S3,
                           class T4, class S4,
           class ACCUMULATOR>
-void extractFeatures(MultiArrayView<N, T1, S1> const & a1, 
-                     MultiArrayView<N, T2, S2> const & a2, 
-                     MultiArrayView<N, T3, S3> const & a3, 
-                     MultiArrayView<N, T4, S4> const & a4, 
+void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
+                     MultiArrayView<N, T2, S2> const & a2,
+                     MultiArrayView<N, T3, S3> const & a3,
+                     MultiArrayView<N, T4, S4> const & a4,
                      ACCUMULATOR & a)
 {
     typedef typename CoupledIteratorType<N, T1, T2, T3, T4>::type Iterator;
@@ -3013,11 +3146,11 @@ template <unsigned int N, class T1, class S1,
                           class T4, class S4,
                           class T5, class S5,
           class ACCUMULATOR>
-void extractFeatures(MultiArrayView<N, T1, S1> const & a1, 
-                     MultiArrayView<N, T2, S2> const & a2, 
-                     MultiArrayView<N, T3, S3> const & a3, 
-                     MultiArrayView<N, T4, S4> const & a4, 
-                     MultiArrayView<N, T5, S5> const & a5, 
+void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
+                     MultiArrayView<N, T2, S2> const & a2,
+                     MultiArrayView<N, T3, S3> const & a3,
+                     MultiArrayView<N, T4, S4> const & a4,
+                     MultiArrayView<N, T5, S5> const & a5,
                      ACCUMULATOR & a)
 {
     typedef typename CoupledIteratorType<N, T1, T2, T3, T4, T5>::type Iterator;
@@ -3101,7 +3234,7 @@ struct AccumulatorResultTraits<MultiArray<N, T, Alloc> >
 /*                                                                          */
 /****************************************************************************/
 
-/** \brief Modifier. Compute statistic globally rather than per region. 
+/** \brief Modifier. Compute statistic globally rather than per region.
 
 This modifier only works when labels are given (with (Dynamic)AccumulatorChainArray), in which case statistics are computed per-region by default.
 */
@@ -3111,16 +3244,16 @@ class Global
   public:
     typedef typename StandardizeTag<TAG>::type  TargetTag;
     typedef typename TargetTag::Dependencies    Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("Global<") + TargetTag::name() + " >";
         // static const std::string n = std::string("Global<") + TargetTag::name() + " >";
         // return n;
     }
 };
 
-/** \brief Specifies index of data in CoupledHandle. 
+/** \brief Specifies index of data in CoupledHandle.
 
     If AccumulatorChain is used with CoupledIterator, DataArg<INDEX> tells the accumulator chain which index of the Handle contains the data. (Coordinates are always index 0)
 */
@@ -3129,14 +3262,14 @@ class DataArg
 {
   public:
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("DataArg<") + asString(INDEX) + "> (internal)";
         // static const std::string n = std::string("DataArg<") + asString(INDEX) + "> (internal)";
         // return n;
     }
-    
+
     template <class T, class BASE>
     struct Impl
     : public BASE
@@ -3150,6 +3283,79 @@ class DataArg
     };
 };
 
+namespace acc_detail {
+
+template <class T, int DEFAULT, class TAG, class IndexDefinition,
+          class TagFound=typename IndexDefinition::Tag>
+struct HandleArgSelectorImpl
+{
+    static const int value = DEFAULT;
+    typedef typename CoupledHandleCast<value, T>::type type;
+    typedef typename CoupledHandleCast<value, T>::value_type value_type;
+    static const int size = type::dimensions;
+
+    template <class U, class NEXT>
+    static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type const &
+    getHandle(CoupledHandle<U, NEXT> const & t)
+    {
+        return vigra::cast<value>(t);
+    }
+
+    template <class U, class NEXT>
+    static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference
+    getValue(CoupledHandle<U, NEXT> const & t)
+    {
+        return vigra::get<value>(t);
+    }
+};
+
+template <class T, int DEFAULT, class TAG, class IndexDefinition>
+struct HandleArgSelectorImpl<T, DEFAULT, TAG, IndexDefinition, TAG>
+{
+    static const int value = IndexDefinition::value;
+    typedef typename CoupledHandleCast<value, T>::type type;
+    typedef typename CoupledHandleCast<value, T>::value_type value_type;
+    static const int size = type::dimensions;
+
+    template <class U, class NEXT>
+    static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type const &
+    getHandle(CoupledHandle<U, NEXT> const & t)
+    {
+        return vigra::cast<value>(t);
+    }
+
+    template <class U, class NEXT>
+    static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference
+    getValue(CoupledHandle<U, NEXT> const & t)
+    {
+        return vigra::get<value>(t);
+    }
+};
+
+} // namespace acc_detail
+
+template <class T, class CHAIN>
+struct HandleArgSelector<T, LabelArgTag, CHAIN>
+: public acc_detail::HandleArgSelectorImpl<T, 2, LabelArgTag,
+                                           typename LookupTag<LabelArgTag, CHAIN>::type>
+{};
+
+template <class T, class CHAIN>
+struct HandleArgSelector<T, DataArgTag, CHAIN>
+: public acc_detail::HandleArgSelectorImpl<T, 1, DataArgTag,
+                                           typename LookupTag<DataArgTag, CHAIN>::type>
+{};
+
+template <class T, class CHAIN>
+struct HandleArgSelector<T, CoordArgTag, CHAIN>
+: public acc_detail::HandleArgSelectorImpl<T, 0, CoordArgTag,
+                                           typename LookupTag<CoordArgTag, CHAIN>::type>
+{
+    typedef acc_detail::HandleArgSelectorImpl<T, 0, CoordArgTag,
+                         typename LookupTag<CoordArgTag, CHAIN>::type> base_type;
+    typedef TinyVector<double, base_type::size> value_type;
+};
+
 // Tags are automatically wrapped with DataFromHandle if CoupledHandle used
 template <class TAG>
 class DataFromHandle
@@ -3157,83 +3363,48 @@ class DataFromHandle
   public:
     typedef typename StandardizeTag<TAG>::type TargetTag;
     typedef typename TargetTag::Dependencies Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("DataFromHandle<") + TargetTag::name() + " > (internal)";
         // static const std::string n = std::string("DataFromHandle<") + TargetTag::name() + " > (internal)";
         // return n;
     }
-    
-    template <class IndexDefinition, class TagFound=typename IndexDefinition::Tag>
-    struct DataIndexSelector
-    {
-        static const int value = 1; // default: CoupledHandle holds data at index 1 
-        
-        template <class U, class NEXT>
-        static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference 
-        exec(CoupledHandle<U, NEXT> const & t)
-        {
-            return vigra::get<value>(t);
-        }
-    };
-    
-    template <class IndexDefinition>
-    struct DataIndexSelector<IndexDefinition, DataArgTag>
-    {
-        static const int value = IndexDefinition::value;
-        
-        template <class U, class NEXT>
-        static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference
-        exec(CoupledHandle<U, NEXT> const & t)
-        {
-            return vigra::get<value>(t);
-        }
-    };
-    
-    template <class T, class BASE>
-    struct SelectInputType
-    {
-        typedef typename LookupTag<DataArgTag, BASE>::type FindDataIndex;
-        typedef DataIndexSelector<FindDataIndex> DataIndex;
-        typedef typename CoupledHandleCast<DataIndex::value, T>::type::value_type type;
-    };
-    
+
     template <class T, class BASE>
     struct Impl
-    : public TargetTag::template Impl<typename SelectInputType<T, BASE>::type, BASE>
-    {
-        typedef SelectInputType<T, BASE>                InputTypeSelector;
-        typedef typename InputTypeSelector::DataIndex   DataIndex;
-        typedef typename InputTypeSelector::type        input_type;
-        typedef input_type const &                      argument_type;
-        typedef argument_type                           first_argument_type;
-        
+    : public TargetTag::template Impl<typename HandleArgSelector<T, DataArgTag, BASE>::value_type, BASE>
+    {
+        typedef HandleArgSelector<T, DataArgTag, BASE>   DataHandle;
+        typedef typename DataHandle::value_type          input_type;
+        typedef input_type const &                       argument_type;
+        typedef argument_type                            first_argument_type;
+
         typedef typename TargetTag::template Impl<input_type, BASE> ImplType;
-        
+
         using ImplType::reshape;
-        
+
         template <class U, class NEXT>
         void reshape(CoupledHandle<U, NEXT> const & t)
         {
-            ImplType::reshape(acc_detail::shapeOf(DataIndex::exec(t)));
+            ImplType::reshape(acc_detail::shapeOf(DataHandle::getValue(t)));
         }
-        
+
         template <class U, class NEXT>
         void update(CoupledHandle<U, NEXT> const & t)
         {
-            ImplType::update(DataIndex::exec(t));
+            ImplType::update(DataHandle::getValue(t));
         }
-        
+
         template <class U, class NEXT>
         void update(CoupledHandle<U, NEXT> const & t, double weight)
         {
-            ImplType::update(DataIndex::exec(t), weight);
+            ImplType::update(DataHandle::getValue(t), weight);
         }
     };
 };
 
-/** \brief Modifier. Compute statistic from pixel coordinates rather than from pixel values. 
+/** \brief Modifier. Compute statistic from pixel coordinates rather than from pixel values.
 
     AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
  */
@@ -3243,95 +3414,59 @@ class Coord
   public:
     typedef typename StandardizeTag<TAG>::type   TargetTag;
     typedef typename TargetTag::Dependencies     Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("Coord<") + TargetTag::name() + " >";
         // static const std::string n = std::string("Coord<") + TargetTag::name() + " >";
         // return n;
     }
-    
-    template <class IndexDefinition, class TagFound=typename IndexDefinition::Tag>
-    struct CoordIndexSelector
-    {
-        static const int value = 0; // default: CoupledHandle holds coordinates at index 0 
-        
-        template <class U, class NEXT>
-        static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference 
-        exec(CoupledHandle<U, NEXT> const & t)
-        {
-            return vigra::get<value>(t);
-        }
-    };
-    
-    template <class IndexDefinition>
-    struct CoordIndexSelector<IndexDefinition, CoordArgTag>
-    {
-        static const int value = IndexDefinition::value;
-        
-        template <class U, class NEXT>
-        static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference
-        exec(CoupledHandle<U, NEXT> const & t)
-        {
-            return vigra::get<value>(t);
-        }
-    };
-     
-    template <class T, class BASE>
-    struct SelectInputType
-    {
-        typedef typename LookupTag<CoordArgTag, BASE>::type FindDataIndex;
-        typedef CoordIndexSelector<FindDataIndex> CoordIndex;
-        typedef typename CoupledHandleCast<CoordIndex::value, T>::type::value_type type;
-        static const int size = type::static_size;
-    };
-    
+
     template <class T, class BASE>
     struct Impl
-    : public TargetTag::template Impl<TinyVector<double, SelectInputType<T, BASE>::size>, BASE>
-    {
-        typedef SelectInputType<T, BASE>                              InputTypeSelector;
-        typedef typename InputTypeSelector::CoordIndex                CoordIndex;
-        typedef TinyVector<double, SelectInputType<T, BASE>::size>    input_type;
-        typedef input_type const &                                    argument_type;
-        typedef argument_type                                         first_argument_type;
-        
+    : public TargetTag::template Impl<typename HandleArgSelector<T, CoordArgTag, BASE>::value_type, BASE>
+    {
+        typedef HandleArgSelector<T, CoordArgTag, BASE>   CoordHandle;
+        typedef typename CoordHandle::value_type          input_type;
+        typedef input_type const &                        argument_type;
+        typedef argument_type                             first_argument_type;
+
         typedef typename TargetTag::template Impl<input_type, BASE> ImplType;
-        
+
         input_type offset_;
-        
+
         Impl()
         : offset_()
         {}
-        
+
         void setCoordinateOffset(input_type const & offset)
         {
             offset_ = offset;
         }
-        
+
         using ImplType::reshape;
-        
+
         template <class U, class NEXT>
         void reshape(CoupledHandle<U, NEXT> const & t)
         {
-            ImplType::reshape(acc_detail::shapeOf(CoordIndex::exec(t)));
+            ImplType::reshape(acc_detail::shapeOf(CoordHandle::getValue(t)));
         }
-        
+
         template <class U, class NEXT>
         void update(CoupledHandle<U, NEXT> const & t)
         {
-            ImplType::update(CoordIndex::exec(t)+offset_);
+            ImplType::update(CoordHandle::getValue(t)+offset_);
         }
-        
+
         template <class U, class NEXT>
         void update(CoupledHandle<U, NEXT> const & t, double weight)
         {
-            ImplType::update(CoordIndex::exec(t)+offset_, weight);
+            ImplType::update(CoordHandle::getValue(t)+offset_, weight);
         }
     };
 };
 
-/** \brief Specifies index of data in CoupledHandle. 
+/** \brief Specifies index of data in CoupledHandle.
 
     If AccumulatorChain is used with CoupledIterator, WeightArg<INDEX> tells the accumulator chain which index of the Handle contains the weights. (Note that coordinates are always index 0.)
 */
@@ -3340,14 +3475,14 @@ class WeightArg
 {
   public:
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("WeightArg<") + asString(INDEX) + "> (internal)";
         // static const std::string n = std::string("WeightArg<") + asString(INDEX) + "> (internal)";
         // return n;
     }
-    
+
     template <class T, class BASE>
     struct Impl
     : public BASE
@@ -3369,24 +3504,24 @@ class Weighted
   public:
     typedef typename StandardizeTag<TAG>::type   TargetTag;
     typedef typename TargetTag::Dependencies     Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("Weighted<") + TargetTag::name() + " >";
         // static const std::string n = std::string("Weighted<") + TargetTag::name() + " >";
         // return n;
     }
-    
+
     template <class IndexDefinition, class TagFound=typename IndexDefinition::Tag>
     struct WeightIndexSelector
     {
         template <class U, class NEXT>
         static double exec(CoupledHandle<U, NEXT> const & t)
         {
-            return (double)*t; // default: CoupledHandle holds weights at the last (outermost) index 
+            return (double)*t; // default: CoupledHandle holds weights at the last (outermost) index
         }
     };
-    
+
     template <class IndexDefinition>
     struct WeightIndexSelector<IndexDefinition, WeightArgTag>
     {
@@ -3396,15 +3531,15 @@ class Weighted
             return (double)get<IndexDefinition::value>(t);
         }
     };
-    
+
     template <class T, class BASE>
     struct Impl
     : public TargetTag::template Impl<T, BASE>
     {
         typedef typename TargetTag::template Impl<T, BASE> ImplType;
-        
+
         typedef typename LookupTag<WeightArgTag, BASE>::type FindWeightIndex;
-                
+
         template <class U, class NEXT>
         void update(CoupledHandle<U, NEXT> const & t)
         {
@@ -3418,58 +3553,58 @@ class Centralize
 {
   public:
     typedef Select<Mean> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
          return "Centralize (internal)";
         // static const std::string n("Centralize (internal)");
         // return n;
     }
-   
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         static const unsigned int workInPass = 2;
-        
+
         typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
         typedef typename AccumulatorResultTraits<U>::SumType              value_type;
         typedef value_type const &                                  result_type;
 
         mutable value_type value_;
-        
+
         Impl()
         : value_()  // call default constructor explicitly to ensure zero initialization
         {}
-        
+
         void reset()
         {
             value_ = element_type();
         }
-    
+
         template <class Shape>
         void reshape(Shape const & s)
         {
             acc_detail::reshapeImpl(value_, s);
         }
-        
+
         void update(U const & t) const
         {
             using namespace vigra::multi_math;
             value_ = t - getDependency<Mean>(*this);
         }
-        
+
         void update(U const & t, double) const
         {
             update(t);
         }
-        
+
         result_type operator()(U const & t) const
         {
             update(t);
             return value_;
         }
-        
+
         result_type operator()() const
         {
             return value_;
@@ -3477,7 +3612,7 @@ class Centralize
     };
 };
 
-/** \brief Modifier. Substract mean before computing statistic. 
+/** \brief Modifier. Substract mean before computing statistic.
 
 Works in pass 2, %operator+=() not supported (merging not supported).
 */
@@ -3487,34 +3622,34 @@ class Central
   public:
     typedef typename StandardizeTag<TAG>::type                    TargetTag;
     typedef Select<Centralize, typename TargetTag::Dependencies>  Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("Central<") + TargetTag::name() + " >";
         // static const std::string n = std::string("Central<") + TargetTag::name() + " >";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE>
     {
         typedef typename TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE> ImplType;
-        
+
         static const unsigned int workInPass = 2;
-        
+
         void operator+=(Impl const & o)
         {
             vigra_precondition(false,
                 "Central<...>::operator+=(): not supported.");
         }
-    
+
         template <class T>
         void update(T const & t)
         {
             ImplType::update(getDependency<Centralize>(*this));
         }
-        
+
         template <class T>
         void update(T const & t, double weight)
         {
@@ -3523,7 +3658,7 @@ class Central
     };
 };
 
-    // alternative implementation without caching 
+    // alternative implementation without caching
     //
 // template <class TAG>
 // class Central
@@ -3531,27 +3666,27 @@ class Central
   // public:
     // typedef typename StandardizeTag<TAG>::type TargetTag;
     // typedef TypeList<Mean, typename TransferModifiers<Central<TargetTag>, typename TargetTag::Dependencies::type>::type> Dependencies;
-    
+
     // template <class U, class BASE>
     // struct Impl
     // : public TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE>
     // {
         // typedef typename TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE> ImplType;
-        
+
         // static const unsigned int workInPass = 2;
-        
+
         // void operator+=(Impl const & o)
         // {
             // vigra_precondition(false,
                 // "Central<...>::operator+=(): not supported.");
         // }
-    
+
         // template <class T>
         // void update(T const & t)
         // {
             // ImplType::update(t - getDependency<Mean>(*this));
         // }
-        
+
         // template <class T>
         // void update(T const & t, double weight)
         // {
@@ -3565,41 +3700,41 @@ class PrincipalProjection
 {
   public:
     typedef Select<Centralize, Principal<CoordinateSystem> > Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "PrincipalProjection (internal)";
         // static const std::string n("PrincipalProjection (internal)");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         static const unsigned int workInPass = 2;
-        
+
         typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
         typedef typename AccumulatorResultTraits<U>::SumType              value_type;
         typedef value_type const &                                  result_type;
 
         mutable value_type value_;
-        
+
         Impl()
         : value_()  // call default constructor explicitly to ensure zero initialization
         {}
-        
+
         void reset()
         {
             value_ = element_type();
         }
-    
+
         template <class Shape>
         void reshape(Shape const & s)
         {
             acc_detail::reshapeImpl(value_, s);
         }
-        
+
         void update(U const & t) const
         {
             for(unsigned int k=0; k<t.size(); ++k)
@@ -3609,19 +3744,19 @@ class PrincipalProjection
                     value_[k] += getDependency<Principal<CoordinateSystem> >(*this)(d, k)*getDependency<Centralize>(*this)[d];
             }
         }
-        
+
         void update(U const & t, double) const
         {
             update(t);
         }
-        
+
         result_type operator()(U const & t) const
         {
             getAccumulator<Centralize>(*this).update(t);
             update(t);
             return value_;
         }
-        
+
         result_type operator()() const
         {
             return value_;
@@ -3639,34 +3774,34 @@ class Principal
   public:
     typedef typename StandardizeTag<TAG>::type                             TargetTag;
     typedef Select<PrincipalProjection, typename TargetTag::Dependencies>  Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("Principal<") + TargetTag::name() + " >";
         // static const std::string n = std::string("Principal<") + TargetTag::name() + " >";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE>
     {
         typedef typename TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE> ImplType;
-        
+
         static const unsigned int workInPass = 2;
-        
+
         void operator+=(Impl const & o)
         {
             vigra_precondition(false,
                 "Principal<...>::operator+=(): not supported.");
         }
-    
+
         template <class T>
         void update(T const & t)
         {
             ImplType::update(getDependency<PrincipalProjection>(*this));
         }
-        
+
         template <class T>
         void update(T const & t, double weight)
         {
@@ -3677,17 +3812,17 @@ class Principal
 
 /*
 important notes on modifiers:
- * upon accumulator creation, modifiers are reordered so that data preparation is innermost, 
+ * upon accumulator creation, modifiers are reordered so that data preparation is innermost,
    and data access is outermost, e.g.:
         Coord<DivideByCount<Principal<PowerSum<2> > > >
  * modifiers are automatically transfered to dependencies as appropriate
  * modifiers for lookup (getAccumulator and get) of dependent accumulators are automatically adjusted
  * modifiers must adjust workInPass for the contained accumulator as appropriate
- * we may implement convenience versions of Select that apply a modifier to all 
+ * we may implement convenience versions of Select that apply a modifier to all
    contained tags at once
  * weighted accumulators have their own Count object when used together
    with unweighted ones (this is as yet untested - FIXME)
- * certain accumulators must remain unchanged when wrapped in certain modifiers: 
+ * certain accumulators must remain unchanged when wrapped in certain modifiers:
     * Count: always except for Weighted<Count> and CoordWeighted<Count>
     * Sum: data preparation modifiers
     * FlatScatterMatrixImpl, CovarianceEigensystemImpl: Principal and Whitened
@@ -3706,14 +3841,14 @@ class CoordinateSystem
 {
   public:
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "CoordinateSystem";
         // static const std::string n("CoordinateSystem");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
@@ -3723,11 +3858,11 @@ class CoordinateSystem
         typedef value_type const &  result_type;
 
         value_type value_;
-        
+
         Impl()
         : value_()  // call default constructor explicitly to ensure zero initialization
         {}
-        
+
         void reset()
         {
             value_ = element_type();
@@ -3738,7 +3873,7 @@ class CoordinateSystem
         {
             acc_detail::reshapeImpl(value_, s);
         }
-        
+
         result_type operator()() const
         {
             return value_;
@@ -3746,8 +3881,8 @@ class CoordinateSystem
     };
 };
 
-template <class BASE, class T, 
-          class ElementType=typename AccumulatorResultTraits<T>::element_promote_type, 
+template <class BASE, class T,
+          class ElementType=typename AccumulatorResultTraits<T>::element_promote_type,
           class SumType=typename AccumulatorResultTraits<T>::SumType>
 struct SumBaseImpl
 : public BASE
@@ -3757,11 +3892,11 @@ struct SumBaseImpl
     typedef value_type const &  result_type;
 
     value_type value_;
-    
+
     SumBaseImpl()
     : value_()  // call default constructor explicitly to ensure zero initialization
     {}
-    
+
     void reset()
     {
         value_ = element_type();
@@ -3772,7 +3907,7 @@ struct SumBaseImpl
     {
         acc_detail::reshapeImpl(value_, s);
     }
-    
+
     void operator+=(SumBaseImpl const & o)
     {
         value_ += o.value_;
@@ -3790,14 +3925,14 @@ class PowerSum<0>
 {
   public:
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "PowerSum<0>";
         // static const std::string n("PowerSum<0>");
         // return n;
     }
-    
+
     template <class T, class BASE>
     struct Impl
     : public SumBaseImpl<BASE, T, double, double>
@@ -3806,7 +3941,7 @@ class PowerSum<0>
         {
             ++this->value_;
         }
-        
+
         void update(T const & t, double weight)
         {
             this->value_ += weight;
@@ -3820,14 +3955,14 @@ class PowerSum<1>
 {
   public:
     typedef Select<> Dependencies;
-     
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "PowerSum<1>";
         // static const std::string n("PowerSum<1>");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public SumBaseImpl<BASE, U>
@@ -3836,9 +3971,11 @@ class PowerSum<1>
         {
             this->value_ += t;
         }
-        
+
         void update(U const & t, double weight)
         {
+            using namespace multi_math;
+
             this->value_ += weight*t;
         }
     };
@@ -3853,27 +3990,27 @@ class PowerSum
 {
   public:
     typedef Select<> Dependencies;
-     
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("PowerSum<") + asString(N) + ">";
         // static const std::string n = std::string("PowerSum<") + asString(N) + ">";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public SumBaseImpl<BASE, U>
     {
         void update(U const & t)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += pow(t, (int)N);
         }
-        
+
         void update(U const & t, double weight)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += weight*pow(t, (int)N);
         }
     };
@@ -3884,27 +4021,27 @@ class AbsPowerSum<1>
 {
   public:
     typedef Select<> Dependencies;
-     
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "AbsPowerSum<1>";
         // static const std::string n("AbsPowerSum<1>");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public SumBaseImpl<BASE, U>
     {
         void update(U const & t)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += abs(t);
         }
-        
+
         void update(U const & t, double weight)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += weight*abs(t);
         }
     };
@@ -3919,27 +4056,27 @@ class AbsPowerSum
 {
   public:
     typedef Select<> Dependencies;
-     
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("AbsPowerSum<") + asString(N) + ">";
         // static const std::string n = std::string("AbsPowerSum<") + asString(N) + ">";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public SumBaseImpl<BASE, U>
     {
         void update(U const & t)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += pow(abs(t), (int)N);
         }
-        
+
         void update(U const & t, double weight)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += weight*pow(abs(t), (int)N);
         }
     };
@@ -3954,11 +4091,11 @@ struct CachedResultBase
     typedef value_type const &                                 result_type;
 
     mutable value_type value_;
-    
+
     CachedResultBase()
     : value_()  // call default constructor explicitly to ensure zero initialization
     {}
-    
+
     void reset()
     {
         value_ = element_type();
@@ -3980,7 +4117,7 @@ struct CachedResultBase
     {
         this->setDirty();
     }
-    
+
     void update(U const &, double)
     {
          this->setDirty();
@@ -3996,20 +4133,20 @@ class DivideByCount
   public:
     typedef typename StandardizeTag<TAG>::type TargetTag;
     typedef Select<TargetTag, Count> Dependencies;
-  
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("DivideByCount<") + TargetTag::name() + " >";
         // static const std::string n = std::string("DivideByCount<") + TargetTag::name() + " >";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
-    : public CachedResultBase<BASE, typename LookupDependency<TargetTag, BASE>::value_type, U> 
+    : public CachedResultBase<BASE, typename LookupDependency<TargetTag, BASE>::value_type, U>
     {
         typedef typename CachedResultBase<BASE, typename LookupDependency<TargetTag, BASE>::value_type, U>::result_type result_type;
-        
+
         result_type operator()() const
         {
             if(this->isDirty())
@@ -4032,21 +4169,21 @@ class DivideUnbiased
   public:
     typedef typename StandardizeTag<TAG>::type TargetTag;
     typedef Select<TargetTag, Count> Dependencies;
-      
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("DivideUnbiased<") + TargetTag::name() + " >";
         // static const std::string n = std::string("DivideUnbiased<") + TargetTag::name() + " >";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         typedef typename LookupDependency<TargetTag, BASE>::value_type  value_type;
         typedef value_type                                       result_type;
-        
+
         result_type operator()() const
         {
             using namespace multi_math;
@@ -4064,22 +4201,22 @@ class RootDivideByCount
   public:
     typedef typename StandardizeTag<DivideByCount<TAG> >::type TargetTag;
     typedef Select<TargetTag> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         typedef typename StandardizeTag<TAG>::type InnerTag;
         return std::string("RootDivideByCount<") + InnerTag::name() + " >";
         // static const std::string n = std::string("RootDivideByCount<") + InnerTag::name() + " >";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         typedef typename LookupDependency<TargetTag, BASE>::value_type  value_type;
         typedef value_type                                       result_type;
-        
+
         result_type operator()() const
         {
             using namespace multi_math;
@@ -4097,22 +4234,22 @@ class RootDivideUnbiased
   public:
     typedef typename StandardizeTag<DivideUnbiased<TAG> >::type TargetTag;
     typedef Select<TargetTag> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         typedef typename StandardizeTag<TAG>::type InnerTag;
         return std::string("RootDivideUnbiased<") + InnerTag::name() + " >";
         // static const std::string n = std::string("RootDivideUnbiased<") + InnerTag::name() + " >";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         typedef typename LookupDependency<TargetTag, BASE>::value_type  value_type;
         typedef value_type                                       result_type;
-        
+
         result_type operator()() const
         {
             using namespace multi_math;
@@ -4128,14 +4265,14 @@ class Central<PowerSum<2> >
 {
   public:
     typedef Select<Mean, Count> Dependencies;
-     
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "Central<PowerSum<2> >";
         // static const std::string n("Central<PowerSum<2> >");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public SumBaseImpl<BASE, U>
@@ -4153,7 +4290,7 @@ class Central<PowerSum<2> >
                 this->value_ += o.value_ + n1 * n2 / (n1 + n2) * sq(getDependency<Mean>(*this) - getDependency<Mean>(o));
             }
         }
-    
+
         void update(U const & t)
         {
             double n = getDependency<Count>(*this);
@@ -4163,7 +4300,7 @@ class Central<PowerSum<2> >
                 this->value_ += n / (n - 1.0) * sq(getDependency<Mean>(*this) - t);
             }
         }
-        
+
         void update(U const & t, double weight)
         {
             double n = getDependency<Count>(*this);
@@ -4183,14 +4320,14 @@ class Central<PowerSum<3> >
 {
   public:
     typedef Select<Centralize, Count, Mean, Central<PowerSum<2> > > Dependencies;
-     
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "Central<PowerSum<3> >";
         // static const std::string n("Central<PowerSum<3> >");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public SumBaseImpl<BASE, U>
@@ -4198,11 +4335,11 @@ class Central<PowerSum<3> >
         typedef typename SumBaseImpl<BASE, U>::value_type value_type;
 
         static const unsigned int workInPass = 2;
-        
+
         void operator+=(Impl const & o)
         {
             typedef Central<PowerSum<2> > Sum2Tag;
-            
+
             using namespace vigra::multi_math;
             double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
             if(n1 == 0.0)
@@ -4218,16 +4355,16 @@ class Central<PowerSum<3> >
                                3.0 / n * delta * (n1 * getDependency<Sum2Tag>(o) - n2 * getDependency<Sum2Tag>(*this));
             }
         }
-    
+
         void update(U const & t)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += pow(getDependency<Centralize>(*this), 3);
         }
-        
+
         void update(U const & t, double weight)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += weight*pow(getDependency<Centralize>(*this), 3);
         }
     };
@@ -4239,14 +4376,14 @@ class Central<PowerSum<4> >
 {
   public:
     typedef Select<Centralize, Central<PowerSum<3> > > Dependencies;
-     
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "Central<PowerSum<4> >";
         // static const std::string n("Central<PowerSum<4> >");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public SumBaseImpl<BASE, U>
@@ -4254,7 +4391,7 @@ class Central<PowerSum<4> >
         typedef typename SumBaseImpl<BASE, U>::value_type value_type;
 
         static const unsigned int workInPass = 2;
-        
+
         void operator+=(Impl const & o)
         {
             typedef Central<PowerSum<2> > Sum2Tag;
@@ -4279,22 +4416,22 @@ class Central<PowerSum<4> >
                               4.0 / n * delta * (n1 * getDependency<Sum3Tag>(o) - n2 * getDependency<Sum3Tag>(*this));
             }
         }
-    
+
         void update(U const & t)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += pow(getDependency<Centralize>(*this), 4);
         }
-        
+
         void update(U const & t, double weight)
         {
-            using namespace vigra::multi_math;            
+            using namespace vigra::multi_math;
             this->value_ += weight*pow(getDependency<Centralize>(*this), 4);
         }
     };
 };
 
-/** \brief Basic statistic. Skewness. 
+/** \brief Basic statistic. Skewness.
 
     %Skewness =@f$ \frac{ \frac{1}{n}\sum_i (x_i-\hat{x})^3 }{ (\frac{1}{n}\sum_i (x_i-\hat{x})^2)^{3/2} } @f$ .
     Works in pass 2, %operator+=() supported (merging supported).
@@ -4303,20 +4440,20 @@ class Skewness
 {
   public:
     typedef Select<Central<PowerSum<2> >, Central<PowerSum<3> > > Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "Skewness";
         // static const std::string n("Skewness");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         static const unsigned int workInPass = 2;
-        
+
         typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::value_type   value_type;
         typedef value_type                                                    result_type;
 
@@ -4324,8 +4461,8 @@ class Skewness
         {
             typedef Central<PowerSum<3> > Sum3;
             typedef Central<PowerSum<2> > Sum2;
-        
-                        using namespace multi_math;
+
+            using namespace multi_math;
             return sqrt(getDependency<Count>(*this)) * getDependency<Sum3>(*this) / pow(getDependency<Sum2>(*this), 1.5);
         }
     };
@@ -4339,66 +4476,66 @@ class UnbiasedSkewness
 {
   public:
     typedef Select<Skewness> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "UnbiasedSkewness";
         // static const std::string n("UnbiasedSkewness");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         static const unsigned int workInPass = 2;
-        
+
         typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::value_type   value_type;
         typedef value_type                                                    result_type;
 
         result_type operator()() const
         {
-                        using namespace multi_math;
+            using namespace multi_math;
             double n = getDependency<Count>(*this);
             return sqrt(n*(n-1.0)) / (n - 2.0) * getDependency<Skewness>(*this);
         }
     };
 };
 
-/** \brief Basic statistic. Kurtosis. 
+/** \brief Basic statistic. Kurtosis.
 
     %Kurtosis = @f$ \frac{ \frac{1}{n}\sum_i (x_i-\bar{x})^4 }{
-    (\frac{1}{n} \sum_i(x_i-\bar{x})^2)^2 } - 3 @f$ . 
+    (\frac{1}{n} \sum_i(x_i-\bar{x})^2)^2 } - 3 @f$ .
     Works in pass 2, %operator+=() supported (merging supported).
 */
 class Kurtosis
 {
   public:
     typedef Select<Central<PowerSum<2> >, Central<PowerSum<4> > > Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "Kurtosis";
         // static const std::string n("Kurtosis");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         static const unsigned int workInPass = 2;
-        
-        typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::value_type value_type;
-        typedef value_type                                                  result_type;
+
+        typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::value_type  value_type;
+        typedef value_type                                                          result_type;
 
         result_type operator()() const
         {
             typedef Central<PowerSum<4> > Sum4;
             typedef Central<PowerSum<2> > Sum2;
-        
-                        using namespace multi_math;
-            return getDependency<Count>(*this) * getDependency<Sum4>(*this) / sq(getDependency<Sum2>(*this)) - value_type(3.0);
+
+            using namespace multi_math;
+            return getDependency<Count>(*this) * getDependency<Sum4>(*this) / sq(getDependency<Sum2>(*this)) - 3.0;
         }
     };
 };
@@ -4411,26 +4548,26 @@ class UnbiasedKurtosis
 {
   public:
     typedef Select<Kurtosis> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "UnbiasedKurtosis";
         // static const std::string n("UnbiasedKurtosis");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         static const unsigned int workInPass = 2;
-        
+
         typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::value_type value_type;
-        typedef value_type                                                  result_type;
+        typedef value_type                                                         result_type;
 
         result_type operator()() const
         {
-                        using namespace multi_math;
+            using namespace multi_math;
             double n = getDependency<Count>(*this);
             return (n-1.0)/((n-2.0)*(n-3.0))*((n+1.0)*getDependency<Kurtosis>(*this) + value_type(6.0));
         }
@@ -4507,14 +4644,14 @@ class FlatScatterMatrix
 {
   public:
     typedef Select<Mean, Count> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "FlatScatterMatrix";
         // static const std::string n("FlatScatterMatrix");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
@@ -4522,22 +4659,22 @@ class FlatScatterMatrix
         typedef typename AccumulatorResultTraits<U>::element_promote_type  element_type;
         typedef typename AccumulatorResultTraits<U>::FlatCovarianceType    value_type;
         typedef value_type const &                                   result_type;
-       
+
         typedef typename AccumulatorResultTraits<U>::SumType        SumType;
 
         value_type value_;
         SumType     diff_;
-        
+
         Impl()
         : value_(),  // call default constructor explicitly to ensure zero initialization
           diff_()
         {}
-        
+
         void reset()
         {
             value_ = element_type();
         }
-    
+
         template <class Shape>
         void reshape(Shape const & s)
         {
@@ -4545,7 +4682,7 @@ class FlatScatterMatrix
             acc_detail::reshapeImpl(value_, Shape1(size*(size+1)/2));
             acc_detail::reshapeImpl(diff_, s);
         }
-        
+
         void operator+=(Impl const & o)
         {
             double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
@@ -4561,22 +4698,22 @@ class FlatScatterMatrix
                 value_ += o.value_;
             }
         }
-    
+
         void update(U const & t)
         {
             compute(t);
         }
-        
+
         void update(U const & t, double weight)
         {
             compute(t, weight);
         }
-        
+
         result_type operator()() const
         {
             return value_;
         }
-        
+
       private:
         void compute(U const & t, double weight = 1.0)
         {
@@ -4597,28 +4734,28 @@ class DivideByCount<FlatScatterMatrix>
 {
   public:
     typedef Select<FlatScatterMatrix, Count> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "DivideByCount<FlatScatterMatrix>";
         // static const std::string n("DivideByCount<FlatScatterMatrix>");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U>
     {
-        typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U> BaseType;      
+        typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U> BaseType;
         typedef typename BaseType::result_type result_type;
-        
+
         template <class Shape>
         void reshape(Shape const & s)
         {
             int size = prod(s);
             acc_detail::reshapeImpl(this->value_, Shape2(size,size));
         }
-        
+
         result_type operator()() const
         {
             if(this->isDirty())
@@ -4637,28 +4774,28 @@ class DivideUnbiased<FlatScatterMatrix>
 {
   public:
     typedef Select<FlatScatterMatrix, Count> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "DivideUnbiased<FlatScatterMatrix>";
         // static const std::string n("DivideUnbiased<FlatScatterMatrix>");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U>
     {
-        typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U> BaseType;      
+        typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U> BaseType;
         typedef typename BaseType::result_type result_type;
-        
+
         template <class Shape>
         void reshape(Shape const & s)
         {
             int size = prod(s);
             acc_detail::reshapeImpl(this->value_, Shape2(size,size));
         }
-        
+
         result_type operator()() const
         {
             if(this->isDirty())
@@ -4677,14 +4814,14 @@ class ScatterMatrixEigensystem
 {
   public:
     typedef Select<FlatScatterMatrix> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "ScatterMatrixEigensystem";
         // static const std::string n("ScatterMatrixEigensystem");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
@@ -4696,11 +4833,11 @@ class ScatterMatrixEigensystem
         typedef value_type const &                                         result_type;
 
         mutable value_type value_;
-        
+
         Impl()
         : value_()
         {}
-        
+
         void operator+=(Impl const & o)
         {
             if(!acc_detail::hasDataImpl(value_.second))
@@ -4715,7 +4852,7 @@ class ScatterMatrixEigensystem
         {
             this->setDirty();
         }
-        
+
         void update(U const &, double)
         {
              this->setDirty();
@@ -4727,7 +4864,7 @@ class ScatterMatrixEigensystem
             value_.second = element_type();
             this->setClean();
         }
-    
+
         template <class Shape>
         void reshape(Shape const & s)
         {
@@ -4735,7 +4872,7 @@ class ScatterMatrixEigensystem
             acc_detail::reshapeImpl(value_.first, Shape1(size));
             acc_detail::reshapeImpl(value_.second, Shape2(size,size));
         }
-        
+
         result_type operator()() const
         {
             if(this->isDirty())
@@ -4745,7 +4882,7 @@ class ScatterMatrixEigensystem
             }
             return value_;
         }
-        
+
       private:
         template <class Flat, class EW, class EV>
         static void compute(Flat const & flatScatter, EW & ew, EV & ev)
@@ -4756,7 +4893,7 @@ class ScatterMatrixEigensystem
             MultiArrayView<2, element_type> ewview(Shape2(ev.shape(0), 1), &ew[0]);
             symmetricEigensystem(scatter, ewview, ev);
         }
-        
+
         static void compute(double v, double & ew, double & ev)
         {
             ew = v;
@@ -4771,14 +4908,14 @@ class DivideByCount<ScatterMatrixEigensystem>
 {
   public:
     typedef Select<ScatterMatrixEigensystem, Count> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "DivideByCount<ScatterMatrixEigensystem>";
         // static const std::string n("DivideByCount<ScatterMatrixEigensystem>");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
@@ -4791,11 +4928,11 @@ class DivideByCount<ScatterMatrixEigensystem>
         typedef value_type const &                                        result_type;
 
         mutable value_type value_;
-        
+
         Impl()
         : value_(EigenvalueType(), BASE::template call_getDependency<ScatterMatrixEigensystem>().second)
         {}
-        
+
         void operator+=(Impl const &)
         {
             this->setDirty();
@@ -4805,7 +4942,7 @@ class DivideByCount<ScatterMatrixEigensystem>
         {
             this->setDirty();
         }
-        
+
         void update(U const &, double)
         {
              this->setDirty();
@@ -4816,14 +4953,14 @@ class DivideByCount<ScatterMatrixEigensystem>
             value_.first = element_type();
             this->setClean();
         }
-    
+
         template <class Shape>
         void reshape(Shape const & s)
         {
             int size = prod(s);
             acc_detail::reshapeImpl(value_.first, Shape2(size,1));
         }
-        
+
         result_type operator()() const
         {
             if(this->isDirty())
@@ -4843,7 +4980,7 @@ class DivideByCount<ScatterMatrixEigensystem>
 // {
   // public:
     // typedef Select<Covariance> Dependencies;
-    
+
     // template <class U, class BASE>
     // struct Impl
     // : public BASE
@@ -4855,11 +4992,11 @@ class DivideByCount<ScatterMatrixEigensystem>
         // typedef value_type const &                                         result_type;
 
         // mutable value_type value_;
-        
+
         // Impl()
         // : value_()
         // {}
-        
+
         // void operator+=(Impl const &)
         // {
             // this->setDirty();
@@ -4869,7 +5006,7 @@ class DivideByCount<ScatterMatrixEigensystem>
         // {
             // this->setDirty();
         // }
-        
+
         // void update(U const &, double)
         // {
              // this->setDirty();
@@ -4881,7 +5018,7 @@ class DivideByCount<ScatterMatrixEigensystem>
             // value_.second = element_type();
             // this->setClean();
         // }
-    
+
         // template <class Shape>
         // void reshape(Shape const & s)
         // {
@@ -4889,7 +5026,7 @@ class DivideByCount<ScatterMatrixEigensystem>
             // acc_detail::reshapeImpl(value_.first, Shape2(size,1));
             // acc_detail::reshapeImpl(value_.second, Shape2(size,size));
         // }
-        
+
         // result_type operator()() const
         // {
             // if(this->isDirty())
@@ -4899,7 +5036,7 @@ class DivideByCount<ScatterMatrixEigensystem>
             // }
             // return value_;
         // }
-        
+
       // private:
         // template <class Cov, class EW, class EV>
         // static void compute(Cov const & cov, EW & ew, EV & ev)
@@ -4908,7 +5045,7 @@ class DivideByCount<ScatterMatrixEigensystem>
             // MultiArrayView<2, element_type> ewview(Shape2(cov.shape(0), 1), &ew[0]);
             // symmetricEigensystem(cov, ewview, ev);
         // }
-        
+
         // static void compute(double cov, double & ew, double & ev)
         // {
             // ew = cov;
@@ -4925,21 +5062,21 @@ class Principal<PowerSum<2> >
 {
   public:
     typedef Select<ScatterMatrixEigensystem> Dependencies;
-     
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "Principal<PowerSum<2> >";
         // static const std::string n("Principal<PowerSum<2> >");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>::type::EigenvalueType value_type;
         typedef value_type const &                                                       result_type;
-        
+
         result_type operator()() const
         {
             return getDependency<ScatterMatrixEigensystem>(*this).first;
@@ -4956,21 +5093,21 @@ class Principal<CoordinateSystem>
 {
   public:
     typedef Select<ScatterMatrixEigensystem> Dependencies;
-     
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "Principal<CoordinateSystem>";
         // static const std::string n("Principal<CoordinateSystem>");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
     {
         typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>::type::EigenvectorType value_type;
         typedef value_type const &                                                        result_type;
-        
+
         result_type operator()() const
         {
             return getDependency<ScatterMatrixEigensystem>(*this).second;
@@ -4986,14 +5123,14 @@ class Minimum
 {
   public:
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "Minimum";
         // static const std::string n("Minimum");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
@@ -5003,43 +5140,43 @@ class Minimum
         typedef value_type const &                                result_type;
 
         value_type value_;
-        
+
         Impl()
         {
             value_ = NumericTraits<element_type>::max();
         }
-        
+
         void reset()
         {
             value_ = NumericTraits<element_type>::max();
         }
-    
+
         template <class Shape>
         void reshape(Shape const & s)
         {
             acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>::max());
         }
-        
+
         void operator+=(Impl const & o)
         {
             updateImpl(o.value_); // necessary because std::min causes ambiguous overload
         }
-    
+
         void update(U const & t)
         {
             updateImpl(t);
         }
-        
+
         void update(U const & t, double)
         {
             updateImpl(t);
         }
-        
+
         result_type operator()() const
         {
             return value_;
         }
-        
+
       private:
         template <class T>
         void updateImpl(T const & o)
@@ -5047,7 +5184,7 @@ class Minimum
             using namespace multi_math;
             value_ = min(value_, o);
         }
-        
+
         template <class T, class Alloc>
         void updateImpl(MultiArray<1, T, Alloc> const & o)
         {
@@ -5064,14 +5201,14 @@ class Maximum
 {
   public:
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return "Maximum";
         // static const std::string n("Maximum");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
@@ -5081,43 +5218,43 @@ class Maximum
         typedef value_type const &                                result_type;
 
         value_type value_;
-        
+
         Impl()
         {
             value_ = NumericTraits<element_type>::min();
         }
-        
+
         void reset()
         {
             value_ = NumericTraits<element_type>::min();
         }
-    
+
         template <class Shape>
         void reshape(Shape const & s)
         {
             acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>::min());
         }
-        
+
         void operator+=(Impl const & o)
         {
             updateImpl(o.value_); // necessary because std::max causes ambiguous overload
         }
-    
+
         void update(U const & t)
         {
             updateImpl(t);
         }
-        
+
         void update(U const & t, double)
         {
             updateImpl(t);
         }
-        
+
         result_type operator()() const
         {
             return value_;
         }
-        
+
       private:
         template <class T>
         void updateImpl(T const & o)
@@ -5125,7 +5262,7 @@ class Maximum
             using namespace multi_math;
             value_ = max(value_, o);
         }
-        
+
         template <class T, class Alloc>
         void updateImpl(MultiArray<1, T, Alloc> const & o)
         {
@@ -5134,22 +5271,23 @@ class Maximum
     };
 };
 
-/** \brief Basic statistic. Data value where weight assumes its minimal value. 
+/** \brief Basic statistic. First data value seen of the object.
 
-    Weights must be given. Coord<ArgMinWeight> gives coordinate where weight assumes its minimal value. Works in pass 1, %operator+=() supported (merging supported).
+    Usually used as <tt>Coord<FirstSeen></tt> (alias <tt>RegionAnchor</tt>)
+    which provides a well-defined anchor point for the region.
 */
-class ArgMinWeight
+class FirstSeen
 {
   public:
-    typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
-        return "ArgMinWeight";
-        // static const std::string n("ArgMinWeight");
+    typedef Select<Count> Dependencies;
+
+    static std::string name()
+    {
+        return "FirstSeen";
+        // static const std::string n("FirstSeen");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
@@ -5158,50 +5296,41 @@ class ArgMinWeight
         typedef typename AccumulatorResultTraits<U>::MinmaxType   value_type;
         typedef value_type const &                                result_type;
 
-        double min_weight_;
         value_type value_;
-        
+
         Impl()
-        : min_weight_(NumericTraits<double>::max()),
-          value_()
+        : value_()
         {}
-        
+
         void reset()
         {
-            min_weight_ = NumericTraits<double>::max();
             value_ = element_type();
         }
-    
+
         template <class Shape>
         void reshape(Shape const & s)
         {
             acc_detail::reshapeImpl(value_, s);
         }
-        
+
         void operator+=(Impl const & o)
         {
-            using namespace multi_math;
-            if(o.min_weight_ < min_weight_)
-            {
-                min_weight_ = o.min_weight_;
+            // FIXME: only works for Coord<FirstSeen>
+            if(reverse(o.value_) < reverse(value_))
                 value_ = o.value_;
-            }
         }
-    
+
         void update(U const & t)
         {
-            vigra_precondition(false, "ArgMinWeight::update() needs weights.");
+            if(getDependency<Count>(*this) == 1)
+                value_ = t;
         }
-        
+
         void update(U const & t, double weight)
         {
-            if(weight < min_weight_)
-            {
-                min_weight_ = weight;
-                value_ = t;
-            }
+            update(t);
         }
-        
+
         result_type operator()() const
         {
             return value_;
@@ -5209,22 +5338,130 @@ class ArgMinWeight
     };
 };
 
-/** \brief Basic statistic. Data where weight assumes its maximal value. 
+/** \brief Return both the minimum and maximum in <tt>std::pair</tt>.
 
-    Weights must be given. Coord<ArgMinWeight> gives coordinate where weight assumes its maximal value. Works in pass 1, %operator+=() supported (merging supported).
+    Usually used as <tt>Coord<Range></tt> (alias <tt>BoundingBox</tt>).
+    Note that <tt>Range</tt> returns a closed interval, i.e. the upper
+    limit is part of the range.
 */
-class ArgMaxWeight
+class Range
 {
   public:
-    typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
-        return "ArgMaxWeight";
+    typedef Select<Minimum, Maximum> Dependencies;
+
+    static std::string name()
+    {
+        return "Range";
+        // static const std::string n("Range");
+        // return n;
+    }
+
+    template <class U, class BASE>
+    struct Impl
+    : public BASE
+    {
+        typedef typename AccumulatorResultTraits<U>::MinmaxType   minmax_type;
+        typedef std::pair<minmax_type, minmax_type>               value_type;
+        typedef value_type                                        result_type;
+
+        result_type operator()() const
+        {
+            return value_type(getDependency<Minimum>(*this), getDependency<Maximum>(*this));
+        }
+    };
+};
+
+/** \brief Basic statistic. Data value where weight assumes its minimal value.
+
+    Weights must be given. Coord<ArgMinWeight> gives coordinate where weight assumes its minimal value. Works in pass 1, %operator+=() supported (merging supported).
+*/
+class ArgMinWeight
+{
+  public:
+    typedef Select<> Dependencies;
+
+    static std::string name()
+    {
+        return "ArgMinWeight";
+        // static const std::string n("ArgMinWeight");
+        // return n;
+    }
+
+    template <class U, class BASE>
+    struct Impl
+    : public BASE
+    {
+        typedef typename AccumulatorResultTraits<U>::element_type element_type;
+        typedef typename AccumulatorResultTraits<U>::MinmaxType   value_type;
+        typedef value_type const &                                result_type;
+
+        double min_weight_;
+        value_type value_;
+
+        Impl()
+        : min_weight_(NumericTraits<double>::max()),
+          value_()
+        {}
+
+        void reset()
+        {
+            min_weight_ = NumericTraits<double>::max();
+            value_ = element_type();
+        }
+
+        template <class Shape>
+        void reshape(Shape const & s)
+        {
+            acc_detail::reshapeImpl(value_, s);
+        }
+
+        void operator+=(Impl const & o)
+        {
+            using namespace multi_math;
+            if(o.min_weight_ < min_weight_)
+            {
+                min_weight_ = o.min_weight_;
+                value_ = o.value_;
+            }
+        }
+
+        void update(U const & t)
+        {
+            vigra_precondition(false, "ArgMinWeight::update() needs weights.");
+        }
+
+        void update(U const & t, double weight)
+        {
+            if(weight < min_weight_)
+            {
+                min_weight_ = weight;
+                value_ = t;
+            }
+        }
+
+        result_type operator()() const
+        {
+            return value_;
+        }
+    };
+};
+
+/** \brief Basic statistic. Data where weight assumes its maximal value.
+
+    Weights must be given. Coord<ArgMinWeight> gives coordinate where weight assumes its maximal value. Works in pass 1, %operator+=() supported (merging supported).
+*/
+class ArgMaxWeight
+{
+  public:
+    typedef Select<> Dependencies;
+
+    static std::string name()
+    {
+        return "ArgMaxWeight";
         // static const std::string n("ArgMaxWeight");
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public BASE
@@ -5235,24 +5472,24 @@ class ArgMaxWeight
 
         double max_weight_;
         value_type value_;
-        
+
         Impl()
         : max_weight_(NumericTraits<double>::min()),
           value_()
         {}
-        
+
         void reset()
         {
             max_weight_ = NumericTraits<double>::min();
             value_ = element_type();
         }
-    
+
         template <class Shape>
         void reshape(Shape const & s)
         {
             acc_detail::reshapeImpl(value_, s);
         }
-        
+
         void operator+=(Impl const & o)
         {
             using namespace multi_math;
@@ -5262,12 +5499,12 @@ class ArgMaxWeight
                 value_ = o.value_;
             }
         }
-    
+
         void update(U const & t)
         {
             vigra_precondition(false, "ArgMaxWeight::update() needs weights.");
         }
-        
+
         void update(U const & t, double weight)
         {
             if(weight > max_weight_)
@@ -5276,7 +5513,7 @@ class ArgMaxWeight
                 value_ = t;
             }
         }
-        
+
         result_type operator()() const
         {
             return value_;
@@ -5290,20 +5527,20 @@ class HistogramBase
 : public BASE
 {
   public:
-  
+
     typedef double                        element_type;
     typedef TinyVector<double, BinCount>  value_type;
     typedef value_type const &            result_type;
-    
+
     value_type value_;
     double left_outliers, right_outliers;
-    
+
     HistogramBase()
     : value_(),
-      left_outliers(), 
+      left_outliers(),
       right_outliers()
     {}
-    
+
     void reset()
     {
         value_ = element_type();
@@ -5317,7 +5554,7 @@ class HistogramBase
         left_outliers += o.left_outliers;
         right_outliers += o.right_outliers;
     }
-        
+
     result_type operator()() const
     {
         return value_;
@@ -5329,27 +5566,27 @@ class HistogramBase<BASE, 0>
 : public BASE
 {
   public:
-  
+
     typedef double                        element_type;
     typedef MultiArray<1, double>         value_type;
     typedef value_type const &            result_type;
-    
+
     value_type value_;
     double left_outliers, right_outliers;
-    
+
     HistogramBase()
     : value_(),
-      left_outliers(), 
+      left_outliers(),
       right_outliers()
     {}
-    
+
     void reset()
     {
         value_ = element_type();
         left_outliers = 0.0;
         right_outliers = 0.0;
     }
-    
+
     void operator+=(HistogramBase const & o)
     {
         if(value_.size() == 0)
@@ -5365,7 +5602,7 @@ class HistogramBase<BASE, 0>
         left_outliers += o.left_outliers;
         right_outliers += o.right_outliers;
     }
-        
+
     void setBinCount(int binCount)
     {
         vigra_precondition(binCount > 0,
@@ -5385,13 +5622,13 @@ class RangeHistogramBase
 {
   public:
     double scale_, offset_, inverse_scale_;
-    
+
     RangeHistogramBase()
     : scale_(),
-      offset_(), 
+      offset_(),
       inverse_scale_()
     {}
-    
+
     void reset()
     {
         scale_ = 0.0;
@@ -5404,7 +5641,7 @@ class RangeHistogramBase
     {
         vigra_precondition(scale_ == 0.0 || o.scale_ == 0.0 || (scale_ == o.scale_ && offset_ == o.offset_),
             "RangeHistogramBase::operator+=(): cannot merge histograms with different data mapping.");
-        
+
         HistogramBase<BASE, BinCount>::operator+=(o);
         if(scale_ == 0.0)
         {
@@ -5418,7 +5655,7 @@ class RangeHistogramBase
     {
         update(t, 1.0);
     }
-    
+
     void update(U const & t, double weight)
     {
         double m = mapItem(t);
@@ -5432,49 +5669,51 @@ class RangeHistogramBase
         else
             this->value_[index] += weight;
     }
-    
+
     void setMinMax(double mi, double ma)
     {
         vigra_precondition(this->value_.size() > 0,
             "RangeHistogramBase::setMinMax(...): setBinCount(...) has not been called.");
-        vigra_precondition(mi < ma,
-            "RangeHistogramBase::setMinMax(...): min < max required.");
+        vigra_precondition(mi <= ma,
+            "RangeHistogramBase::setMinMax(...): min <= max required.");
+        if(mi == ma)
+            ma += this->value_.size() * NumericTraits<double>::epsilon();
         offset_ = mi;
         scale_ = (double)this->value_.size() / (ma - mi);
         inverse_scale_ = 1.0 / scale_;
     }
-    
+
     double mapItem(double t) const
     {
         return scale_ * (t - offset_);
     }
-    
+
     double mapItemInverse(double t) const
     {
         return inverse_scale_ * t + offset_;
     }
-    
+
     template <class ArrayLike>
-    void computeStandardQuantiles(double minimum, double maximum, double count, 
+    void computeStandardQuantiles(double minimum, double maximum, double count,
                                   ArrayLike const & desiredQuantiles, ArrayLike & res) const
     {
         if(count == 0.0) {
             return;
         }
-        
+
         ArrayVector<double> keypoints, cumhist;
         double mappedMinimum = mapItem(minimum);
         double mappedMaximum = mapItem(maximum);
-        
+
         keypoints.push_back(mappedMinimum);
         cumhist.push_back(0.0);
-        
+
         if(this->left_outliers > 0.0)
         {
             keypoints.push_back(0.0);
             cumhist.push_back(this->left_outliers);
         }
-        
+
         int size = (int)this->value_.size();
         double cumulative = this->left_outliers;
         for(int k=0; k<size; ++k)
@@ -5491,7 +5730,7 @@ class RangeHistogramBase
                 cumhist.push_back(cumulative);
             }
         }
-        
+
         if(this->right_outliers > 0.0)
         {
             if(keypoints.back() != size)
@@ -5507,9 +5746,9 @@ class RangeHistogramBase
             keypoints.back() = mappedMaximum;
             cumhist.back() = count;
         }
-        
+
         int quantile = 0, end = (int)desiredQuantiles.size();
-        
+
         if(desiredQuantiles[0] == 0.0)
         {
             res[0] = minimum;
@@ -5520,7 +5759,7 @@ class RangeHistogramBase
             res[end-1] = maximum;
             --end;
         }
-        
+
         int point = 0;
         double qcount = count * desiredQuantiles[quantile];
         while(quantile < end)
@@ -5543,7 +5782,7 @@ class RangeHistogramBase
 /** \brief Histogram where data values are equal to bin indices.
 
     - If BinCount != 0, the return type of the accumulator is TinyVector<double, BinCount> .
-    - If BinCount == 0, the return type of the accumulator is MultiArray<1, double> . BinCount can be set by calling getAccumulator<IntegerHistogram<0> >(acc_chain).setBinCount(bincount).  
+    - If BinCount == 0, the return type of the accumulator is MultiArray<1, double> . BinCount can be set by calling getAccumulator<IntegerHistogram<0> >(acc_chain).setBinCount(bincount).
     - Outliers can be accessed via getAccumulator<IntegerHistogram<Bincount>>(a).left_outliers and getAccumulator<...>(acc_chain).right_outliers.
     - Note that histogram options (for all histograms in the accumulator chain) can also be set by passing an instance of HistogramOptions to the accumulator chain via acc_chain.setHistogramOptions().
     Works in pass 1, %operator+=() supported (merging supported).
@@ -5552,16 +5791,16 @@ template <int BinCount>
 class IntegerHistogram
 {
   public:
-    
+
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("IntegerHistogram<") + asString(BinCount) + ">";
         // static const std::string n = std::string("IntegerHistogram<") + asString(BinCount) + ">";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public HistogramBase<BASE, BinCount>
@@ -5575,20 +5814,20 @@ class IntegerHistogram
             else
                 ++this->value_[index];
         }
-        
+
         void update(int index, double weight)
         {
             // cannot compute quantile from weighted integer histograms,
             // so force people to use UserRangeHistogram or AutoRangeHistogram
             vigra_precondition(false, "IntegerHistogram::update(): weighted histograms not supported, use another histogram type.");
         }
-    
+
         template <class ArrayLike>
-        void computeStandardQuantiles(double minimum, double maximum, double count, 
+        void computeStandardQuantiles(double minimum, double maximum, double count,
                                       ArrayLike const & desiredQuantiles, ArrayLike & res) const
         {
             int quantile = 0, end = (int)desiredQuantiles.size();
-            
+
             if(desiredQuantiles[0] == 0.0)
             {
                 res[0] = minimum;
@@ -5599,16 +5838,16 @@ class IntegerHistogram
                 res[end-1] = maximum;
                 --end;
             }
-            
+
             count -= 1.0;
             int currentBin = 0, size = (int)this->value_.size();
             double cumulative1 = this->left_outliers,
                    cumulative2 = this->value_[currentBin] + cumulative1;
-            
+
             // add a to the quantiles to account for the fact that counting
             // corresponds to 1-based indexing (one element == index 1)
             double qcount = desiredQuantiles[quantile]*count + 1.0;
-            
+
             while(quantile < end)
             {
                 if(cumulative2 == qcount)
@@ -5665,16 +5904,16 @@ template <int BinCount>
 class UserRangeHistogram
 {
   public:
-    
+
     typedef Select<> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("UserRangeHistogram<") + asString(BinCount) + ">";
         // static const std::string n = std::string("UserRangeHistogram<") + asString(BinCount) + ">";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public RangeHistogramBase<BASE, BinCount, U>
@@ -5683,12 +5922,12 @@ class UserRangeHistogram
         {
             update(t, 1.0);
         }
-        
+
         void update(U const & t, double weight)
         {
             vigra_precondition(this->scale_ != 0.0,
                 "UserRangeHistogram::update(): setMinMax(...) has not been called.");
-                
+
             RangeHistogramBase<BASE, BinCount, U>::update(t, weight);
         }
     };
@@ -5707,32 +5946,32 @@ template <int BinCount>
 class AutoRangeHistogram
 {
   public:
-    
+
     typedef Select<Minimum, Maximum> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("AutoRangeHistogram<") + asString(BinCount) + ">";
         // static const std::string n = std::string("AutoRangeHistogram<") + asString(BinCount) + ">";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public RangeHistogramBase<BASE, BinCount, U>
     {
         static const unsigned int workInPass = LookupDependency<Minimum, BASE>::type::workInPass + 1;
-        
+
         void update(U const & t)
         {
             update(t, 1.0);
         }
-        
+
         void update(U const & t, double weight)
         {
             if(this->scale_ == 0.0)
                 this->setMinMax(getDependency<Minimum>(*this), getDependency<Maximum>(*this));
-                
+
             RangeHistogramBase<BASE, BinCount, U>::update(t, weight);
         }
     };
@@ -5751,39 +5990,39 @@ template <int BinCount>
 class GlobalRangeHistogram
 {
   public:
-    
+
     typedef Select<Global<Minimum>, Global<Maximum>, Minimum, Maximum> Dependencies;
-    
-    static std::string name() 
-    { 
+
+    static std::string name()
+    {
         return std::string("GlobalRangeHistogram<") + asString(BinCount) + ">";
         // static const std::string n = std::string("GlobalRangeHistogram<") + asString(BinCount) + ">";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public RangeHistogramBase<BASE, BinCount, U>
     {
         static const unsigned int workInPass = LookupDependency<Minimum, BASE>::type::workInPass + 1;
-        
+
         bool useLocalMinimax_;
-        
+
         Impl()
         : useLocalMinimax_(false)
         {}
-        
+
         void setRegionAutoInit(bool locally)
         {
             this->scale_ = 0.0;
             useLocalMinimax_ = locally;
         }
-        
+
         void update(U const & t)
         {
             update(t, 1.0);
         }
-        
+
         void update(U const & t, double weight)
         {
             if(this->scale_ == 0.0)
@@ -5793,7 +6032,7 @@ class GlobalRangeHistogram
                 else
                     this->setMinMax(getDependency<Global<Minimum> >(*this), getDependency<Global<Maximum> >(*this));
             }
-            
+
             RangeHistogramBase<BASE, BinCount, U>::update(t, weight);
         }
     };
@@ -5801,39 +6040,39 @@ class GlobalRangeHistogram
 
 /** \brief Compute (0%, 10%, 25%, 50%, 75%, 90%, 100%) quantiles from given histogram.
 
-    Return type is TinyVector<double, 7> . 
+    Return type is TinyVector<double, 7> .
 */
-template <class HistogramAccumulator> 
+template <class HistogramAccumulator>
 class StandardQuantiles
 {
   public:
-    
+
     typedef typename StandardizeTag<HistogramAccumulator>::type HistogramTag;
     typedef Select<HistogramTag, Minimum, Maximum, Count> Dependencies;
 
-    static std::string name() 
-    { 
+    static std::string name()
+    {
         return std::string("StandardQuantiles<") + HistogramTag::name() + " >";
         // static const std::string n = std::string("StandardQuantiles<") + HistogramTag::name() + " >";
         // return n;
     }
-    
+
     template <class U, class BASE>
     struct Impl
     : public CachedResultBase<BASE, TinyVector<double, 7>, U>
     {
         typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>::result_type result_type;
         typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>::value_type  value_type;
-        
+
         static const unsigned int workInPass = LookupDependency<HistogramTag, BASE>::type::workInPass;
-        
+
         result_type operator()() const
         {
             if(this->isDirty())
             {
                 double desiredQuantiles[] = {0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 1.0 };
-                getAccumulator<HistogramTag>(*this).computeStandardQuantiles(getDependency<Minimum>(*this), getDependency<Maximum>(*this), 
-                                                                             getDependency<Count>(*this), value_type(desiredQuantiles), 
+                getAccumulator<HistogramTag>(*this).computeStandardQuantiles(getDependency<Minimum>(*this), getDependency<Maximum>(*this),
+                                                                             getDependency<Count>(*this), value_type(desiredQuantiles),
                                                                              this->value_);
                 this->setClean();
             }
@@ -5842,6 +6081,507 @@ class StandardQuantiles
     };
 };
 
+template <int N>
+struct feature_RegionContour_can_only_be_computed_for_2D_arrays
+: vigra::staticAssert::AssertBool<N==2>
+{};
+
+/** \brief Compute the contour of a 2D region.
+
+    AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
+ */
+class RegionContour
+{
+  public:
+    typedef Select<Count> Dependencies;
+
+    static std::string name()
+    {
+        return std::string("RegionContour");
+        // static const std::string n = std::string("RegionContour");
+        // return n;
+    }
+
+    template <class T, class BASE>
+    struct Impl
+    : public BASE
+    {
+        typedef HandleArgSelector<T, LabelArgTag, BASE>               LabelHandle;
+        typedef TinyVector<double, 2>                                 point_type;
+        typedef Polygon<point_type>                                   value_type;
+        typedef value_type const &                                    result_type;
+
+        point_type offset_;
+        value_type contour_;
+
+        Impl()
+        : offset_()
+        , contour_()
+        {}
+
+        void setCoordinateOffset(point_type const & offset)
+        {
+            offset_ = offset;
+        }
+
+        template <class U, class NEXT>
+        void update(CoupledHandle<U, NEXT> const & t)
+        {
+            VIGRA_STATIC_ASSERT((feature_RegionContour_can_only_be_computed_for_2D_arrays<
+                                 CoupledHandle<U, NEXT>::dimensions>));
+            if(getDependency<Count>(*this) == 1)
+            {
+                contour_.clear();
+                extractContour(LabelHandle::getHandle(t).arrayView(), t.point(), contour_);
+                contour_ += offset_;
+            }
+        }
+
+        template <class U, class NEXT>
+        void update(CoupledHandle<U, NEXT> const & t, double weight)
+        {
+            update(t);
+        }
+
+        void operator+=(Impl const & o)
+        {
+            vigra_precondition(false,
+                "RegionContour::operator+=(): RegionContour cannot be merged.");
+        }
+
+        result_type operator()() const
+        {
+            return contour_;
+        }
+    };
+};
+
+
+/** \brief Compute the perimeter of a 2D region.
+
+    This is the length of the polygon returned by RegionContour.
+
+    AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
+ */
+class RegionPerimeter
+{
+  public:
+    typedef Select<RegionContour> Dependencies;
+
+    static std::string name()
+    {
+        return std::string("RegionPerimeter");
+        // static const std::string n = std::string("RegionPerimeter");
+        // return n;
+    }
+
+    template <class T, class BASE>
+    struct Impl
+    : public BASE
+    {
+        typedef double       value_type;
+        typedef value_type   result_type;
+
+        result_type operator()() const
+        {
+            return getDependency<RegionContour>(*this).length();
+        }
+    };
+};
+
+/** \brief Compute the circularity of a 2D region.
+
+    The is the ratio between the perimeter of a circle with the same area as the
+    present region and the perimeter of the region, i.e. \f[c = \frac{2 \sqrt{\pi a}}{p} \f], where a and p are the area and length of the polygon returned by RegionContour.
+
+    AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
+ */
+class RegionCircularity
+{
+  public:
+    typedef Select<Count, RegionContour> Dependencies;
+
+    static std::string name()
+    {
+        return std::string("RegionCircularity");
+        // static const std::string n = std::string("RegionCircularity");
+        // return n;
+    }
+
+    template <class T, class BASE>
+    struct Impl
+    : public BASE
+    {
+        typedef double       value_type;
+        typedef value_type   result_type;
+
+        result_type operator()() const
+        {
+            return 2.0*sqrt(M_PI*getDependency<RegionContour>(*this).area()) / getDependency<RegionContour>(*this).length();
+        }
+    };
+};
+
+/** \brief Compute the eccentricity of a 2D region in terms of its prinipal radii.
+
+    Formula: \f[ e = \sqrt{1 - m^2 / M^2 } \f], where m and M are the minor and major principal radius.
+
+    AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
+ */
+class RegionEccentricity
+{
+  public:
+    typedef Select<RegionRadii> Dependencies;
+
+    static std::string name()
+    {
+        return std::string("RegionEccentricity");
+        // static const std::string n = std::string("RegionEccentricity");
+        // return n;
+    }
+
+    template <class T, class BASE>
+    struct Impl
+    : public BASE
+    {
+        typedef double       value_type;
+        typedef value_type   result_type;
+
+        result_type operator()() const
+        {
+            double M = getDependency<RegionRadii>(*this).front(),
+                   m = getDependency<RegionRadii>(*this).back();
+            return sqrt(1.0 - sq(m/M));
+        }
+    };
+};
+
+template <int N>
+struct feature_ConvexHull_can_only_be_computed_for_2D_arrays
+: vigra::staticAssert::AssertBool<N==2>
+{};
+
+/** \brief Compute the contour of a 2D region.
+
+    AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
+ */
+class ConvexHull
+{
+  public:
+    typedef Select<BoundingBox, RegionContour, RegionCenter> Dependencies;
+
+    static std::string name()
+    {
+        return std::string("ConvexHull");
+        // static const std::string n = std::string("ConvexHull");
+        // return n;
+    }
+
+    template <class T, class BASE>
+    struct Impl
+    : public BASE
+    {
+        static const unsigned int            workInPass = 2;
+
+        typedef HandleArgSelector<T, LabelArgTag, BASE>               LabelHandle;
+        typedef TinyVector<double, 2>                                 point_type;
+        typedef Polygon<point_type>                                   polygon_type;
+        typedef Impl                                                  value_type;
+        typedef value_type const &                                    result_type;
+
+        polygon_type convex_hull_;
+        point_type input_center_, convex_hull_center_, defect_center_;
+        double convexity_, rugosity_, mean_defect_displacement_,
+               defect_area_mean_, defect_area_variance_, defect_area_skewness_, defect_area_kurtosis_;
+        int convexity_defect_count_;
+        ArrayVector<MultiArrayIndex> convexity_defect_area_;
+        bool features_computed_;
+
+        Impl()
+        : convex_hull_()
+        , input_center_()
+        , convex_hull_center_()
+        , defect_center_()
+        , convexity_()
+        , rugosity_()
+        , mean_defect_displacement_()
+        , defect_area_mean_()
+        , defect_area_variance_()
+        , defect_area_skewness_()
+        , defect_area_kurtosis_()
+        , convexity_defect_count_()
+        , convexity_defect_area_()
+        , features_computed_(false)
+        {}
+
+        template <class U, class NEXT>
+        void update(CoupledHandle<U, NEXT> const & t)
+        {
+            VIGRA_STATIC_ASSERT((feature_ConvexHull_can_only_be_computed_for_2D_arrays<
+                                  CoupledHandle<U, NEXT>::dimensions>));
+            if(!features_computed_)
+            {
+                using namespace functor;
+                Shape2 start = getDependency<Coord<Minimum> >(*this),
+                       stop  = getDependency<Coord<Maximum> >(*this) + Shape2(1);
+                point_type offset(start);
+                input_center_ = getDependency<RegionCenter>(*this);
+                MultiArrayIndex label = LabelHandle::getValue(t);
+
+                convex_hull_.clear();
+                convexHull(getDependency<RegionContour>(*this), convex_hull_);
+                convex_hull_center_ = centroid(convex_hull_);
+
+                convexity_ = getDependency<RegionContour>(*this).area() / convex_hull_.area();
+                rugosity_ = getDependency<RegionContour>(*this).length() / convex_hull_.length();
+
+                MultiArray<2, UInt8> convex_hull_difference(stop-start);
+                fillPolygon(convex_hull_ - offset, convex_hull_difference, 1);
+                combineTwoMultiArrays(convex_hull_difference,
+                                      LabelHandle::getHandle(t).arrayView().subarray(start, stop),
+                                      convex_hull_difference,
+                                      ifThenElse(Arg2() == Param(label), Param(0), Arg1()));
+
+                MultiArray<2, UInt32> convexity_defects(stop-start);
+                convexity_defect_count_ =
+                   labelImageWithBackground(convex_hull_difference, convexity_defects, false, 0);
+
+                if (convexity_defect_count_ != 0)
+                {
+                    AccumulatorChainArray<CoupledArrays<2, UInt32>,
+                                          Select<LabelArg<1>, Count, RegionCenter> > convexity_defects_stats;
+                    convexity_defects_stats.ignoreLabel(0);
+                    extractFeatures(convexity_defects, convexity_defects_stats);
+
+                    double total_defect_area = 0.0;
+                    mean_defect_displacement_ = 0.0;
+                    defect_center_ = point_type();
+                    for (int k = 1; k <= convexity_defect_count_; ++k)
+                    {
+                        double area = get<Count>(convexity_defects_stats, k);
+                        point_type center = get<RegionCenter>(convexity_defects_stats, k) + offset;
+
+                        convexity_defect_area_.push_back(area);
+                        total_defect_area += area;
+                        defect_center_ += area*center;
+                        mean_defect_displacement_ += area*norm(input_center_ - center);
+                    }
+                    sort(convexity_defect_area_.begin(), convexity_defect_area_.end(),
+                         std::greater<MultiArrayIndex>());
+                    mean_defect_displacement_ /= total_defect_area;
+                    defect_center_ /= total_defect_area;
+
+                    AccumulatorChain<MultiArrayIndex,
+                                     Select<Mean, UnbiasedVariance, UnbiasedSkewness, UnbiasedKurtosis> > defect_area_stats;
+                    extractFeatures(convexity_defect_area_.begin(),
+                                    convexity_defect_area_.end(), defect_area_stats);
+
+                    defect_area_mean_ = convexity_defect_count_ > 0
+                        ? get<Mean>(defect_area_stats)
+                        : 0.0;
+                    defect_area_variance_ = convexity_defect_count_ > 1
+                        ? get<UnbiasedVariance>(defect_area_stats)
+                        : 0.0;
+                    defect_area_skewness_ = convexity_defect_count_ > 2
+                        ? get<UnbiasedSkewness>(defect_area_stats)
+                        : 0.0;
+                    defect_area_kurtosis_ = convexity_defect_count_ > 3
+                        ? get<UnbiasedKurtosis>(defect_area_stats)
+                        : 0.0;
+                }
+                /**********************************************/
+                features_computed_ = true;
+            }
+        }
+
+        template <class U, class NEXT>
+        void update(CoupledHandle<U, NEXT> const & t, double weight)
+        {
+            update(t);
+        }
+
+        void operator+=(Impl const & o)
+        {
+            vigra_precondition(false,
+                "ConvexHull::operator+=(): ConvexHull features cannot be merged.");
+        }
+
+        result_type operator()() const
+        {
+            return *this;
+        }
+
+        /*
+         * Returns the convex hull polygon.
+         */
+        polygon_type const & hull() const
+        {
+            return convex_hull_;
+        }
+
+        /*
+         * Returns the area enclosed by the input polygon.
+         */
+        double inputArea() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return getDependency<RegionContour>(*this).area();
+        }
+
+        /*
+         * Returns the area enclosed by the convex hull polygon.
+         */
+        double hullArea() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return convex_hull_.area();
+        }
+
+        /*
+         * Returns the perimeter of the input polygon.
+         */
+        double inputPerimeter() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return getDependency<RegionContour>(*this).length();
+        }
+
+        /*
+         * Returns the perimeter of the convex hull polygon.
+         */
+        double hullPerimeter() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return convex_hull_.length();
+        }
+
+        /*
+         * Center of the original region.
+         */
+        point_type const & inputCenter() const
+        {
+            return input_center_;
+        }
+
+        /*
+         * Center of the region enclosed by the convex hull.
+         */
+        point_type const & hullCenter() const
+        {
+            return convex_hull_center_;
+        }
+
+        /*
+         * Center of difference between the convex hull and the original region.
+         */
+        point_type const & convexityDefectCenter() const
+        {
+            return defect_center_;
+        }
+
+        /*
+         * Returns the ratio between the input area and the convex hull area.
+         * This is always <tt><= 1</tt>, and the smaller the value is,
+         * the less convex is the input polygon.
+         */
+        double convexity() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return convexity_;
+        }
+
+        /*
+         * Returns the ratio between the input perimeter and the convex perimeter.
+         * This is always <tt>>= 1</tt>, and the higher the value is, the less
+         * convex is the input polygon.
+         */
+        double rugosity() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return rugosity_;
+        }
+
+        /*
+         * Returns the number of convexity defects (i.e. number of connected components
+         * of the difference between convex hull and input region).
+         */
+        int convexityDefectCount() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return convexity_defect_count_;
+        }
+
+        /*
+         * Returns the mean area of the convexity defects.
+         */
+        double convexityDefectAreaMean() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return defect_area_mean_;
+        }
+
+        /*
+         * Returns the variance of the convexity defect areas.
+         */
+        double convexityDefectAreaVariance() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return defect_area_variance_;
+        }
+
+        /*
+         * Returns the skewness of the convexity defect areas.
+         */
+        double convexityDefectAreaSkewness() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return defect_area_skewness_;
+        }
+
+        /*
+         * Returns the kurtosis of the convexity defect areas.
+         */
+        double convexityDefectAreaKurtosis() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return defect_area_kurtosis_;
+        }
+
+        /*
+         * Returns the mean distance between the defect areas and the center of
+         * the input region, weighted by the area of each defect region.
+         */
+        double meanDefectDisplacement() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return mean_defect_displacement_;
+        }
+
+        /*
+         * Returns the areas of the convexity defect regions (ordered descending).
+         */
+        ArrayVector<MultiArrayIndex> const & defectAreaList() const
+        {
+            vigra_precondition(features_computed_,
+                    "ConvexHull: features must be calculated first.");
+            return convexity_defect_area_;
+        }
+    };
+};
+
+
 }} // namespace vigra::acc
 
 #endif // VIGRA_ACCUMULATOR_HXX
diff --git a/include/vigra/adjacency_list_graph.hxx b/include/vigra/adjacency_list_graph.hxx
new file mode 100644
index 0000000..369aaf7
--- /dev/null
+++ b/include/vigra/adjacency_list_graph.hxx
@@ -0,0 +1,1165 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2011 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+
+#ifndef VIGRA_ADJACENCY_LIST_GRAPH_HXX
+#define VIGRA_ADJACENCY_LIST_GRAPH_HXX
+
+/*std*/
+#include <vector>
+#include  <set>
+
+/*vigra*/
+#include "multi_array.hxx"
+#include "multi_gridgraph.hxx"
+#include "graphs.hxx"
+#include "tinyvector.hxx"
+#include "random_access_set.hxx"
+#include "graph_maps.hxx"
+#include "iteratorfacade.hxx"
+
+#include "algorithm.hxx"
+#include "graph_item_impl.hxx"
+
+
+namespace vigra{
+
+/** \addtogroup GraphDataStructures
+*/
+//@{
+
+    namespace detail_adjacency_list_graph{
+
+        template<class G,class ITEM>
+        class ItemIter
+         : public ForwardIteratorFacade<
+            ItemIter<G,ITEM>,ITEM,true
+        >
+        {
+
+            typedef vigra::GraphItemHelper<G,ITEM> ItemHelper;
+            typedef typename G::index_type index_type;
+
+        public:
+            ItemIter(const lemon::Invalid & iv = lemon::INVALID)
+            :   graph_(NULL),
+                id_(-1),
+                item_(lemon::INVALID)
+            {
+            }
+
+            ItemIter(const G & g)
+            :   graph_(&g),
+                id_(0),
+                item_(ItemHelper::itemFromId(*graph_,id_))
+            {
+                while( !isEnd()  &&  item_==lemon::INVALID ){
+                    ++id_;
+                    item_ = ItemHelper::itemFromId(*graph_,id_);
+                }
+            }
+
+            ItemIter(const G & g,const ITEM & item)
+            :   graph_(&g),
+                id_(g.id(item)),
+                item_(item)
+            {
+
+            }
+
+        private:
+
+            friend class vigra::IteratorFacadeCoreAccess;
+            bool isEnd( )const{
+                return graph_==NULL ||  ItemHelper::itemNum(*graph_)==0 || id_>ItemHelper::maxItemId(*graph_);
+            }
+            bool isBegin( )const{
+                return graph_!=NULL &&  id_ == 0 ;
+            }
+
+            bool equal(const ItemIter & other) const{
+                return   (isEnd() && other.isEnd() ) || (isEnd()==other.isEnd() && (id_ == other.id_) );
+            }
+
+            void increment(){
+                ++id_;
+                item_ = ItemHelper::itemFromId(*graph_,id_);
+                while( !isEnd()  &&  item_==lemon::INVALID ){
+                    ++id_;
+                    item_ = ItemHelper::itemFromId(*graph_,id_);
+                }
+            }
+            const ITEM & dereference()const{
+                return item_;
+            }
+            const G * graph_;
+            index_type id_;
+            ITEM item_;
+        };
+
+
+
+        template<class GRAPH>
+        class ArcIt
+        : public ForwardIteratorFacade<
+            ArcIt<GRAPH>,
+            typename GRAPH::Arc,true
+        >
+        {
+        public:
+            typedef GRAPH Graph;
+            typedef typename  Graph::Arc Arc;
+            typedef typename  Graph::Edge Edge;
+            typedef typename  Graph::EdgeIt EdgeIt;
+            ArcIt(const lemon::Invalid invalid = lemon::INVALID )
+            :   graph_(NULL),
+                pos_(),
+                inFirstHalf_(false),
+                veryEnd_(true),
+                arc_(){
+            }
+            ArcIt(const GRAPH & g )
+            :   graph_(&g),
+                pos_(g),
+                inFirstHalf_(true),
+                veryEnd_( g.edgeNum()==0 ? true : false),
+                arc_(){
+            }
+
+            ArcIt(const GRAPH & g , const Arc & arc )
+            :   graph_(&g),
+                pos_(g,arc.edgeId()),
+                inFirstHalf_(g.id(arc)<=g.maxEdgeId()),
+                veryEnd_(false),
+                arc_(){
+            }
+        private:
+            friend class vigra::IteratorFacadeCoreAccess;
+            bool isEnd()const{
+                return veryEnd_ || graph_==NULL;
+            }
+
+            bool isBegin()const{
+                return graph_!=NULL &&  veryEnd_==false && pos_ == EdgeIt(*graph_);         
+            }
+            void increment() {
+                if(inFirstHalf_){
+                    ++pos_;
+                    if(pos_ == lemon::INVALID  ) {
+                        pos_ = EdgeIt(*graph_);
+                        inFirstHalf_=false;
+                    }
+                    return;
+                }
+                else{
+                    ++pos_;
+                    if(pos_ == lemon::INVALID){
+                        veryEnd_=true;
+                    }
+                    return;
+                }
+            
+               
+            }
+            bool equal(ArcIt const& other) const{
+                return (
+                    (
+                        isEnd()==other.isEnd()                  &&
+                        inFirstHalf_==other.inFirstHalf_ 
+                    ) &&
+                    (isEnd() || graph_==NULL || pos_==other.pos_ )
+                    );
+                    
+            }
+
+            const Arc & dereference() const { 
+                //std::cout<<graph_->id(*pos_)<<"\n";
+                arc_ = graph_->direct(*pos_,inFirstHalf_);
+                return arc_;
+            }
+
+
+            const GRAPH * graph_;
+            EdgeIt pos_;
+            bool inFirstHalf_;
+            bool veryEnd_;
+            mutable Arc arc_;
+        };
+
+    } // namespace detail_adjacency_list_graph
+
+
+    /** \brief undirected adjacency list graph in the LEMON API 
+
+    */
+    class AdjacencyListGraph
+    {
+        
+    public:
+        // public typdedfs
+        typedef Int64                                                     index_type;
+    private:
+        // private typedes which are needed for defining public typedes
+        typedef AdjacencyListGraph                                          GraphType;
+        typedef detail::GenericNodeImpl<index_type,false>                   NodeStorage;
+        typedef detail::GenericEdgeImpl<index_type >                        EdgeStorage;
+        typedef detail::NeighborNodeFilter<GraphType>                       NnFilter;
+        typedef detail::IncEdgeFilter<GraphType>                            IncFilter;
+        typedef detail::IsInFilter<GraphType>                               InFlter;
+        typedef detail::IsOutFilter<GraphType>                              OutFilter;
+        typedef detail::IsBackOutFilter<GraphType>                          BackOutFilter;
+    public:
+        // LEMON API TYPEDEFS (and a few more(NeighborNodeIt))
+
+        /// node descriptor
+        typedef detail::GenericNode<index_type>                           Node;
+        /// edge descriptor
+        typedef detail::GenericEdge<index_type>                           Edge;
+        /// arc descriptor
+        typedef detail::GenericArc<index_type>                            Arc;
+        /// edge iterator
+        typedef detail_adjacency_list_graph::ItemIter<GraphType,Edge>    EdgeIt;
+        /// node iterator
+        typedef detail_adjacency_list_graph::ItemIter<GraphType,Node>    NodeIt; 
+        /// arc iterator
+        typedef detail_adjacency_list_graph::ArcIt<GraphType>            ArcIt;
+        
+        /// incident edge iterator
+        typedef detail::GenericIncEdgeIt<GraphType,NodeStorage,IncFilter >  IncEdgeIt;
+        /// incoming arc iterator
+        typedef detail::GenericIncEdgeIt<GraphType,NodeStorage,InFlter   >  InArcIt;
+        /// outgoing arc iterator
+        typedef detail::GenericIncEdgeIt<GraphType,NodeStorage,OutFilter >  OutArcIt;
+
+        typedef detail::GenericIncEdgeIt<GraphType,NodeStorage,NnFilter  >  NeighborNodeIt;
+
+
+        /// outgoing back arc iterator
+        typedef detail::GenericIncEdgeIt<GraphType,NodeStorage,BackOutFilter >  OutBackArcIt;
+
+
+        // BOOST GRAPH API TYPEDEFS
+        // - categories (not complete yet)
+        typedef directed_tag            directed_category;
+        // iterators
+        typedef NeighborNodeIt          adjacency_iterator;
+        typedef EdgeIt                  edge_iterator;
+        typedef NodeIt                  vertex_iterator;
+        typedef IncEdgeIt               in_edge_iterator;
+        typedef IncEdgeIt               out_edge_iterator;
+
+        // size types
+        typedef size_t                  degree_size_type;
+        typedef size_t                  edge_size_type;
+        typedef size_t                  vertex_size_type;
+        // item descriptors
+        typedef Edge                    edge_descriptor;
+        typedef Node                    vertex_descriptor;
+
+
+        /// default edge map 
+        template<class T>
+        struct EdgeMap : DenseEdgeReferenceMap<GraphType,T> {
+            EdgeMap(): DenseEdgeReferenceMap<GraphType,T>(){
+            }
+            EdgeMap(const GraphType & g)
+            : DenseEdgeReferenceMap<GraphType,T>(g){
+            }
+            EdgeMap(const GraphType & g,const T & val)
+            : DenseEdgeReferenceMap<GraphType,T>(g,val){
+            }
+        };
+
+        /// default node map 
+        template<class T>
+        struct NodeMap : DenseNodeReferenceMap<GraphType,T> {
+            NodeMap(): DenseNodeReferenceMap<GraphType,T>(){
+            }
+            NodeMap(const GraphType & g)
+            : DenseNodeReferenceMap<GraphType,T>(g){
+            }
+            NodeMap(const GraphType & g,const T & val)
+            : DenseNodeReferenceMap<GraphType,T>(g,val){
+            }
+        };
+
+        /// default arc map 
+        template<class T>
+        struct ArcMap : DenseArcReferenceMap<GraphType,T> {
+            ArcMap(): DenseArcReferenceMap<GraphType,T>(){
+            }
+            ArcMap(const GraphType & g)
+            : DenseArcReferenceMap<GraphType,T>(g){
+            }
+            ArcMap(const GraphType & g,const T & val)
+            : DenseArcReferenceMap<GraphType,T>(g,val){
+            }
+        };
+
+
+
+    // public member functions
+    public:
+        /** \brief Constructor.
+         
+            @param nodes : reserve space for so many nodes
+            @param edges : reserve space for so many edges
+        */
+        AdjacencyListGraph(const size_t nodes=0,const size_t edges=0);
+
+        /** \brief Get the number of edges in this graph (API: LEMON).
+        */
+        index_type edgeNum()const;
+
+        /** \brief Get the number of nodes in this graph (API: LEMON).
+        */
+        index_type nodeNum()const;
+        /** \brief Get the number of arcs in this graph (API: LEMON).
+        */
+        index_type arcNum()const;
+
+        /** \brief Get the maximum ID of any edge in this graph (API: LEMON).
+        */
+        index_type maxEdgeId()const;
+        /** \brief Get the maximum ID of any node in this graph (API: LEMON).
+        */
+        index_type maxNodeId()const;
+        /** \brief Get the maximum ID of any edge in arc graph (API: LEMON).
+        */
+        index_type maxArcId()const;
+
+        /** \brief Create an arc for the given edge \a e, oriented along the 
+            edge's natural (<tt>forward = true</tt>) or reversed 
+            (<tt>forward = false</tt>) direction (API: LEMON).
+        */
+        Arc direct(const Edge & edge,const bool forward)const;
+
+        /** \brief Create an arc for the given edge \a e oriented
+            so that node \a n is the starting node of the arc (API: LEMON), or
+            return <tt>lemon::INVALID</tt> if the edge is not incident to this node.
+        */
+        Arc direct(const Edge & edge,const Node & node)const;
+
+        /** \brief Return <tt>true</tt> when the arc is looking on the underlying
+            edge in its natural (i.e. forward) direction, <tt>false</tt> otherwise (API: LEMON).
+        */
+        bool direction(const Arc & arc)const;
+        /** \brief Get the start node of the given edge \a e (API: LEMON,<br/>
+            the boost::graph API provides the free function <tt>boost::source(e, graph)</tt>).
+        */
+        Node u(const Edge & edge)const;
+        /** \brief Get the end node of the given edge \a e (API: LEMON,<br/>
+            the boost::graph API provides the free function <tt>boost::target(e, graph)</tt>).
+        */
+        Node v(const Edge & edge)const;
+        /** \brief Get the start node of the given arc \a a (API: LEMON).
+        */
+        Node source(const Arc & arc)const;
+        /** \brief Get the end node of the given arc \a a (API: LEMON).
+        */
+        Node target(const Arc & arc)const;
+        /** \brief Return the opposite node of the given node \a n
+            along edge \a e (API: LEMON), or return <tt>lemon::INVALID</tt>
+            if the edge is not incident to this node.
+        */
+        Node oppositeNode(Node const &n, const Edge &e) const;
+
+        /** \brief Return the start node of the edge the given iterator is referring to (API: LEMON).
+        */
+        Node baseNode(const IncEdgeIt & iter)const;
+        /** \brief Return the start node of the edge the given iterator is referring to (API: LEMON).
+        */
+        Node baseNode(const OutArcIt & iter)const;
+
+        /** \brief Return the end node of the edge the given iterator is referring to (API: LEMON).
+        */
+        Node runningNode(const IncEdgeIt & iter)const;
+        /** \brief Return the end node of the edge the given iterator is referring to (API: LEMON).
+        */ 
+        Node runningNode(const OutArcIt & iter)const;
+
+
+        /** \brief Get the ID  for node desciptor \a v (API: LEMON).
+        */
+        index_type id(const Node & node)const;
+        /** \brief Get the ID  for edge desciptor \a v (API: LEMON).
+        */
+        index_type id(const Edge & edge)const;
+        /** \brief Get the ID  for arc desciptor \a v (API: LEMON).
+        */
+        index_type id(const Arc  & arc )const;
+
+        /** \brief Get edge descriptor for given node ID \a i (API: LEMON).
+            Return <tt>Edge(lemon::INVALID)</tt> when the ID does not exist in this graph.
+        */
+        Edge edgeFromId(const index_type id)const;
+
+        /** \brief Get node descriptor for given node ID \a i (API: LEMON).
+            Return <tt>Node(lemon::INVALID)</tt> when the ID does not exist in this graph.
+        */
+        Node nodeFromId(const index_type id)const;
+        /** \brief Get arc descriptor for given node ID \a i (API: LEMON).
+            Return <tt>Arc(lemon::INVALID)</tt> when the ID does not exist in this graph.
+        */
+        Arc  arcFromId(const index_type id)const;
+
+
+        /** \brief Get a descriptor for the edge connecting vertices \a u and \a v,<br/>or <tt>lemon::INVALID</tt> if no such edge exists (API: LEMON).
+        */
+        Edge findEdge(const Node & a,const Node & b)const;
+        /** \brief Get a descriptor for the arc connecting vertices \a u and \a v,<br/>or <tt>lemon::INVALID</tt> if no such edge exists (API: LEMON).
+        */
+        Arc  findArc(const Node & u,const Node & v)const;
+
+        /* \brief add a new node to the graph. 
+            the next unused id will be assigned to the node
+        */
+        Node addNode();
+        /* \brief add a  node to the graph with a given id.
+            If there is  another node with this id, no
+            new node will be added.
+        */
+        Node addNode(const index_type id);
+
+
+        /*  \brief this will remove any nodes if there are existing nodes (and edges)
+            and will add nodes in the range of ids , endId is not included!
+        */
+        void assignNodeRange(const index_type beginId, const index_type endId);
+
+
+
+        /* \brief add an edge to the graph.
+            If there is an other edge between u and v no new edge will be added.
+        */
+        Edge addEdge(const Node & u , const Node & v);
+        /* \brief add an edge to the graph.
+            If there is an other edge between u and v no new edge will be added.
+            If the nodes for the given id's are not in the graph, they will be added.
+        */
+        Edge addEdge(const index_type u ,const index_type v);
+
+        
+        size_t maxDegree()const{
+            size_t md=0;
+            for(NodeIt it(*this);it!=lemon::INVALID;++it){
+                std::max(md, size_t( degree(*it) ) );
+            }
+            return md;
+        }
+
+
+        ////////////////////////
+        // BOOST API
+        /////////////////////////
+        // - sizes 
+        // - iterators
+        vertex_iterator  get_vertex_iterator()const;
+        vertex_iterator  get_vertex_end_iterator()const  ;
+        edge_iterator    get_edge_iterator()const;
+        edge_iterator    get_edge_end_iterator()const  ;
+        degree_size_type degree(const vertex_descriptor & node)const{
+            return nodeImpl(node).numberOfEdges();
+        }
+
+        static const bool is_directed = false;
+
+    public:
+
+        void reserveMaxNodeId(const index_type mxid ){
+            if(nodeNum()==0 ||  mxid>maxNodeId())
+                nodes_.reserve(mxid+1);
+        }
+
+        void reserveEdges(const size_t size ){
+            if(size>(size_t)edgeNum())
+                edges_.reserve(size);
+        }
+
+
+        void clear(){
+            nodeNum_=0;
+            edgeNum_=0;
+            edges_.clear();
+            nodes_.clear();
+        }
+        size_t serializationSize()const{
+
+            // num edges + num nodes 
+            // max edge id  + max node id
+            size_t size=4;
+
+            // edge ids
+            size+= 2*edgeNum();
+
+
+            for(NodeIt iter(*this); iter!= lemon::INVALID ; ++iter){
+                size+= 2+this->degree(*iter)*2;    
+            }
+
+            return size;
+        }
+
+        template<class ITER>
+        void serialize(ITER outIter) const {
+
+            // sizes of graph
+            *outIter = nodeNum(); ++outIter;
+            *outIter = edgeNum(); ++outIter;
+            *outIter = maxNodeId(); ++outIter;
+            *outIter = maxEdgeId(); ++outIter;
+
+            // edges
+            for(EdgeIt iter(*this); iter!=lemon::INVALID; ++iter){
+                const Edge e(*iter);
+                const size_t ui = this->id(this->u(e));
+                const size_t vi = this->id(this->v(e));
+                *outIter = ui; ++outIter;
+                *outIter = vi; ++outIter;
+            }
+
+
+
+            // node neighbors
+            for(NodeIt iter(*this); iter!= lemon::INVALID ; ++iter){
+                const Node n(*iter);
+
+                *outIter = this->id(*iter); ++outIter;
+                *outIter = this->degree(*iter); ++outIter;
+
+                for(OutArcIt eIter(*this,n); eIter!=lemon::INVALID; ++eIter){
+                    const Edge e(*eIter);
+                    const Node oNode(this->target(*eIter));
+
+                    const size_t ei = this->id(e);
+                    const size_t oni = this->id(oNode);
+
+                    *outIter = ei; ++outIter;
+                    *outIter = oni; ++outIter;
+                }
+            }
+
+        }
+
+        template<class ITER>
+        void deserialize(ITER begin, ITER end){
+
+
+            nodeNum_ = *begin; ++begin;
+            edgeNum_ = *begin; ++begin;
+            const size_t maxNid = *begin; ++begin;
+            const size_t maxEid = *begin; ++begin;
+
+            nodes_.clear();
+            edges_.clear();
+            nodes_.resize(maxNid+1, NodeStorage());
+            edges_.resize(maxEid+1, EdgeStorage());
+
+            // set up edges
+            for(size_t eid=0; eid<edgeNum_; ++eid){
+                const size_t u = *begin; ++begin;
+                const size_t v = *begin; ++begin;
+                nodes_[u].setId(u);
+                nodes_[v].setId(v);
+                edges_[eid]=EdgeStorage(u,v,eid);
+            }
+
+            // set up nodes
+            for(size_t i=0; i<nodeNum_; ++i){
+
+                const size_t id = *begin; ++begin;
+                const size_t nodeDegree=*begin; ++begin;
+
+                NodeStorage & nodeImpl = nodes_[id];
+                nodeImpl.setId(id);
+                for(size_t d=0; d<nodeDegree; ++d){
+                    const size_t ei  = *begin; ++begin;
+                    const size_t oni =  *begin; ++begin;
+                    nodeImpl.insert(oni, ei);
+                }
+            }
+        }
+
+    private:
+        // private typedefs
+        typedef std::vector<NodeStorage> NodeVector;
+        typedef std::vector<EdgeStorage> EdgeVector;
+
+
+        // needs acces to const nodeImpl
+        template<class G,class NIMPL,class FILT>
+        friend class detail::GenericIncEdgeIt;
+
+        template<class G>
+        friend struct detail::NeighborNodeFilter;
+        template<class G>
+        friend struct detail::IncEdgeFilter;
+        template<class G>
+        friend struct detail::BackEdgeFilter;
+        template<class G>
+        friend struct detail::IsOutFilter;
+        template<class G>
+        friend struct detail::IsBackOutFilter;
+        template<class G>
+        friend struct detail::IsInFilter;
+
+
+        friend class detail_adjacency_list_graph::ItemIter<GraphType,Node>;
+        friend class detail_adjacency_list_graph::ItemIter<GraphType,Edge>;
+
+
+        const NodeStorage & nodeImpl(const Node & node)const{
+            return nodes_[node.id()];
+        }
+
+        NodeStorage & nodeImpl(const Node & node){
+            return nodes_[node.id()];
+        }
+
+
+
+
+
+        // graph
+        NodeVector nodes_;
+        EdgeVector edges_;
+
+        size_t nodeNum_;
+        size_t edgeNum_;
+    };
+
+
+
+#ifndef DOXYGEN  // doxygen doesn't like out-of-line definitions
+
+    inline AdjacencyListGraph::AdjacencyListGraph(
+        const size_t reserveNodes,
+        const size_t reserveEdges
+    )
+    :   nodes_(),
+        edges_(),
+        nodeNum_(0),
+        edgeNum_(0)
+    {
+        nodes_.reserve(reserveNodes);
+        edges_.reserve(reserveEdges);
+    }
+
+
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::addNode(){
+        const index_type id = nodes_.size();
+        nodes_.push_back(NodeStorage(id));
+        ++nodeNum_;
+        return Node(id);
+    }
+
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::addNode(const AdjacencyListGraph::index_type id){
+        if(id == nodes_.size()){
+            nodes_.push_back(NodeStorage(id));
+            ++nodeNum_;
+            return Node(id);
+        }
+        else if((std::size_t)id < nodes_.size()){
+            const Node node = nodeFromId(id);
+            if(node==lemon::INVALID){
+                nodes_[id]=NodeStorage(id);
+                ++nodeNum_;
+                return Node(id);
+            }
+            else{
+                return node;
+            }
+        }
+        else{
+            // refactor me
+            while(nodes_.size() < (std::size_t)id){
+                nodes_.push_back(NodeStorage(lemon::INVALID));
+            }
+            nodes_.push_back(NodeStorage(id));
+            ++nodeNum_;
+            return Node(id);
+        }
+    }
+
+
+    inline void 
+    AdjacencyListGraph::assignNodeRange(const AdjacencyListGraph::index_type beginId, const AdjacencyListGraph::index_type endId){
+        nodes_.clear();
+        edges_.clear();
+        edgeNum_=0;
+        nodeNum_ = endId - beginId;
+        nodes_.resize(endId);
+        for(index_type i=beginId; i<endId; ++i)
+            nodes_[i]=NodeStorage(i);
+    }
+
+
+
+    inline AdjacencyListGraph::Edge 
+    AdjacencyListGraph::addEdge(
+        const AdjacencyListGraph::Node & u , 
+        const AdjacencyListGraph::Node & v
+    ){
+        const Edge foundEdge  = findEdge(u,v);
+        if(foundEdge!=lemon::INVALID){
+            return foundEdge;
+        }
+        else if(u==lemon::INVALID || v==lemon::INVALID){
+            return Edge(lemon::INVALID);
+        }
+        else{
+            const index_type eid  = edges_.size();
+            const index_type uid = u.id();
+            const index_type vid = v.id();
+            edges_.push_back(EdgeStorage(uid,vid,eid));
+            nodeImpl(u).insert(vid,eid);
+            nodeImpl(v).insert(uid,eid);
+            ++edgeNum_;
+            return Edge(eid);
+        }   
+    }
+
+    inline AdjacencyListGraph::Edge 
+    AdjacencyListGraph::addEdge(
+        const AdjacencyListGraph::index_type u ,
+        const AdjacencyListGraph::index_type v
+    ){
+        const Node uu = addNode(u);
+        const Node vv = addNode(v);
+        return addEdge(uu,vv);
+    }
+
+    
+    
+    inline AdjacencyListGraph::Arc 
+    AdjacencyListGraph::direct(
+        const AdjacencyListGraph::Edge & edge,
+        const bool forward
+    )const{
+        if(edge!=lemon::INVALID){
+            if(forward)
+                return Arc(id(edge),id(edge));
+            else
+                return Arc(id(edge)+maxEdgeId()+1,id(edge));
+        }
+        else
+            return Arc(lemon::INVALID);
+    }
+
+    
+    inline AdjacencyListGraph::Arc 
+    AdjacencyListGraph::direct(
+        const AdjacencyListGraph::Edge & edge,
+        const AdjacencyListGraph::Node & node
+    )const{
+        if(u(edge)==node){
+            return Arc(id(edge),id(edge));
+        }
+        else if(v(edge)==node){
+            return Arc(id(edge)+maxEdgeId()+1,id(edge));
+        }
+        else{
+            return Arc(lemon::INVALID);
+        }
+    }
+
+    
+    inline bool
+    AdjacencyListGraph::direction(
+        const AdjacencyListGraph::Arc & arc
+    )const{
+        return id(arc)<=maxEdgeId();
+    }
+
+    
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::u(
+        const AdjacencyListGraph::Edge & edge
+    )const{
+        return Node(edges_[id(edge)].u());
+    }
+
+    
+    inline AdjacencyListGraph::Node
+    AdjacencyListGraph::v(
+        const AdjacencyListGraph::Edge & edge
+    )const{
+        return Node(edges_[id(edge)].v());
+    }
+
+
+    
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::source(
+        const AdjacencyListGraph::Arc & arc
+    )const{
+        const index_type arcIndex  = id(arc);
+        if (arcIndex > maxEdgeId() ){
+            const index_type edgeIndex = arc.edgeId();
+            const Edge edge = edgeFromId(edgeIndex);
+            return v(edge);
+        }
+        else{
+            const index_type edgeIndex = arcIndex;
+            const Edge edge = edgeFromId(edgeIndex);
+            return u(edge);
+        }
+    }   
+
+
+    
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::target(
+        const AdjacencyListGraph::Arc & arc
+    )const{
+        const index_type arcIndex  = id(arc);
+        if (arcIndex > maxEdgeId() ){
+            const index_type edgeIndex = arc.edgeId();
+            const Edge edge = edgeFromId(edgeIndex);
+            return u(edge);
+        }
+        else{
+            const index_type edgeIndex = arcIndex;
+            const Edge edge = edgeFromId(edgeIndex);
+            return v(edge);
+        }
+    }
+
+    inline AdjacencyListGraph::Node
+    AdjacencyListGraph::oppositeNode(
+        const AdjacencyListGraph::Node &n,
+        const AdjacencyListGraph::Edge &e
+    ) const {
+        const Node uNode = u(e);
+        const Node vNode = v(e);
+        if(id(uNode)==id(n)){
+            return vNode;
+        }
+        else if(id(vNode)==id(n)){
+            return uNode;
+        }
+        else{
+            return Node(-1);
+        }
+    }
+
+
+    
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::baseNode(
+        const AdjacencyListGraph::IncEdgeIt & iter
+    )const{
+        return u(*iter);
+    }
+
+    
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::baseNode(
+        const AdjacencyListGraph::OutArcIt & iter 
+    )const{
+        return source(*iter);
+    }
+
+
+    
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::runningNode(
+        const AdjacencyListGraph::IncEdgeIt & iter
+    )const{
+        return v(*iter);
+    }
+
+    
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::runningNode(
+        const AdjacencyListGraph::OutArcIt & iter 
+    )const{
+        return target(*iter);
+    }
+
+    
+    inline AdjacencyListGraph::index_type 
+    AdjacencyListGraph::edgeNum()const{
+        return edgeNum_;
+    }
+
+    
+    inline AdjacencyListGraph::index_type 
+    AdjacencyListGraph::nodeNum()const{
+        return nodeNum_;
+    }
+
+    
+    inline AdjacencyListGraph::index_type 
+    AdjacencyListGraph::arcNum()const{
+        return edgeNum()*2;
+    }
+
+    
+    inline AdjacencyListGraph::index_type 
+    AdjacencyListGraph::maxEdgeId()const{
+        return edges_.back().id();
+    }
+
+    
+    inline AdjacencyListGraph::index_type 
+    AdjacencyListGraph::maxNodeId()const{
+        return nodes_.back().id();
+    }
+
+    
+    inline AdjacencyListGraph::index_type 
+    AdjacencyListGraph::maxArcId()const{
+        return maxEdgeId()*2+1;
+    }
+
+    // ids 
+    
+    inline AdjacencyListGraph::index_type 
+    AdjacencyListGraph::id(
+        const AdjacencyListGraph::Node & node
+    )const{
+        return node.id();
+    }
+
+    
+    inline AdjacencyListGraph::index_type 
+    AdjacencyListGraph::id(
+        const AdjacencyListGraph::Edge & edge
+    )const{
+        return edge.id();
+    }
+
+    
+    inline AdjacencyListGraph::index_type 
+    AdjacencyListGraph::id(
+        const AdjacencyListGraph::Arc & arc
+    )const{
+        return arc.id();
+    }
+
+    // get edge / node from id
+    
+    inline AdjacencyListGraph::Edge 
+    AdjacencyListGraph::edgeFromId(
+        const AdjacencyListGraph::index_type id
+    )const{
+        if((std::size_t)id < edges_.size() && edges_[id].id() != -1)
+            return Edge(edges_[id].id());
+        else
+            return Edge(lemon::INVALID);
+    }
+
+    
+    inline AdjacencyListGraph::Node 
+    AdjacencyListGraph::nodeFromId(
+        const AdjacencyListGraph::index_type id
+    )const{
+        if((std::size_t)id < nodes_.size() && nodes_[id].id() != -1)
+            return Node(nodes_[id].id());
+        else
+            return Node(lemon::INVALID);
+    }
+
+    
+    inline AdjacencyListGraph::Arc 
+    AdjacencyListGraph::arcFromId(
+        const AdjacencyListGraph::index_type id
+    )const{
+        if(id<=maxEdgeId()){
+            if(edgeFromId(id)==lemon::INVALID)
+                return Arc(lemon::INVALID);
+            else
+                return Arc(id,id);
+        }
+        else{
+            const index_type edgeId = id - (maxEdgeId() + 1);
+            if( edgeFromId(edgeId)==lemon::INVALID)
+                return Arc(lemon::INVALID);
+            else
+                return Arc(id,edgeId);
+        }
+    }
+
+    
+    inline  AdjacencyListGraph::Edge  
+    AdjacencyListGraph::findEdge(
+        const AdjacencyListGraph::Node & a,
+        const AdjacencyListGraph::Node & b
+    )const{
+        if(a!=b){
+            std::pair<index_type,bool> res =  nodes_[id(a)].findEdge(id(b));
+            if(res.second){
+                return Edge(res.first);
+            }
+        }
+        return Edge(lemon::INVALID);
+    }
+
+
+    
+    inline  AdjacencyListGraph::Arc  
+    AdjacencyListGraph::findArc(
+        const AdjacencyListGraph::Node & uNode,
+        const AdjacencyListGraph::Node & vNode
+    )const{
+        const Edge e = findEdge(uNode,vNode);
+        if(e==lemon::INVALID){
+            return Arc(lemon::INVALID);
+        }
+        else{
+            if(u(e)==uNode)
+                return direct(e,true) ;
+            else
+                return direct(e,false) ;
+        }
+    }
+
+
+    // iterators
+    
+    inline AdjacencyListGraph::vertex_iterator 
+    AdjacencyListGraph::get_vertex_iterator()const{
+        return NodeIt(0,nodeNum());
+    }
+
+    
+    inline AdjacencyListGraph::vertex_iterator 
+    AdjacencyListGraph::get_vertex_end_iterator()const{  
+        return NodeIt(nodeNum(),nodeNum());
+    }
+
+
+    
+    inline AdjacencyListGraph::edge_iterator 
+    AdjacencyListGraph::get_edge_iterator()const{
+        return EdgeIt(0,edgeNum());
+    }
+
+    
+    inline AdjacencyListGraph::edge_iterator 
+    AdjacencyListGraph::get_edge_end_iterator()const{  
+        return EdgeIt(edgeNum(),edgeNum());
+    }
+
+#endif //DOXYGEN
+
+//@}
+
+} // namespace vigra
+
+
+// boost free functions specialized for adjacency list graph
+namespace boost{
+
+    ////////////////////////////////////
+    // functions to get size of the graph
+    ////////////////////////////////////
+    inline vigra::AdjacencyListGraph::vertex_size_type
+    num_vertices(const vigra::AdjacencyListGraph & g){
+        return g.nodeNum();
+    }
+    inline vigra::AdjacencyListGraph::edge_size_type
+    num_edges(const vigra::AdjacencyListGraph & g){
+        return g.edgeNum();
+    }
+
+
+    ////////////////////////////////////
+    // functions to get degrees of nodes
+    // (degree / indegree / outdegree)
+    ////////////////////////////////////
+    inline vigra::AdjacencyListGraph::degree_size_type
+    degree(const vigra::AdjacencyListGraph::vertex_descriptor & v , const vigra::AdjacencyListGraph & g){
+        return g.degree(v);
+    }
+    // ??? check if this is the right impl. for undirected graphs
+    inline vigra::AdjacencyListGraph::degree_size_type
+    in_degree(const vigra::AdjacencyListGraph::vertex_descriptor & v , const vigra::AdjacencyListGraph & g){
+        return g.degree(v);
+    }
+    // ??? check if this is the right impl. for undirected graphs
+    inline vigra::AdjacencyListGraph::degree_size_type
+    out_degree(const vigra::AdjacencyListGraph::vertex_descriptor & v , const vigra::AdjacencyListGraph & g){
+        return g.degree(v);
+    }
+
+
+    ////////////////////////////////////
+    // functions to u/v source/target
+    ////////////////////////////////////
+    inline vigra::AdjacencyListGraph::vertex_descriptor
+    source(const vigra::AdjacencyListGraph::edge_descriptor & e , const vigra::AdjacencyListGraph & g){
+        return g.u(e);
+    }
+
+    inline vigra::AdjacencyListGraph::vertex_descriptor
+    target(const vigra::AdjacencyListGraph::edge_descriptor & e , const vigra::AdjacencyListGraph & g){
+        return g.v(e);
+    }
+
+    ////////////////////////////////////
+    // functions to get iterator pairs
+    ////////////////////////////////////
+    inline  std::pair< vigra::AdjacencyListGraph::vertex_iterator, vigra::AdjacencyListGraph::vertex_iterator >
+    vertices(const vigra::AdjacencyListGraph & g ){
+        return std::pair< vigra::AdjacencyListGraph::vertex_iterator, vigra::AdjacencyListGraph::vertex_iterator >(
+            g.get_vertex_iterator(), g.get_vertex_end_iterator());
+    }
+    inline  std::pair< vigra::AdjacencyListGraph::edge_iterator, vigra::AdjacencyListGraph::edge_iterator >
+    edges(const vigra::AdjacencyListGraph & g ){
+        return std::pair< vigra::AdjacencyListGraph::edge_iterator, vigra::AdjacencyListGraph::edge_iterator >(
+            g.get_edge_iterator(),g.get_edge_end_iterator());
+    }
+
+
+    inline  std::pair< vigra::AdjacencyListGraph::in_edge_iterator, vigra::AdjacencyListGraph::in_edge_iterator >
+    in_edges(const vigra::AdjacencyListGraph::vertex_descriptor & v,  const vigra::AdjacencyListGraph & g ){
+        return std::pair< vigra::AdjacencyListGraph::in_edge_iterator, vigra::AdjacencyListGraph::in_edge_iterator >(
+            vigra::AdjacencyListGraph::in_edge_iterator(g,v),vigra::AdjacencyListGraph::in_edge_iterator(lemon::INVALID)
+        );
+    }
+    inline  std::pair< vigra::AdjacencyListGraph::out_edge_iterator, vigra::AdjacencyListGraph::out_edge_iterator >
+    out_edges(const vigra::AdjacencyListGraph::vertex_descriptor & v,  const vigra::AdjacencyListGraph & g ){
+        return std::pair< vigra::AdjacencyListGraph::out_edge_iterator, vigra::AdjacencyListGraph::out_edge_iterator >(
+            vigra::AdjacencyListGraph::out_edge_iterator(g,v),vigra::AdjacencyListGraph::out_edge_iterator(lemon::INVALID)
+        );
+    }
+
+}  // namespace boost
+
+#endif /*VIGRA_ADJACENCY_LIST_GRAPH_HXX*/
diff --git a/include/vigra/affine_registration.hxx b/include/vigra/affine_registration.hxx
index e608d97..9e5247b 100644
--- a/include/vigra/affine_registration.hxx
+++ b/include/vigra/affine_registration.hxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*               Copyright 2005-2006 by Ullrich Koethe                  */
+/*                 Copyright 2005-2006 by Ullrich Koethe                */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -29,10 +29,10 @@
 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
-/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
- 
+
 #ifndef VIGRA_AFFINE_REGISTRATION_HXX
 #define VIGRA_AFFINE_REGISTRATION_HXX
 
@@ -43,34 +43,37 @@
 #include "splineimageview.hxx"
 #include "imagecontainer.hxx"
 #include "multi_shape.hxx"
+#include "affinegeometry.hxx"
 
 #include <cmath>
 
 namespace vigra {
 
 /** \addtogroup Registration Image Registration
+
+    Transform different image into a common coordinate system.
 */
 //@{
 
 /********************************************************/
 /*                                                      */
-/*       affineMatrix2DFromCorrespondingPoints          */
+/*         affineMatrix2DFromCorrespondingPoints        */
 /*                                                      */
 /********************************************************/
 
 /** \brief Create homogeneous matrix that maps corresponding points onto each other.
- 
+
     For use with \ref affineWarpImage(). When only two corresponding points are given,
-    the matrix will only represent a similarity transform 
+    the matrix will only represent a similarity transform
     (translation, rotation, and uniform scaling). When only one point pair is given,
     the result will be a pure translation.
 */
 template <class SrcIterator, class DestIterator>
-linalg::TemporaryMatrix<double> 
+linalg::TemporaryMatrix<double>
 affineMatrix2DFromCorrespondingPoints(SrcIterator s, SrcIterator send, DestIterator d)
 {
     int size = send - s;
-    
+
     linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
 
     if(size == 1)
@@ -81,7 +84,7 @@ affineMatrix2DFromCorrespondingPoints(SrcIterator s, SrcIterator send, DestItera
     else if(size == 2)
     {
         Matrix<double> m(4,4), r(4,1), so(4,1);
-        
+
         for(int k=0; k<size; ++k, ++s, ++d)
         {
             m(2*k,0) = (*s)[0];
@@ -89,17 +92,17 @@ affineMatrix2DFromCorrespondingPoints(SrcIterator s, SrcIterator send, DestItera
             m(2*k,2) = 1.0;
             m(2*k,3) = 0.0;
             r(2*k,0) = (*d)[0];
-            
+
             m(2*k+1,0) = (*s)[1];
             m(2*k+1,1) = (*s)[0];
             m(2*k+1,2) = 0.0;
             m(2*k+1,3) = 1.0;
             r(2*k+1,0) = (*d)[1];
         }
-    
+
         if(!linearSolve(m, r, so))
             vigra_fail("affineMatrix2DFromCorrespondingPoints(): singular solution matrix.");
-        
+
         ret(0,0) = so(0,0);
         ret(1,1) = so(0,0);
         ret(0,1) = -so(1,0);
@@ -109,21 +112,21 @@ affineMatrix2DFromCorrespondingPoints(SrcIterator s, SrcIterator send, DestItera
     }
     else if(size >= 3)
     {
-        Matrix<double> m(3,3),  rx(3,1), sx(3,1), ry(3,1), sy(3,1), c(3,1);
+        Matrix<double> m(3,3),    rx(3,1), sx(3,1), ry(3,1), sy(3,1), c(3,1);
         c(2,0) = 1.0;
         for(int k=0; k<size; ++k, ++s, ++d)
         {
             c(0,0) = (*s)[0];
             c(1,0) = (*s)[1];
-            
+
             m  += outer(c);
             rx += (*d)[0]*c;
             ry += (*d)[1]*c;
         }
-    
+
         if(!linearSolve(m, rx, sx) || !linearSolve(m, ry, sy))
             vigra_fail("affineMatrix2DFromCorrespondingPoints(): singular solution matrix.");
-        
+
         ret(0,0) = sx(0,0);
         ret(0,1) = sx(1,0);
         ret(0,2) = sx(2,0);
@@ -135,6 +138,12 @@ affineMatrix2DFromCorrespondingPoints(SrcIterator s, SrcIterator send, DestItera
     return ret;
 }
 
+    /** \brief Option object for affine registration functions.
+
+        The template parameter <tt>SPLINEORDER</tt> (default: 2) specifies
+        the order of interpolation for the intensities at non-integer image
+        coordinates.
+    */
 template <int SPLINEORDER = 2>
 class AffineMotionEstimationOptions
 {
@@ -142,42 +151,74 @@ class AffineMotionEstimationOptions
     double burt_filter_strength;
     int highest_level, iterations_per_level;
     bool use_laplacian_pyramid;
-    
+
     AffineMotionEstimationOptions()
     : burt_filter_strength(0.4),
       highest_level(4),
       iterations_per_level(4),
       use_laplacian_pyramid(false)
     {}
-    
+
     template <int ORDER>
-    AffineMotionEstimationOptions(AffineMotionEstimationOptions<ORDER>  const & other)
+    AffineMotionEstimationOptions(AffineMotionEstimationOptions<ORDER>    const & other)
     : burt_filter_strength(other.burt_filter_strength),
       highest_level(other.highest_level),
       iterations_per_level(other.iterations_per_level),
       use_laplacian_pyramid(other.use_laplacian_pyramid)
     {}
-    
+
+        /** \brief Change the spline order for intensity interpolation.
+
+            Usage:
+            \code
+            // use linear interpolation
+            AffineMotionEstimationOptions<>().splineOrder<1>();
+            \endcode
+
+            Default: order = 2 (quadratic interpolation)
+        */
     template <int NEWORDER>
     AffineMotionEstimationOptions<NEWORDER> splineOrder() const
     {
         return AffineMotionEstimationOptions<NEWORDER>(*this);
     }
-    
-    AffineMotionEstimationOptions & burtFilterStrength(double strength)
+
+        /** \brief Define amount of smoothing before subsampling to the next pyramid level.
+
+            Pyramids are created with the Burt filter:
+            \code
+            [0.25 - center / 2.0, 0.25, center, 0.25, 0.25 - center / 2.0]
+            \endcode
+            \a center must thus be between 0.25 and 0.5, and the smaller it is,
+            the more smoothing is applied.
+
+            Default: 0.4 (moderate smoothing)
+        */
+    AffineMotionEstimationOptions & burtFilterCenterStrength(double center)
     {
-        vigra_precondition(0.25 <= strength && strength <= 0.5,
-          "AffineMotionEstimationOptions::burtFilterStrength(): strength must be between 0.25 and 0.5 (inclusive).");
-        burt_filter_strength = strength;
+        vigra_precondition(0.25 <= center && center <= 0.5,
+          "AffineMotionEstimationOptions::burtFilterCenterStrength(): center must be between 0.25 and 0.5 (inclusive).");
+        burt_filter_strength = center;
         return *this;
     }
-    
+
+        /** \brief Define the highest level of the image pyramid.
+
+            The original image is at level 0, and each level downsamples
+            the image by 1/2.
+
+            Default: 4 (16-fold downsampling)
+        */
     AffineMotionEstimationOptions & highestPyramidLevel(unsigned int level)
     {
         highest_level = (int)level;
         return *this;
     }
-    
+
+        /** \brief Number of Gauss-Newton iterations per level.
+
+            Default: 4
+        */
     AffineMotionEstimationOptions & iterationsPerLevel(unsigned int iter)
     {
         vigra_precondition(0 < iter,
@@ -185,13 +226,27 @@ class AffineMotionEstimationOptions
         iterations_per_level = (int)iter;
         return *this;
     }
-    
+
+        /** \brief Base registration on a Gaussian pyramid.
+
+            Images are registered such that the similarity in intensity is
+            maximized.
+
+            Default: true
+        */
     AffineMotionEstimationOptions & useGaussianPyramid(bool f = true)
     {
         use_laplacian_pyramid = !f;
         return *this;
     }
-    
+
+        /** \brief Base registration on a Laplacian pyramid.
+
+            Images are registered such that the similarity in second
+            derivatives (=Laplacian operator results) is maximized.
+
+            Default: false
+        */
     AffineMotionEstimationOptions & useLaplacianPyramid(bool f = true)
     {
         use_laplacian_pyramid = f;
@@ -208,10 +263,10 @@ struct TranslationEstimationFunctor
     {
         int w = dest.width();
         int h = dest.height();
-        
+
         Matrix<double> grad(2,1), m(2,2), r(2,1), s(2,1);
         double dx = matrix(0,0), dy = matrix(1,0);
-        
+
         for(int y = 0; y < h; ++y)
         {
             double sx = matrix(0,1)*y + matrix(0,2);
@@ -220,18 +275,18 @@ struct TranslationEstimationFunctor
             {
                 if(!src.isInside(sx, sy))
                     continue;
-                  
+
                 grad(0,0) = src.dx(sx, sy);
                 grad(1,0) = src.dy(sx, sy);
                 double diff = dest(x, y) - src(sx, sy);
-                
+
                 m += outer(grad);
                 r -= diff*grad;
             }
         }
-        
+
         linearSolve(m, r, s);
-        
+
         matrix(0,2) -= s(0,0);
         matrix(1,2) -= s(1,0);
     }
@@ -244,12 +299,12 @@ struct SimilarityTransformEstimationFunctor
     {
         int w = dest.width();
         int h = dest.height();
-        
+
         Matrix<double> grad(2,1), coord(4, 2), c(4, 1), m(4, 4), r(4,1), s(4,1);
         coord(0,0) = 1.0;
         coord(1,1) = 1.0;
         double dx = matrix(0,0), dy = matrix(1,0);
-        
+
         for(int y = 0; y < h; ++y)
         {
             double sx = matrix(0,1)*y + matrix(0,2);
@@ -258,7 +313,7 @@ struct SimilarityTransformEstimationFunctor
             {
                 if(!src.isInside(sx, sy))
                     continue;
-                  
+
                 grad(0,0) = src.dx(sx, sy);
                 grad(1,0) = src.dy(sx, sy);
                 coord(2,0) = (double)x;
@@ -266,15 +321,15 @@ struct SimilarityTransformEstimationFunctor
                 coord(3,0) = -(double)y;
                 coord(2,1) = (double)y;
                 double diff = dest(x, y) - src(sx, sy);
-                
+
                 c = coord * grad;
                 m += outer(c);
                 r -= diff*c;
             }
         }
-        
+
         linearSolve(m, r, s);
-        
+
         matrix(0,2) -= s(0,0);
         matrix(1,2) -= s(1,0);
         matrix(0,0) -= s(2,0);
@@ -291,12 +346,12 @@ struct AffineTransformEstimationFunctor
     {
         int w = dest.width();
         int h = dest.height();
-        
+
         Matrix<double> grad(2,1), coord(6, 2), c(6, 1), m(6,6), r(6,1), s(6,1);
         coord(0,0) = 1.0;
         coord(1,1) = 1.0;
         double dx = matrix(0,0), dy = matrix(1,0);
-        
+
         for(int y = 0; y < h; ++y)
         {
             double sx = matrix(0,1)*y + matrix(0,2);
@@ -305,7 +360,7 @@ struct AffineTransformEstimationFunctor
             {
                 if(!src.isInside(sx, sy))
                     continue;
-                  
+
                 grad(0,0) = src.dx(sx, sy);
                 grad(1,0) = src.dy(sx, sy);
                 coord(2,0) = (double)x;
@@ -313,15 +368,15 @@ struct AffineTransformEstimationFunctor
                 coord(3,0) = (double)y;
                 coord(5,1) = (double)y;
                 double diff = dest(x, y) - src(sx, sy);
-                
+
                 c = coord * grad;
                 m += outer(c);
                 r -= diff*c;
             }
         }
-        
+
         linearSolve(m, r, s);
-        
+
         matrix(0,2) -= s(0,0);
         matrix(1,2) -= s(1,0);
         matrix(0,0) -= s(2,0);
@@ -331,13 +386,13 @@ struct AffineTransformEstimationFunctor
     }
 };
 
-template <class SrcIterator, class SrcAccessor, 
-          class DestIterator, class DestAccessor, 
+template <class SrcIterator, class SrcAccessor,
+          class DestIterator, class DestAccessor,
           int SPLINEORDER, class Functor>
-void 
+void
 estimateAffineMotionImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                          DestIterator dul, DestIterator dlr, DestAccessor dest,
-                         Matrix<double> & affineMatrix, 
+                         Matrix<double> & affineMatrix,
                          AffineMotionEstimationOptions<SPLINEORDER> const & options,
                          Functor motionModel)
 {
@@ -345,11 +400,11 @@ estimateAffineMotionImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src,
     typedef BasicImage<STmpType> STmpImage;
     typedef typename NumericTraits<typename DestAccessor::value_type>::RealPromote DTmpType;
     typedef BasicImage<DTmpType> DTmpImage;
-    
+
     int toplevel = options.highest_level;
     ImagePyramid<STmpImage> srcPyramid(0, toplevel, sul, slr, src);
     ImagePyramid<DTmpImage> destPyramid(0, toplevel, dul, dlr, dest);
-    
+
     if(options.use_laplacian_pyramid)
     {
         pyramidReduceBurtLaplacian(srcPyramid, 0, toplevel, options.burt_filter_strength);
@@ -360,43 +415,45 @@ estimateAffineMotionImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src,
         pyramidReduceBurtFilter(srcPyramid, 0, toplevel, options.burt_filter_strength);
         pyramidReduceBurtFilter(destPyramid, 0, toplevel, options.burt_filter_strength);
     }
-        
-    Matrix<double> currentMatrix(affineMatrix(2,2) == 0.0 
+
+    Matrix<double> currentMatrix(affineMatrix(2,2) == 0.0
                                     ? identityMatrix<double>(3)
                                     : affineMatrix);
     currentMatrix(0,2) /= std::pow(2.0, toplevel);
     currentMatrix(1,2) /= std::pow(2.0, toplevel);
-    
+
     for(int level = toplevel; level >= 0; --level)
     {
         SplineImageView<SPLINEORDER, STmpType> sp(srcImageRange(srcPyramid[level]));
-        
+
         for(int iter = 0; iter < options.iterations_per_level; ++iter)
         {
             motionModel(sp, destPyramid[level], currentMatrix);
         }
-        
+
         if(level > 0)
         {
             currentMatrix(0,2) *= 2.0;
             currentMatrix(1,2) *= 2.0;
         }
     }
-    
+
     affineMatrix = currentMatrix;
 }
 
-} // namespace detail 
+} // namespace detail
 
 /********************************************************/
 /*                                                      */
-/*                 estimateTranslation                  */
+/*                   estimateTranslation                */
 /*                                                      */
 /********************************************************/
 
 /** \brief Estimate the optical flow between two images according to a translation model.
 
-    Sorry, no \ref detailedDocumentation() available yet.
+    This function applies the same algorithm as \ref estimateAffineTransform()
+    with the additional constraint that the motion model must be a translation
+    rather than affine.
 
     <b> Declarations:</b>
 
@@ -406,13 +463,13 @@ estimateAffineMotionImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src,
     pass 2D array views:
     \code
     namespace vigra {
-        template <class T1, class S1, 
-                  class T2, class S2, 
+        template <class T1, class S1,
+                  class T2, class S2,
                   int SPLINEORDER>
-        void 
+        void
         estimateTranslation(MultiArrayView<2, T1, S1> const & src,
                             MultiArrayView<2, T2, S2> dest,
-                            Matrix<double> & affineMatrix, 
+                            Matrix<double> & affineMatrix,
                             AffineMotionEstimationOptions<SPLINEORDER> const & options = AffineMotionEstimationOptions<SPLINEORDER>());
     }
     \endcode
@@ -428,7 +485,7 @@ estimateAffineMotionImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src,
         estimateTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                             DestIterator dul, DestIterator dlr, DestAccessor dest,
                             Matrix<double> & affineMatrix,
-                            AffineMotionEstimationOptions<SPLINEORDER> const & options = 
+                            AffineMotionEstimationOptions<SPLINEORDER> const & options =
                                                         AffineMotionEstimationOptions<>())
     }
     \endcode
@@ -462,10 +519,10 @@ estimateTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
     detail::estimateAffineMotionImpl(sul, slr, src, dul, dlr, dest, affineMatrix,
                                      options, detail::TranslationEstimationFunctor());
 }
-             
+
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
-inline void 
+inline void
 estimateTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                     DestIterator dul, DestIterator dlr, DestAccessor dest,
                     Matrix<double> & affineMatrix)
@@ -474,22 +531,22 @@ estimateTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                         affineMatrix, AffineMotionEstimationOptions<>());
 }
 
-template <class SrcIterator, class SrcAccessor, 
-          class DestIterator, class DestAccessor, 
+template <class SrcIterator, class SrcAccessor,
+          class DestIterator, class DestAccessor,
           int SPLINEORDER>
-inline void 
+inline void
 estimateTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                     triple<DestIterator, DestIterator, DestAccessor> dest,
-                    Matrix<double> & affineMatrix, 
+                    Matrix<double> & affineMatrix,
                     AffineMotionEstimationOptions<SPLINEORDER> const & options)
 {
     estimateTranslation(src.first, src.second, src.third, dest.first, dest.second, dest.third,
                         affineMatrix, options);
 }
 
-template <class SrcIterator, class SrcAccessor, 
+template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
-inline void 
+inline void
 estimateTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                     triple<DestIterator, DestIterator, DestAccessor> dest,
                     Matrix<double> & affineMatrix)
@@ -498,22 +555,22 @@ estimateTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                         affineMatrix, AffineMotionEstimationOptions<>());
 }
 
-template <class T1, class S1, 
-          class T2, class S2, 
+template <class T1, class S1,
+          class T2, class S2,
           int SPLINEORDER>
-inline void 
+inline void
 estimateTranslation(MultiArrayView<2, T1, S1> const & src,
                     MultiArrayView<2, T2, S2> dest,
-                    Matrix<double> & affineMatrix, 
+                    Matrix<double> & affineMatrix,
                     AffineMotionEstimationOptions<SPLINEORDER> const & options)
 {
     estimateTranslation(srcImageRange(src), destImageRange(dest),
                         affineMatrix, options);
 }
 
-template <class T1, class S1, 
+template <class T1, class S1,
           class T2, class S2>
-inline void 
+inline void
 estimateTranslation(MultiArrayView<2, T1, S1> const & src,
                     MultiArrayView<2, T2, S2> dest,
                     Matrix<double> & affineMatrix)
@@ -524,14 +581,16 @@ estimateTranslation(MultiArrayView<2, T1, S1> const & src,
 
 /********************************************************/
 /*                                                      */
-/*              estimateSimilarityTransform             */
+/*                estimateSimilarityTransform           */
 /*                                                      */
 /********************************************************/
 
 /** \brief Estimate the optical flow between two images according to a similarity transform model
            (e.g. translation, rotation, and uniform scaling).
 
-    Sorry, no \ref detailedDocumentation() available yet.
+    This function applies the same algorithm as \ref estimateAffineTransform()
+    with the additional constraint that the motion model must be a similarity
+    transform rather than affine.
 
     <b> Declarations:</b>
 
@@ -541,14 +600,14 @@ estimateTranslation(MultiArrayView<2, T1, S1> const & src,
     pass 2D array views:
     \code
     namespace vigra {
-        template <class T1, class S1, 
-                  class T2, class S2, 
+        template <class T1, class S1,
+                  class T2, class S2,
                   int SPLINEORDER>
-        void 
+        void
         estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
                                     MultiArrayView<2, T2, S2> dest,
-                                    Matrix<double> & affineMatrix, 
-                                    AffineMotionEstimationOptions<SPLINEORDER> const & options = 
+                                    Matrix<double> & affineMatrix,
+                                    AffineMotionEstimationOptions<SPLINEORDER> const & options =
                                                         AffineMotionEstimationOptions<SPLINEORDER>());
     }
     \endcode
@@ -564,7 +623,7 @@ estimateTranslation(MultiArrayView<2, T1, S1> const & src,
         estimateSimilarityTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                             DestIterator dul, DestIterator dlr, DestAccessor dest,
                             Matrix<double> & affineMatrix,
-                            AffineMotionEstimationOptions<SPLINEORDER> const & options = 
+                            AffineMotionEstimationOptions<SPLINEORDER> const & options =
                                                         AffineMotionEstimationOptions<>())
     }
     \endcode
@@ -587,21 +646,21 @@ estimateTranslation(MultiArrayView<2, T1, S1> const & src,
 doxygen_overloaded_function(template <...> void estimateSimilarityTransform)
 
 template <class SrcIterator, class SrcAccessor,
-          class DestIterator, class DestAccessor, 
+          class DestIterator, class DestAccessor,
           int SPLINEORDER>
-inline void 
+inline void
 estimateSimilarityTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                             DestIterator dul, DestIterator dlr, DestAccessor dest,
-                            Matrix<double> & affineMatrix, 
+                            Matrix<double> & affineMatrix,
                             AffineMotionEstimationOptions<SPLINEORDER> const & options)
 {
     detail::estimateAffineMotionImpl(sul, slr, src, dul, dlr, dest, affineMatrix,
                                      options, detail::SimilarityTransformEstimationFunctor());
 }
-             
-template <class SrcIterator, class SrcAccessor, 
+
+template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
-inline void 
+inline void
 estimateSimilarityTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                             DestIterator dul, DestIterator dlr, DestAccessor dest,
                             Matrix<double> & affineMatrix)
@@ -609,23 +668,23 @@ estimateSimilarityTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src,
     estimateSimilarityTransform(sul, slr, src, dul, dlr, dest,
                                 affineMatrix, AffineMotionEstimationOptions<>());
 }
-             
-template <class SrcIterator, class SrcAccessor, 
-          class DestIterator, class DestAccessor, 
+
+template <class SrcIterator, class SrcAccessor,
+          class DestIterator, class DestAccessor,
           int SPLINEORDER>
-inline void 
+inline void
 estimateSimilarityTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                             triple<DestIterator, DestIterator, DestAccessor> dest,
-                            Matrix<double> & affineMatrix, 
+                            Matrix<double> & affineMatrix,
                             AffineMotionEstimationOptions<SPLINEORDER> const & options)
 {
     estimateSimilarityTransform(src.first, src.second, src.third, dest.first, dest.second, dest.third,
                                 affineMatrix, options);
 }
 
-template <class SrcIterator, class SrcAccessor, 
+template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
-inline void 
+inline void
 estimateSimilarityTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                             triple<DestIterator, DestIterator, DestAccessor> dest,
                             Matrix<double> & affineMatrix)
@@ -634,22 +693,22 @@ estimateSimilarityTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                                 affineMatrix, AffineMotionEstimationOptions<>());
 }
 
-template <class T1, class S1, 
-          class T2, class S2, 
+template <class T1, class S1,
+          class T2, class S2,
           int SPLINEORDER>
-inline void 
+inline void
 estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
                             MultiArrayView<2, T2, S2> dest,
-                            Matrix<double> & affineMatrix, 
+                            Matrix<double> & affineMatrix,
                             AffineMotionEstimationOptions<SPLINEORDER> const & options)
 {
     estimateSimilarityTransform(srcImageRange(src), destImageRange(dest),
                                 affineMatrix, options);
 }
 
-template <class T1, class S1, 
+template <class T1, class S1,
           class T2, class S2>
-inline void 
+inline void
 estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
                             MultiArrayView<2, T2, S2> dest,
                             Matrix<double> & affineMatrix)
@@ -660,14 +719,45 @@ estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
 
 /********************************************************/
 /*                                                      */
-/*                estimateAffineTransform               */
+/*                  estimateAffineTransform             */
 /*                                                      */
 /********************************************************/
 
 /** \brief Estimate the optical flow between two images according to an affine transform model
            (e.g. translation, rotation, non-uniform scaling, and shearing).
 
-    Sorry, no \ref detailedDocumentation() available yet.
+    This function implements the algorithm described in
+
+    J.R. Bergen, P. Anandan, K.J. Hanna, R. Hingorani: <i>"Hierarchical model-based motion estimation"</i>, ECCV 1992
+
+    Specifically, it minimizes the squared loss between the images I at two consecutive time
+    points t-1 and t:
+    \f[ \min_{\theta} \sum_{\mathbf{x}} \left(I(\mathbf{x}, t) - I(\mathbf{x} - \mathbf{u}_{\theta}(\mathbf{x}), t-1)\right)^2
+    \f]
+    where \f$\mathbf{x}\f$ are the pixel coordinates and \f$\mathbf{u}_{\theta}(\mathbf{x})\f$
+    is an affine motion model parameterized by \f$\theta\f$. Since the objective is
+    non-linear, it is linearized by first-order Taylor expansion w.r.t. \f$\theta\f$,
+    and a local optimum is determined iteratively by the Gauss-Newton method. To handle
+    larger displacements, the algorithm employs a coarse-to-fine strategy, where the
+    motion is first estimated on downsampled versions of the images and then refined at
+    consecutively higher resolutions.
+
+    The algorithm's parameters can be controlled by the option object
+    \ref vigra::AffineMotionEstimationOptions. In particular, one can determine if
+    <ul>
+    <li> I in the objective refers to the original images (default) or their second
+    derivatives (<tt>options.useLaplacianPyramid()</tt> -- makes motion
+    estimation invariant against additive intensity offsets);</li>
+    <li> the highest pyramid level to be used
+    (<tt>options.highestPyramidLevel(h)</tt> -- images are downsampled to 2<sup>-h</sup> times their original size, default: h=4);</li>
+    <li> the number of Gauss-Newton iterations per resolution level
+    (<tt>options.iterationsPerLevel(i)</tt>, default: i=4);</li>
+    <li> the interpolation order to compute subpixel intensities \f$I(\mathbf{x} - \mathbf{u}_{\theta}(\mathbf{x}), t-1)\f$ (default: 2)
+    </ul>
+
+    The resulting affine model is stored in parameter <tt>affineMatrix</tt>, which
+    can be used by \ref affineWarpImage() to apply the transformation to time frame t-1.
+    See documentation there for the precise meaning of the matrix elements.
 
     <b> Declarations:</b>
 
@@ -677,14 +767,14 @@ estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
     pass 2D array views:
     \code
     namespace vigra {
-        template <class T1, class S1, 
-                  class T2, class S2, 
+        template <class T1, class S1,
+                  class T2, class S2,
                   int SPLINEORDER>
-        void 
+        void
         estimateAffineTransform(MultiArrayView<2, T1, S1> const & src,
                                 MultiArrayView<2, T2, S2> dest,
-                                Matrix<double> & affineMatrix, 
-                                AffineMotionEstimationOptions<SPLINEORDER> const & options = 
+                                Matrix<double> & affineMatrix,
+                                AffineMotionEstimationOptions<SPLINEORDER> const & options =
                                                    AffineMotionEstimationOptions<SPLINEORDER>());
     }
     \endcode
@@ -700,7 +790,7 @@ estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
         estimateAffineTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                             DestIterator dul, DestIterator dlr, DestAccessor dest,
                             Matrix<double> & affineMatrix,
-                            AffineMotionEstimationOptions<SPLINEORDER> const & options = 
+                            AffineMotionEstimationOptions<SPLINEORDER> const & options =
                                                         AffineMotionEstimationOptions<>())
     }
     \endcode
@@ -723,21 +813,21 @@ estimateSimilarityTransform(MultiArrayView<2, T1, S1> const & src,
 doxygen_overloaded_function(template <...> void estimateAffineTransform)
 
 template <class SrcIterator, class SrcAccessor,
-          class DestIterator, class DestAccessor, 
+          class DestIterator, class DestAccessor,
           int SPLINEORDER>
-inline void 
+inline void
 estimateAffineTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                         DestIterator dul, DestIterator dlr, DestAccessor dest,
-                        Matrix<double> & affineMatrix, 
+                        Matrix<double> & affineMatrix,
                         AffineMotionEstimationOptions<SPLINEORDER> const & options)
 {
     detail::estimateAffineMotionImpl(sul, slr, src, dul, dlr, dest, affineMatrix,
                                      options, detail::AffineTransformEstimationFunctor());
 }
-             
-template <class SrcIterator, class SrcAccessor, 
+
+template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
-inline void 
+inline void
 estimateAffineTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src,
                         DestIterator dul, DestIterator dlr, DestAccessor dest,
                         Matrix<double> & affineMatrix)
@@ -745,23 +835,23 @@ estimateAffineTransform(SrcIterator sul, SrcIterator slr, SrcAccessor src,
     estimateAffineTransform(sul, slr, src, dul, dlr, dest,
                             affineMatrix, AffineMotionEstimationOptions<>());
 }
-             
-template <class SrcIterator, class SrcAccessor, 
-          class DestIterator, class DestAccessor, 
+
+template <class SrcIterator, class SrcAccessor,
+          class DestIterator, class DestAccessor,
           int SPLINEORDER>
-inline void 
+inline void
 estimateAffineTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                         triple<DestIterator, DestIterator, DestAccessor> dest,
-                        Matrix<double> & affineMatrix, 
+                        Matrix<double> & affineMatrix,
                         AffineMotionEstimationOptions<SPLINEORDER> const & options)
 {
     estimateAffineTransform(src.first, src.second, src.third, dest.first, dest.second, dest.third,
                             affineMatrix, options);
 }
 
-template <class SrcIterator, class SrcAccessor, 
+template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
-inline void 
+inline void
 estimateAffineTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                         triple<DestIterator, DestIterator, DestAccessor> dest,
                         Matrix<double> & affineMatrix)
@@ -769,14 +859,14 @@ estimateAffineTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src,
     estimateAffineTransform(src.first, src.second, src.third, dest.first, dest.second, dest.third,
                             affineMatrix, AffineMotionEstimationOptions<>());
 }
-             
-template <class T1, class S1, 
-          class T2, class S2, 
+
+template <class T1, class S1,
+          class T2, class S2,
           int SPLINEORDER>
-inline void 
+inline void
 estimateAffineTransform(MultiArrayView<2, T1, S1> const & src,
                         MultiArrayView<2, T2, S2> dest,
-                        Matrix<double> & affineMatrix, 
+                        Matrix<double> & affineMatrix,
                         AffineMotionEstimationOptions<SPLINEORDER> const & options)
 {
     vigra_precondition(src.shape() == dest.shape(),
@@ -785,9 +875,9 @@ estimateAffineTransform(MultiArrayView<2, T1, S1> const & src,
                             affineMatrix, options);
 }
 
-template <class T1, class S1, 
+template <class T1, class S1,
           class T2, class S2>
-inline void 
+inline void
 estimateAffineTransform(MultiArrayView<2, T1, S1> const & src,
                         MultiArrayView<2, T2, S2> dest,
                         Matrix<double> & affineMatrix)
diff --git a/include/vigra/affine_registration_fft.hxx b/include/vigra/affine_registration_fft.hxx
new file mode 100644
index 0000000..64f16d6
--- /dev/null
+++ b/include/vigra/affine_registration_fft.hxx
@@ -0,0 +1,754 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2007-2014 by Benjamin Seppke                 */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_AFFINE_REGISTRATION_FFT_HXX
+#define VIGRA_AFFINE_REGISTRATION_FFT_HXX
+
+#include "mathutil.hxx"
+#include "matrix.hxx"
+#include "linear_solve.hxx"
+#include "tinyvector.hxx"
+#include "splineimageview.hxx"
+#include "imagecontainer.hxx"
+#include "multi_shape.hxx"
+#include "affinegeometry.hxx"
+#include "correlation.hxx"
+
+#include <cmath>
+
+namespace vigra {
+
+/** \addtogroup Registration Image Registration
+*/
+//@{
+
+/********************************************************/
+/*                                                      */
+/*               transformToPolarCoordinates            */
+/*                                                      */
+/********************************************************/
+
+/** \brief Transforms a given image to its (image-centered) polar coordinates representation.
+
+ This algorithm transforms a given image (by means of an spline image view) to its
+ image-centered polar coordinates reprensentation. The sampling of the polar coordinate system
+ is determined by the shape of the dest. image.
+
+ <b> Declarations:</b>
+
+ <b>\#include</b> \<vigra/affine_registration_fft.hxx\><br>
+ Namespace: vigra
+
+ pass 2D array views:
+ \code
+ namespace vigra {
+     template <class SplineImage,
+               class T1, class S1>
+     void
+     transformToPolarCoordinates(SplineImage const & src,
+                                 MultiArrayView<2, T1, S1> dest);
+ }
+ \endcode
+
+ \deprecatedAPI{estimateTranslation}
+     pass \ref ImageIterators and \ref DataAccessors :
+     \code
+     namespace vigra {
+         template <class SplineImage,
+                   class DestIterator, class DestAccessor>
+         void
+         transformToPolarCoordinates(SplineImage const & src,
+                                     DestIterator dul, DestIterator dlr, DestAccessor dest)
+     }
+     \endcode
+     use argument objects in conjunction with \ref ArgumentObjectFactories :
+     \code
+         namespace vigra {
+             template <class SplineImage,
+                       class DestIterator, class DestAccessor>
+             void
+             transformToPolarCoordinates(SplineImage const & src,
+                                 triple<DestIterator, DestIterator, DestAccessor> dest)
+        }
+     \endcode
+ \deprecatedEnd
+*/
+
+template <class SplineImage,
+          class DestIterator, class DestAccessor>
+void
+transformToPolarCoordinates(SplineImage const & src,
+                            DestIterator d_ul, DestIterator d_lr, DestAccessor d_acc)
+{
+    typename DestIterator::difference_type d_shape = (d_lr - d_ul);
+
+    int s_w = src.width(),
+        s_h = src.height();
+
+    int s_size = min(s_w, s_h);
+
+    int d_w = d_shape.x,
+        d_h = d_shape.y;
+
+    double r_max = s_size / 2.0;
+
+    DestIterator yd = d_ul;
+    DestIterator xd = yd;
+
+    for (int t_step = 0; t_step < d_h; t_step++, yd.y++)
+    {
+        xd = yd;
+        for (int r_step = 0; r_step < d_w; r_step++, xd.x++)
+        {
+            double theta = 2.0 * M_PI * double(t_step) / double(d_h);
+            double r = r_max * double(r_step) / double(d_w);
+            double u = r * cos(theta) + r_max;
+            double v = r * -sin(theta) + r_max;
+
+            if (   u >= 0 && u < s_size
+                && v >= 0 && v < s_size)
+            {
+                d_acc.set(src(u, v), xd);
+            }
+        }
+    }
+}
+
+template <class SplineImage,
+          class DestIterator, class DestAccessor>
+inline void
+transformToPolarCoordinates(SplineImage const & src,
+                            vigra::triple<DestIterator, DestIterator, DestAccessor> dest)
+{
+    transformToPolarCoordinates(src, dest.first, dest.second, dest.third);
+}
+
+template <class SplineImage,
+          class T1, class S1>
+void
+transformToPolarCoordinates(SplineImage const & src,
+                            MultiArrayView<2, T1, S1> dest)
+{
+    transformToPolarCoordinates(src, srcImageRange(dest));
+}
+
+
+
+
+namespace detail
+{
+    template <class SrcIterator, class SrcAccessor,
+              class DestIterator, class DestAccessor>
+    void
+    maximumFastNCC(SrcIterator s_ul, SrcIterator s_lr, SrcAccessor s_acc,
+                   DestIterator d_ul, DestIterator d_lr, DestAccessor d_acc,
+                   TinyVector<int,2> & position,
+                   double & correlation_coefficent)
+    {
+        typename DestIterator::difference_type s_shape = s_lr - s_ul;
+        typename DestIterator::difference_type d_shape = d_lr - d_ul;
+
+        MultiArray<2, float> src(s_shape.x, s_shape.y), dest(d_shape.x, d_shape.y), ncc(d_shape.x, d_shape.y);
+        BasicImageView<float> src_view = makeBasicImageView(src);
+        BasicImageView<float> dest_view = makeBasicImageView(dest);
+
+        copyImage(srcIterRange(s_ul, s_lr, s_acc), destImage(src_view));
+        copyImage(srcIterRange(d_ul, d_lr, d_acc), destImage(dest_view));
+
+        fastNormalizedCrossCorrelation(dest, src, ncc);
+
+        int max_x = 0;
+        int max_y = 0;
+        float val = 0.0;
+        float max_val = -1.0;
+
+        for (int y = 0; y < ncc.height()-s_shape.y; y++)
+        {
+            for (int x = 0; x < ncc.width()-s_shape.x; x++)
+            {
+                val = ncc(x+s_shape.x/2, y+s_shape.y/2);
+
+                if (val > max_val)
+                {
+                    max_x = x;
+                    max_y = y;
+                    max_val = val;
+                }
+            }
+        }
+
+        position[0] = max_x;
+        position[1] = max_y;
+
+        correlation_coefficent = max_val;
+    }
+
+    template <class SrcIterator, class SrcAccessor,
+              class DestIterator, class DestAccessor>
+    inline void
+    maximumFastNCC(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                   triple<DestIterator, DestIterator, DestAccessor> dest,
+                   TinyVector<int,2> & position,
+                   double & correlation_coefficent)
+    {
+        maximumFastNCC(src.first, src.second, src.third,
+                       dest.first, dest.second, dest.third,
+                       position,
+                       correlation_coefficent);
+    }
+
+    template <class SrcIterator, class SrcAccessor,
+              class DestIterator, class DestAccessor>
+    void fourierLogAbsSpectrumInPolarCoordinates(SrcIterator s_ul, SrcIterator s_lr, SrcAccessor s_acc,
+                                                 DestIterator d_ul, DestIterator d_lr, DestAccessor d_acc)
+    {
+        using namespace vigra;
+
+        typename SrcIterator::difference_type shape = s_lr - s_ul;
+
+        FFTWComplexImage fourier(shape);
+        FImage           fft_mag(shape);
+
+        fourierTransform(srcIterRange(s_ul, s_lr, s_acc), destImage(fourier));
+        moveDCToCenter(srcImageRange(fourier, FFTWMagnitudeAccessor<>()), destImage(fft_mag));
+
+        vigra::SplineImageView<2, double> spl(srcImageRange(fft_mag));
+
+        transformToPolarCoordinates(spl,
+                                    destIterRange(d_ul, d_lr, d_acc));
+
+        transformImage(srcIterRange(d_ul,d_lr,d_acc), destIter(d_ul,d_acc), log(abs(functor::Arg1())));
+    }
+
+    template <class SrcIterator, class SrcAccessor,
+              class DestIterator, class DestAccessor>
+    void fourierLogAbsSpectrumInPolarCoordinates(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                                                 triple<DestIterator, DestIterator, DestAccessor> dest)
+    {
+        fourierLogAbsSpectrumInPolarCoordinates(src.first, src.second, src.third, dest.first, dest.second, dest.third);
+    }
+} //namespace detail
+
+
+
+
+/********************************************************/
+/*                                                      */
+/*                 estimateGlobalRotation               */
+/*                                                      */
+/********************************************************/
+
+/** \brief Estimate the rotation between two images by means of a normalized cross correlation matching of the FFT spectra.
+
+ This algorithm uses the fast normalized cross correlation to determine a global rotation
+ between two images (from image2 to image1). To derive the rotation, the algorithm performs the following steps:
+ <ol>
+    <li>Transforming both images to the frequency domain using FFTW</li>
+    <li>Create LogAbs PolarCoordinate representations for each spectrum.</li>
+    <li>Determining the final Rotation by performing a fast normalized cross correlation
+        based on the polar representations.</li>
+ </ol>
+ The images are cropped to the corresponding images center-squared before the estimation
+ takes place.
+
+ <b> Declarations:</b>
+
+ <b>\#include</b> \<vigra/affine_registration_fft.hxx\><br>
+ Namespace: vigra
+
+ pass 2D array views:
+ \code
+ namespace vigra {
+     template <class T1, class S1,
+               class T2, class S2>
+     void
+     estimateGlobalRotation(MultiArrayView<2, T1, S1> const & src,
+                            MultiArrayView<2, T2, S2> dest,
+                            Matrix<double> & affineMatrix,
+                            double & correlation_coefficent);
+ }
+ \endcode
+
+ \deprecatedAPI{estimateGlobalRotation}
+     pass \ref ImageIterators and \ref DataAccessors :
+     \code
+     namespace vigra {
+         template <class SrcIterator, class SrcAccessor,
+                   class DestIterator, class DestAccessor>
+         void
+         estimateGlobalRotation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
+                                DestIterator dul, DestIterator dlr, DestAccessor dest,
+                                Matrix<double> & affineMatrix,
+                                double & correlation_coefficent)
+     }
+     \endcode
+     use argument objects in conjunction with \ref ArgumentObjectFactories :
+     \code
+         namespace vigra {
+             template <class SrcIterator, class SrcAccessor,
+                       class DestIterator, class DestAccessor>
+             void
+             estimateGlobalRotation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                                    triple<DestIterator, DestIterator, DestAccessor> dest,
+                                    Matrix<double> & affineMatrix,
+                                    double & correlation_coefficent)
+        }
+     \endcode
+ \deprecatedEnd
+*/
+doxygen_overloaded_function(template <...> void estimateGlobalRotation)
+
+template <class SrcIterator, class SrcAccessor,
+          class DestIterator, class DestAccessor>
+void
+estimateGlobalRotation(SrcIterator s_ul, SrcIterator s_lr, SrcAccessor s_acc,
+                        DestIterator d_ul, DestIterator d_lr, DestAccessor d_acc,
+                       Matrix<double> & affineMatrix,
+                       double & correlation_coefficient)
+{
+    //determine squared centers of both images without consuming any additional memory!
+    typename SrcIterator::difference_type s_shape = s_lr - s_ul;
+    Diff2D s2_shape(min(s_shape.x, s_shape.y),min(s_shape.x, s_shape.y));
+    Diff2D s2_offset = (s_shape-s2_shape)/2;
+
+    typename DestIterator::difference_type d_shape = d_lr - d_ul;
+    Diff2D d2_shape(min(d_shape.x, d_shape.y),min(d_shape.x, d_shape.y));
+    Diff2D d2_offset = (d_shape-d2_shape)/2;
+
+    //Determine Shape for united polar coordinate representation
+    Diff2D mean_shape = (s_shape + d_shape)/2;
+
+    int size = min(mean_shape.x, mean_shape.y);
+    if(size %2 == 0)
+        size++;
+
+    const int pc_w = size,
+              pc_h = size*6+1;
+
+
+    DImage s_polCoords(pc_w, pc_h/2),
+           d_polCoords(pc_w, pc_h),
+           ncc(pc_w, pc_h);
+
+    detail::fourierLogAbsSpectrumInPolarCoordinates(srcIterRange(s_ul+s2_offset, s_ul+s2_offset+s2_shape, s_acc),
+                                                    destImageRange(d_polCoords));
+    copyImage(srcIterRange(d_polCoords.upperLeft(), d_polCoords.upperLeft() + vigra::Diff2D(pc_w, pc_h/2), d_polCoords.accessor()),
+              destImage(s_polCoords));
+
+    detail::fourierLogAbsSpectrumInPolarCoordinates(srcIterRange(d_ul+d2_offset, d_ul+d2_offset+d2_shape, d_acc),
+                                                    destImageRange(d_polCoords));
+
+    //Basic Cross correlation is assumed to be faster here, as there are only pc_h comparisons possible...
+    normalizedCrossCorrelation(srcImageRange(d_polCoords), srcImageRange(s_polCoords), destImage(ncc));
+
+    int max_idx = 0;
+    double max_val = -1;
+
+    const int x=pc_w/2;
+    double val;
+
+    //Only look at a stripe for the maximum angle of rotation
+    //at the image center, at find the best fitting angle...
+    for (int y=0; y<pc_h/2; y++)
+    {
+        val = ncc(x,y+pc_h/4);
+
+        if (val > max_val)
+        {
+            max_idx = y;
+            max_val = val;
+        }
+    }
+
+    double theta = double(max_idx) / pc_h * 360.0;
+
+    affineMatrix = rotationMatrix2DDegrees(theta, vigra::TinyVector<double,2>(s_shape.x/2.0, s_shape.y/2.0));
+    correlation_coefficient = max_val;
+}
+
+template <class SrcIterator, class SrcAccessor,
+          class DestIterator, class DestAccessor>
+inline void
+estimateGlobalRotation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                        triple<DestIterator, DestIterator, DestAccessor> dest,
+                        Matrix<double> & affineMatrix,
+                        double & correlation_coefficient)
+{
+    estimateGlobalRotation(src.first, src.second, src.third,
+                            dest.first, dest.second, dest.third,
+                           affineMatrix,
+                           correlation_coefficient);
+}
+
+template <class T1, class S1,
+          class T2, class S2>
+inline void
+estimateGlobalRotation(MultiArrayView<2, T1, S1> const & src,
+                       MultiArrayView<2, T2, S2> dest,
+                       Matrix<double> & affineMatrix,
+                       double & correlation_coefficent)
+{
+    estimateGlobalRotation(srcImageRange(src),
+                           destImageRange(dest),
+                           affineMatrix,
+                           correlation_coefficent);
+}
+
+/********************************************************/
+/*                                                      */
+/*               estimateGlobalTranslation              */
+/*                                                      */
+/********************************************************/
+
+/** \brief Estimate the translation between two images by means of a normalized cross correlation matching.
+
+ This algorithm uses the fast normalized cross correlation to determine a global translation
+ between two images (from image2 to image1). To derive the translation, the algorithm consists of differents steps:
+ <ol>
+    <li>Separation of the second image<br/>
+        The second image (the one, for which the translation shall be determined) is cut into five
+        subregions: UpperLeft, UpperRight, Center, LowerLeft and LowerRight, each of 1/4 the size of
+        the original image. Using a border > 0 results in (all) overlapping regions.</li>
+    <li>Cross-Correlation of the subimages to the first image<br/>
+        The subimages are normalized cross-correlated to the (complete) first image.
+        The resulting maximum-likelihood translations and the correlation coefficients are stored for the next step.</li>
+    <li>Determining the final Translation by voting<br/>
+        Each correlation vector gets one vote at the beginning. For each equality of derived motion vectors,
+        the voting to these vectors is incremented. If the maximum number of votes is larger than 1, the vector with the
+        most votes is chosen. If the maximum number of votes is 1, the vector with the maximum likelihood is choosen.</li>
+ </ol>
+ <b> Declarations:</b>
+
+ <b>\#include</b> \<vigra/affine_registration_fft.hxx\><br>
+ Namespace: vigra
+
+ pass 2D array views:
+ \code
+ namespace vigra {
+     template <class T1, class S1,
+               class T2, class S2>
+     void
+     estimateGlobalTranslation(MultiArrayView<2, T1, S1> const & src,
+                               MultiArrayView<2, T2, S2> dest,
+                               Matrix<double> & affineMatrix,
+                               double & correlation_coefficent,
+                               Diff2D border = Diff2D(0,0));
+ }
+ \endcode
+
+ \deprecatedAPI{estimateGlobalTranslation}
+     pass \ref ImageIterators and \ref DataAccessors :
+     \code
+     namespace vigra {
+         template <class SrcIterator, class SrcAccessor,
+                   class DestIterator, class DestAccessor>
+         void
+         estimateGlobalTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
+                                   DestIterator dul, DestIterator dlr, DestAccessor dest,
+                                   Matrix<double> & affineMatrix,
+                                   double & correlation_coefficent,
+                                   Diff2D border = Diff2D(0,0))
+     }
+     \endcode
+     use argument objects in conjunction with \ref ArgumentObjectFactories :
+     \code
+         namespace vigra {
+             template <class SrcIterator, class SrcAccessor,
+                       class DestIterator, class DestAccessor>
+             void
+             estimateGlobalTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                                       triple<DestIterator, DestIterator, DestAccessor> dest,
+                                       Matrix<double> & affineMatrix,
+                                       double & correlation_coefficent,
+                                       Diff2D border = Diff2D(0,0))
+        }
+     \endcode
+ \deprecatedEnd
+*/
+doxygen_overloaded_function(template <...> void estimateGlobalTranslation)
+
+template <class SrcIterator, class SrcAccessor,
+          class DestIterator, class DestAccessor>
+void estimateGlobalTranslation(SrcIterator    s_ul, SrcIterator  s_lr, SrcAccessor  s_acc,
+                               DestIterator d_ul, DestIterator d_lr, DestAccessor d_acc,
+                               Matrix<double> & affine_matrix,
+                               double & correlation_coefficent,
+                               Diff2D border = Diff2D(0,0))
+{
+    typename SrcIterator::difference_type s_shape = s_lr - s_ul;
+    typename DestIterator::difference_type d_shape = d_lr - d_ul;
+
+    //determine matrix by using 5 quater-matches and a maximum likelihood decision:
+    Diff2D q_shape = (s_shape - border - border)/2;
+    if (q_shape.x % 2 == 0)        q_shape.x--;
+    if (q_shape.y % 2 == 0)        q_shape.y--;
+
+    Diff2D q_offsets[5];
+    q_offsets[0] = border;
+    q_offsets[1] = Diff2D(s_shape.x, 0)/2 + border;
+    q_offsets[2] = s_shape/4;
+    q_offsets[3] = Diff2D(0, s_shape.y)/2 + border;
+    q_offsets[4] = s_shape/2 + border;
+
+    TinyVector<int,2> translation_vectors[5];
+    double translation_correlations[5] = {0.0,0.0,0.0,0.0,0.0};
+    int translation_votes[5] = {1,1,1,1,1};
+
+    int max_corr_idx=0;
+
+    for (int q=0; q!=5; q++)
+    {
+        Diff2D offset = q_offsets[q];
+
+        //we are searching a transformation from img2 ->  transformed image1, thus we switch dest and tmp
+        detail::maximumFastNCC(srcIterRange(d_ul+offset, d_ul+offset+q_shape, d_acc),
+                               srcIterRange(s_ul, s_lr, s_acc),
+                               translation_vectors[q],
+                               translation_correlations[q]);
+
+        translation_vectors[q] = translation_vectors[q] - TinyVector<int,2>(offset);
+
+        if(translation_correlations[q] > translation_correlations[max_corr_idx])
+        {
+            max_corr_idx=q;
+        }
+
+        for (int q_old=0; q_old!=q; q_old++)
+        {
+            if (translation_vectors[q] == translation_vectors[q_old])
+            {
+                translation_votes[q_old]++;
+            }
+        }
+    }
+
+    int max_votes_idx=0;
+
+    for (int q=0; q!=5; q++)
+    {
+        if(translation_votes[q] > translation_votes[max_votes_idx])
+        {
+            max_votes_idx=q;
+        }
+    }
+
+    int best_idx=0;
+    if(translation_votes[max_votes_idx] > 1)
+    {
+        best_idx = max_votes_idx;
+    }
+    else
+    {
+        best_idx = max_corr_idx;
+    }
+
+    affine_matrix = translationMatrix2D(translation_vectors[best_idx]);
+    correlation_coefficent = translation_correlations[best_idx];
+}
+
+template <class SrcIterator, class SrcAccessor,
+          class DestIterator, class DestAccessor>
+inline void
+estimateGlobalTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                          triple<DestIterator, DestIterator, DestAccessor> dest,
+                          Matrix<double> & affineMatrix,
+                          double & correlation_coefficent,
+                          Diff2D border = Diff2D(0,0))
+{
+    estimateGlobalTranslation(src.first, src.second, src.third,
+                              dest.first, dest.second, dest.third,
+                              affineMatrix,
+                              correlation_coefficent,
+                              border);
+}
+
+template <class T1, class S1,
+          class T2, class S2>
+inline void
+estimateGlobalTranslation(MultiArrayView<2, T1, S1> const & src,
+                          MultiArrayView<2, T2, S2> dest,
+                          Matrix<double> & affineMatrix,
+                          double & correlation_coefficent,
+                          Diff2D border = Diff2D(0,0))
+{
+    estimateGlobalTranslation(srcImageRange(src),
+                              destImageRange(dest),
+                              affineMatrix,
+                              correlation_coefficent,
+                              border);
+}
+
+/********************************************************/
+/*                                                      */
+/*              estimateGlobalRotationTranslation       */
+/*                                                      */
+/********************************************************/
+
+/** \brief Estimate the (global) rotation and translation between two images by means a normalized cross correlation matching.
+
+ This algorithm use the functions \ref estimateGlobalRotation() and
+ \ref estimateGlobalTranslation() to estimate a matrix which describes
+ the global rotation and translation from the second to the first image.
+
+ <b> Declarations:</b>
+
+ <b>\#include</b> \<vigra/affine_registration_fft.hxx\><br>
+ Namespace: vigra
+
+ pass 2D array views:
+ \code
+ namespace vigra {
+     template <class T1, class S1,
+               class T2, class S2>
+     void
+     estimateGlobalRotationTranslation(MultiArrayView<2, T1, S1> const & src,
+                                       MultiArrayView<2, T2, S2> dest,
+                                       Matrix<double> & affineMatrix,
+                                       double & rotation_correlation,
+                                       double & translation_correlation,
+                                       Diff2D border = Diff2D(0,0));
+ }
+ \endcode
+
+ \deprecatedAPI{estimateGlobalRotationTranslation}
+     pass \ref ImageIterators and \ref DataAccessors :
+     \code
+     namespace vigra {
+         template <class SrcIterator, class SrcAccessor,
+                   class DestIterator, class DestAccessor>
+         void
+         estimateGlobalRotationTranslation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
+                                           DestIterator dul, DestIterator dlr, DestAccessor dest,
+                                           Matrix<double> & affineMatrix,
+                                           double & rotation_correlation,
+                                           double & translation_correlation,
+                                           Diff2D border = Diff2D(0,0))
+     }
+     \endcode
+     use argument objects in conjunction with \ref ArgumentObjectFactories :
+     \code
+         namespace vigra {
+             template <class SrcIterator, class SrcAccessor,
+                       class DestIterator, class DestAccessor>
+             void
+             estimateGlobalRotationTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                                               triple<DestIterator, DestIterator, DestAccessor> dest,
+                                               Matrix<double> & affineMatrix,
+                                               double & rotation_correlation,
+                                               double & translation_correlation,
+                                               Diff2D border = Diff2D(0,0))
+        }
+     \endcode
+ \deprecatedEnd
+*/
+doxygen_overloaded_function(template <...> void estimateGlobalRotationTranslation)
+template <class SrcIterator, class SrcAccessor,
+       class DestIterator, class DestAccessor>
+void
+estimateGlobalRotationTranslation(SrcIterator s_ul, SrcIterator s_lr, SrcAccessor s_acc,
+                                  DestIterator d_ul, DestIterator d_lr, DestAccessor d_acc,
+                                  Matrix<double> & affineMatrix,
+                                  double & rotation_correlation,
+                                  double & translation_correlation,
+                                  Diff2D border = Diff2D(0,0))
+{
+    typename SrcIterator::difference_type s_shape = s_lr - s_ul;
+    typename DestIterator::difference_type d_shape = d_lr - d_ul;
+
+    //First step: Estimate rotation from img2 -> img1.
+    Matrix<double> rotation_matrix;
+    estimateGlobalRotation(srcIterRange(s_ul+border, s_lr-border, s_acc),
+                           srcIterRange(d_ul+border, d_lr-border, d_acc),
+                           rotation_matrix,
+                           rotation_correlation);
+
+    //Second step: correct image according to the estimated rotation:
+    FImage tmp(d_shape);
+    SplineImageView<3, double> spl(srcIterRange(s_ul, s_lr, s_acc));
+    affineWarpImage(spl, destImageRange(tmp), rotation_matrix);
+
+    //Third step: find rotation between temp image (of step 2) and dest:
+    Matrix<double> translation_matrix;
+    estimateGlobalTranslation(srcImageRange(tmp),
+                                 srcIterRange(d_ul, d_lr, d_acc),
+                                 translation_matrix,
+                              translation_correlation,
+                              border);
+
+    affineMatrix = rotation_matrix * translation_matrix;
+}
+
+template <class SrcIterator, class SrcAccessor,
+          class DestIterator, class DestAccessor>
+inline void
+estimateGlobalRotationTranslation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                                  triple<DestIterator, DestIterator, DestAccessor> dest,
+                                  Matrix<double> & affineMatrix,
+                                  double & rotation_correlation,
+                                  double & translation_correlation,
+                                  Diff2D border = Diff2D(0,0))
+{
+    estimateGlobalRotationTranslation(src.first, src.second, src.third,
+                                      dest.first, dest.second, dest.third,
+                                      affineMatrix,
+                                      rotation_correlation,
+                                      translation_correlation,
+                                      border);
+}
+
+template <class T1, class S1,
+          class T2, class S2>
+inline void
+estimateGlobalRotationTranslation(MultiArrayView<2, T1, S1> const & src,
+                                  MultiArrayView<2, T2, S2> dest,
+                                  Matrix<double> & affineMatrix,
+                                  double & rotation_correlation,
+                                  double & translation_correlation,
+                                  Diff2D border = Diff2D(0,0))
+{
+    estimateGlobalRotationTranslation(srcImageRange(src),
+                                      destImageRange(dest),
+                                      affineMatrix,
+                                      rotation_correlation,
+                                      translation_correlation,
+                                      border);
+}
+
+//@}
+
+} // namespace vigra
+
+
+#endif /* VIGRA_AFFINE_REGISTRATION_FFT_HXX */
diff --git a/include/vigra/algorithm.hxx b/include/vigra/algorithm.hxx
index c9440d4..6300b32 100644
--- a/include/vigra/algorithm.hxx
+++ b/include/vigra/algorithm.hxx
@@ -179,7 +179,8 @@ Iterator argMaxIf(Iterator first, Iterator last, UnaryFunctor condition)
     /** \brief Fill an array with a sequence of numbers.
     
         The sequence starts at \a start and is incremented with \a step. Default start
-        and stepsize are 0 and 1 respectively.
+        and stepsize are 0 and 1 respectively. This is a generalization of function
+        <tt>std::iota()</tt> in C++11.
         
         <b> Declaration:</b>
 
@@ -213,8 +214,7 @@ void linearSequence(Iterator first, Iterator last, Value start, Value step)
 template <class Iterator, class Value>
 void linearSequence(Iterator first, Iterator last, Value start)
 {
-    for(; first != last; ++first, ++start)
-        *first = start;
+    linearSequence(first, last, start, NumericTraits<Value>::one());
 }
 
 template <class Iterator>
@@ -291,13 +291,13 @@ inspectSequence(InputIterator first, InputIterator last, Functor & f)
    
 namespace detail {
 
-template <class Iterator, class Compare>
+template <class ArrayLike, class Compare>
 struct IndexCompare
 {
-    Iterator i_;
+    ArrayLike i_;
     Compare c_;
     
-    IndexCompare(Iterator i, Compare c)
+    IndexCompare(ArrayLike i, Compare c)
     : i_(i),
       c_(c)
     {}
@@ -311,11 +311,80 @@ struct IndexCompare
 
 } // namespace detail
 
+    /** \brief Create a compare functor for indirect sort.
+    
+        Indirect sorting refers to the situation where you have an array holding
+        data and another array holding indices referencing the first array,
+        and you want to sort the index array according to some property of
+        the data array without changing the data array itself. The factory
+        function <tt>makeIndexComparator()</tt> creates a sorting predicate
+        for this task, given a sorting predicate for the data array.
+        
+        \see vigra::indexSort(), vigra::applyPermutation()
+        
+        <b>Usage:</b>
+
+        <b>\#include</b> \<vigra/algorithm.hxx\><br>
+        Namespace: vigra
+        
+        \code
+        const std:vector<double> data(...);  // data is immutable
+        
+        std::vector<int> index(data.size());
+        std::iota(index.begin(), index.end());
+        
+        // sort the indices such that data[index[k]] is an ascending sequence in k
+        std::sort(index.begin(), index.end(), makeIndexComparator(data));
+        \endcode
+        
+        <b>Declarations:</b>
+
+        \code
+        namespace vigra {
+            // compare using std::less
+            template <class ArrayLike>
+            auto makeIndexComparator(ArrayLike a);
+
+            // compare using functor Compare
+            template <class ArrayLike, class Compare>
+            auto makeIndexComparator(ArrayLike a, Compare c);
+        }
+        \endcode
+    */
+template <class ArrayLike, class Compare>
+inline detail::IndexCompare<ArrayLike, Compare>
+makeIndexComparator(ArrayLike a, Compare c)
+{
+    return detail::IndexCompare<ArrayLike, Compare>(a, c);
+}
+
+template <class ArrayLike>
+inline detail::IndexCompare<ArrayLike, std::less<typename ArrayLike::value_type> >
+makeIndexComparator(ArrayLike a)
+{
+    typedef std::less<typename ArrayLike::value_type> Compare;
+    return detail::IndexCompare<ArrayLike, Compare>(a, Compare());
+}
+
     /** \brief Return the index permutation that would sort the input array.
     
         To actually sort an array according to the ordering thus determined, use 
         \ref applyPermutation().
         
+        <b>Usage:</b>
+
+        <b>\#include</b> \<vigra/algorithm.hxx\><br>
+        Namespace: vigra
+        
+        \code
+        const std:vector<double> data(...);  // data is immutable
+        
+        std::vector<int> index(data.size());
+        
+        // arrange indices such that data[index[k]] is an ascending sequence in k
+        indexSort(data.begin(), data.end(), index.begin());
+        \endcode
+        
         <b> Declarations:</b>
 
         \code
@@ -346,8 +415,7 @@ void indexSort(Iterator first, Iterator last, IndexIterator index_first, Compare
 {
     int size = last - first;
     linearSequence(index_first, index_first+size);
-    std::sort(index_first, index_first+size, 
-              detail::IndexCompare<Iterator, Compare>(first, c));
+    std::sort(index_first, index_first+size, makeIndexComparator(first, c));
 }
 
 template <class Iterator, class IndexIterator>
diff --git a/include/vigra/any.hxx b/include/vigra/any.hxx
new file mode 100644
index 0000000..21d95f0
--- /dev/null
+++ b/include/vigra/any.hxx
@@ -0,0 +1,407 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2014-2015 by Ullrich Koethe                  */
+/*                                                                      */
+/*    This file is part of the VIGRA2 computer vision library.          */
+/*    The VIGRA2 Website is                                             */
+/*        http://ukoethe.github.io/vigra2                               */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#pragma once
+
+#ifndef VIGRA_ANY_HXX
+#define VIGRA_ANY_HXX
+
+#include "config.hxx"
+#include "error.hxx"
+#include <typeinfo>
+#include <type_traits>
+
+namespace vigra {
+
+namespace detail {
+
+struct AnyHandle
+{
+    AnyHandle() {}
+    virtual ~AnyHandle() {}
+    virtual const std::type_info & type() const = 0;
+    virtual AnyHandle * clone() const = 0;
+    virtual bool equal(AnyHandle const *) const = 0;
+
+  private:
+    AnyHandle(AnyHandle const &);
+    AnyHandle & operator=(AnyHandle const &);
+};
+
+template <class T>
+struct TypedAnyHandle
+: public AnyHandle
+{
+    T value_;
+
+    TypedAnyHandle(T const & t)
+    : value_(t)
+    {}
+
+    const std::type_info & type() const
+    {
+        return typeid(T);
+    }
+
+    AnyHandle * clone() const
+    {
+        return new TypedAnyHandle(value_);
+    }
+
+    bool equal(AnyHandle const * h) const
+    {
+        TypedAnyHandle const * ptr = dynamic_cast<TypedAnyHandle const *>(h);
+        return ptr != 0 && value_ == ptr->value_;
+    }
+};
+
+struct ConvertibleAnyHandle
+: public AnyHandle
+{
+    template <class T>
+    struct TypeTag {};
+
+    ConvertibleAnyHandle() {}
+
+    virtual signed char      cast(TypeTag<signed char>) const = 0;
+    virtual signed short     cast(TypeTag<signed short>) const = 0;
+    virtual signed int       cast(TypeTag<signed int>) const = 0;
+    virtual signed long      cast(TypeTag<signed long>) const = 0;
+    virtual signed long long cast(TypeTag<signed long long>) const = 0;
+
+    virtual unsigned char      cast(TypeTag<unsigned char>) const = 0;
+    virtual unsigned short     cast(TypeTag<unsigned short>) const = 0;
+    virtual unsigned int       cast(TypeTag<unsigned int>) const = 0;
+    virtual unsigned long      cast(TypeTag<unsigned long>) const = 0;
+    virtual unsigned long long cast(TypeTag<unsigned long long>) const = 0;
+
+    virtual float       cast(TypeTag<float>) const = 0;
+    virtual double      cast(TypeTag<double>) const = 0;
+    virtual long double cast(TypeTag<long double>) const = 0;
+};
+
+#define VIGRA_ANY_OF_CONVERTIBLE(TYPE) \
+template <> \
+struct TypedAnyHandle<TYPE> \
+: public ConvertibleAnyHandle \
+{ \
+    TYPE value_; \
+    \
+    TypedAnyHandle(TYPE const & t) \
+    : value_(t) \
+    {} \
+    \
+    const std::type_info & type() const \
+    { \
+        return typeid(value_); \
+    } \
+    \
+    AnyHandle * clone() const \
+    { \
+        return new TypedAnyHandle(value_); \
+    } \
+    \
+    bool equal(AnyHandle const * h) const \
+    { \
+        TypedAnyHandle const * ptr = dynamic_cast<TypedAnyHandle const *>(h); \
+        return ptr != 0 && value_ == ptr->value_; \
+    } \
+    \
+    virtual signed char      cast(TypeTag<signed char>) const \
+    { return static_cast<signed char>(value_); } \
+    virtual signed short     cast(TypeTag<signed short>) const \
+    { return static_cast<signed short>(value_); } \
+    virtual signed int       cast(TypeTag<signed int>) const \
+    { return static_cast<signed int>(value_); } \
+    virtual signed long      cast(TypeTag<signed long>) const \
+    { return static_cast<signed long>(value_); } \
+    virtual signed long long cast(TypeTag<signed long long>) const \
+    { return static_cast<signed long long>(value_); } \
+    \
+    virtual unsigned char      cast(TypeTag<unsigned char>) const \
+    { return static_cast<unsigned char>(value_); } \
+    virtual unsigned short     cast(TypeTag<unsigned short>) const \
+    { return static_cast<unsigned short>(value_); } \
+    virtual unsigned int       cast(TypeTag<unsigned int>) const \
+    { return static_cast<unsigned int>(value_); } \
+    virtual unsigned long      cast(TypeTag<unsigned long>) const \
+    { return static_cast<unsigned long>(value_); } \
+    virtual unsigned long long cast(TypeTag<unsigned long long>) const \
+    { return static_cast<unsigned long long>(value_); } \
+    \
+    virtual float       cast(TypeTag<float>) const \
+    { return static_cast<float>(value_); } \
+    virtual double      cast(TypeTag<double>) const \
+    { return static_cast<double>(value_); } \
+    virtual long double cast(TypeTag<long double>) const \
+    { return static_cast<long double>(value_); } \
+};
+
+VIGRA_ANY_OF_CONVERTIBLE(signed char     )
+VIGRA_ANY_OF_CONVERTIBLE(signed short    )
+VIGRA_ANY_OF_CONVERTIBLE(signed int      )
+VIGRA_ANY_OF_CONVERTIBLE(signed long     )
+VIGRA_ANY_OF_CONVERTIBLE(signed long long)
+
+VIGRA_ANY_OF_CONVERTIBLE(unsigned char     )
+VIGRA_ANY_OF_CONVERTIBLE(unsigned short    )
+VIGRA_ANY_OF_CONVERTIBLE(unsigned int      )
+VIGRA_ANY_OF_CONVERTIBLE(unsigned long     )
+VIGRA_ANY_OF_CONVERTIBLE(unsigned long long)
+
+VIGRA_ANY_OF_CONVERTIBLE(float      )
+VIGRA_ANY_OF_CONVERTIBLE(double     )
+VIGRA_ANY_OF_CONVERTIBLE(long double)
+
+#undef VIGRA_ANY_OF_CONVERTIBLE
+
+} // namespace detail
+
+    /** \brief Typesafe storage of arbitrary values.
+
+        Items are always stored by value, but it is of course possible
+        to store pointers and smart pointers.
+
+        <b>Usage:</b>
+
+        \code
+        Any a(10);  // store integer '10'
+
+        assert(a.is_type<int>());
+        assert(a.is_convertible<int>());
+
+        // retrieve the stored value (throws when types don't match)
+        assert(a.get<int>() == 10);
+
+        // change the value
+        a = 20;
+        assert(a.get<int>() == 20);
+
+        // values of arithmetic types can be converted into each other
+        // (this is currently not implemented for other types)
+        assert(a.is_convewrtible<double>());
+        assert(a.cast<double>() == 20.0);
+
+        // delete the stored value
+        a.release();
+        assert(a.empty());
+        assert(a == false);
+
+        // store a shared_ptr
+        typedef std::shared_ptr<int> Ptr;
+        Any p(Ptr(new int(5))), q = p;
+        assert(*(p.get<Ptr>()) == 5);
+        // the addresses of the elements in p and q are the same
+        assert(p.get<Ptr>().get() == p.get<Ptr>().get());
+        \endcode
+    */
+class Any
+{
+
+    VIGRA_UNIQUE_PTR<detail::AnyHandle> handle_;
+
+  public:
+
+        /** Construct empty 'Any' object.
+        */
+    Any()
+    : handle_((detail::AnyHandle*)0)
+    {}
+
+        /** Construct 'Any' object holding the given value.
+        */
+    template <class T>
+    Any(T const & t)
+    : handle_(new detail::TypedAnyHandle<T>(t))
+    {}
+
+        /** Construct 'Any' object holding a copy of other's value.
+        */
+    Any(Any const & other)
+    : handle_(bool(other) ? other.handle_->clone() : (detail::AnyHandle*)0)
+    {}
+
+        /** Assign the given value to this 'Any' object
+            (overwrites the old value, regardless of types).
+        */
+    template <class T>
+    Any & operator=(T const & t)
+    {
+        handle_.reset(new detail::TypedAnyHandle<T>(t));
+        return *this;
+    }
+
+        /** Assign a copy of other's value to this 'Any' object
+            (overwrites the old value, regardless of types).
+        */
+    Any & operator=(Any const & other)
+    {
+        if(this != &other)
+            handle_.reset(bool(other) ? other.handle_->clone() : (detail::AnyHandle*)0);
+        return *this;
+    }
+
+        /** Delete the contained object (make this 'Any' object empty).
+        */
+    void release()
+    {
+        handle_.release();
+    }
+
+        /** Exchange the value of this object with other's.
+        */
+    void swap(Any & other)
+    {
+#ifdef VIGRA_NO_UNIQUE_PTR  // fallback for old compilers
+        detail::AnyHandle *t = handle_.release(),
+                          *o = other.handle_.release();
+        handle_.reset(o);
+        other.handle_.reset(t);
+#else
+        handle_.swap(other.handle_);
+#endif
+    }
+
+        /** Exchange the value of objects l and r.
+        */
+    friend void swap(Any & l, Any & r)
+    {
+        l.swap(r);
+    }
+
+        /** Check if this object contains the same type and value as other.
+            Also true if both 'Any' objects are empty.
+        */
+    bool operator==(Any const & other) const
+    {
+        return (handle_.get() == 0 && other.handle_.get() == 0) ||
+               (handle_.get() != 0 && handle_->equal(other.handle_.get()));
+    }
+
+        /** Check if this object differs from other by type or value.
+        */
+    bool operator!=(Any const & other) const
+    {
+        return !operator==(other);
+    }
+
+    bool operator==(bool other) const
+    {
+        return bool(*this) == other;
+    }
+
+    bool operator!=(bool other) const
+    {
+        return bool(*this) != other;
+    }
+
+        /** Convert 'Any' to <tt>false</tt> if this object is empty, <tt>true</tt> otherwise.
+        */
+    operator bool() const
+    {
+        return handle_.get() != 0;
+    }
+
+        /** Check if this object is empty (holds no value).
+        */
+    bool empty() const
+    {
+        return handle_.get() == 0;
+    }
+
+        /** Check if this object holds a value of the given type.
+        */
+    template <class T>
+    bool is_type() const
+    {
+        return dynamic_cast<detail::TypedAnyHandle<T> const *>(handle_.get()) != 0;
+    }
+
+        /** Check if this object's value is convertible to the given type.
+            At present, this only succeeds if <tt>T</tt> matches the stored
+            type exactly or is an arithmetic type convertible from the stored type.
+        */
+    template <class T>
+    bool is_readable() const
+    {
+        return  (dynamic_cast<detail::TypedAnyHandle<T> const *>(handle_.get()) != 0) ||
+                (std::is_arithmetic<T>::value &&
+                 dynamic_cast<detail::ConvertibleAnyHandle const *>(handle_.get()) != 0);
+    }
+
+        /** Read-write access to the contained value. This throws an exception
+            if the types don't match.
+        */
+    template <class T>
+    T & get()
+    {
+        vigra_precondition(bool(*this), "Any::get(): object empty.");
+        auto ptr = dynamic_cast<detail::TypedAnyHandle<T> *>(handle_.get());
+        vigra_precondition(ptr != 0, "Any::get(): object is not an instance of the target type.");
+        return ptr->value_;
+    }
+
+        /** Read-only access to the contained value. This throws an exception
+            if the types don't match.
+        */
+    template <class T>
+    T const & get() const
+    {
+        vigra_precondition(bool(*this), "Any::get(): object empty.");
+        auto ptr = dynamic_cast<detail::TypedAnyHandle<T> const *>(handle_.get());
+        vigra_precondition(ptr != 0, "Any::get(): object is not an instance of the target type.");
+        return ptr->value_;
+    }
+
+        /** By-value access to the stored value. This throws an exception
+            if the stored type doesn't match <tt>T</tt> and <tt>T</tt> is
+            not an arithmetic type.
+        */
+    template <class T>
+    T read() const
+    {
+        vigra_precondition(bool(*this), "Any::read(): object empty.");
+        auto ptr1 = dynamic_cast<detail::TypedAnyHandle<T> const *>(handle_.get());
+        if(ptr1 != 0)
+            return ptr1->value_;
+        auto ptr2 = dynamic_cast<detail::ConvertibleAnyHandle const *>(handle_.get());
+        vigra_precondition(ptr2 != 0, "Any::read(): object is not covertible to the target type.");
+        return ptr2->cast(detail::ConvertibleAnyHandle::TypeTag<T>());
+    }
+};
+
+} // namespace vigra
+
+#endif // VIGRA_ANY_HXX
diff --git a/include/vigra/applywindowfunction.hxx b/include/vigra/applywindowfunction.hxx
new file mode 100644
index 0000000..3d2b5a5
--- /dev/null
+++ b/include/vigra/applywindowfunction.hxx
@@ -0,0 +1,1010 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2007-2014 by Benjamin Seppke                 */
+/*       Cognitive Systems Group, University of Hamburg, Germany        */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_APPLYWINDOWFUCTION_HXX
+#define VIGRA_APPLYWINDOWFUCTION_HXX
+
+#include "basicimage.hxx"
+#include "copyimage.hxx"
+#include "basicgeometry.hxx"
+#include "initimage.hxx"
+#include "bordertreatment.hxx"
+
+namespace vigra {
+
+/********************************************************/
+/*                                                      */
+/*             Apply window filters to images           */
+/*                                                      */
+/********************************************************/
+
+/**  
+    This function calculates the results for a window function (given as a functor) when
+    applied to the complete image. Also allows a correct border handling! 
+    See \ref medianFilter() for an example of a quite basic window function and its application.
+*/
+//@{
+
+/** \brief Apply a window function to each pixels of a given image.
+
+    If you pass a functor to this function, which implements the two functions:
+    <ol>
+        <li>Diff2D windowShape() const<br/>
+        to return the filter window size, which has to be odd in each dimension and</li>
+        <li>void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)<br/>
+        to compute the results of the current window,</li>
+    </ol>
+    this function calculates the results for the complete image.
+
+    All \ref BorderTreatmentMode "border treatment modes"  (except BORDER_TREATMENT_CLIP)  are supported.
+
+    The input pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over 
+    the window functions' value_type <tt>T</tt>, i.e. addition of source values, multiplication with functions' values,
+    and NumericTraits must be defined. The filters' value_type must be an \ref AlgebraicField "algebraic field",
+    i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be defined. 
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2,
+                  class ProcessingFunctor>
+        void
+        applyWindowFunction(MultiArrayView<2, T1, S1> const & src,
+                            MultiArrayView<2, T2, S2> dest,
+                            ProcessingFunctor func, 
+                            BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+
+    }
+    \endcode
+
+    \deprecatedAPI{applyWindowFunction}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor,
+                  class ProcessingFunctor>
+        void applyWindowFunction(SrcIterator supperleft,
+                                 SrcIterator slowerright, SrcAccessor sa,
+                                 DestIterator dupperleft, DestAccessor da,
+                                 ProcessingFunctor func, 
+                                 BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor,
+                  class ProcessingFunctor>
+        void
+        applyWindowFunction(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                            pair<DestIterator, DestAccessor> dest,
+                            ProcessingFunctor func, 
+                            BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/applywindowfunction.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> src(w,h), dest(w,h);
+    ...
+    
+    template<class VALUETYPE>
+    class AvgFunctor
+    {
+        public:
+            MedianFunctor(Diff2D window_shape)
+            : m_window_shape(window_shape)
+            {
+            }
+            
+            template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+            void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)
+            {
+                SrcIterator s_ul = s - m_window_shape/2,
+                            s_lr = s_ul + m_window_shape;
+        
+                VALUETYPE result = NumericTraits<float>::zero();
+                                
+                SrcIterator ys = s_ul;
+                SrcIterator xs = ys;
+            
+                for( ; ys.y != s_lr.y; ys.y++)
+                {   
+                    for(xs = ys; xs.x != s_lr.x; xs.x++, iter++)
+                    {
+                        res += s_acc(xs);
+                    }       
+                }
+                
+                d_acc.set(res/(m_window_shape.x*m_window_shape.y),d);
+            }
+    
+            Diff2D windowShape() const
+            {
+                return m_window_shape;
+            }
+        private:
+            Diff2D m_window_shape;  
+    };
+ 
+    
+    // create an AverageFilter function for a 5x5 filter
+    AvgFunctor func(Diff2D(5,5));
+    
+    
+    // apply the filter function to the input image
+    applyWindowFunction(src, dest, func);
+    \endcode
+
+    <b> Preconditions:</b>
+
+    The image must be larger than the window size.
+*/
+
+doxygen_overloaded_function(template <...> void applyWindowFunction)
+
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor, 
+          class ProcessingFunctor>
+void applyWindowFunction(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+                         DestIterator d_ul, DestAccessor d_acc, 
+                         ProcessingFunctor func, 
+                         BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    vigra_precondition((border == BORDER_TREATMENT_AVOID   ||
+                      //border == BORDER_TREATMENT_CLIP    ||
+                        border == BORDER_TREATMENT_REPEAT  ||
+                        border == BORDER_TREATMENT_REFLECT ||
+                        border == BORDER_TREATMENT_WRAP    ||
+                        border == BORDER_TREATMENT_ZEROPAD   
+                        ),  
+                       "vigra::applyWindowFunction():\n"
+                       "  Border treatment must be one of follow treatments:\n"
+                       "  - BORDER_TREATMENT_AVOID\n"
+                       //"  - BORDER_TREATMENT_CLIP\n" 
+                       "  - BORDER_TREATMENT_REPEAT\n"
+                       "  - BORDER_TREATMENT_REFLECT\n"
+                       "  - BORDER_TREATMENT_WRAP\n"
+                       "  - BORDER_TREATMENT_ZEROPAD\n"
+                       );
+    
+    typename SrcIterator::difference_type img_shape = s_lr - s_ul;
+    Diff2D win_shape = func.windowShape();
+    
+    vigra_precondition( win_shape.x % 2 == 1 , "vigra::applyWindowFunction(): Filter window width has to be of odd size!");
+    vigra_precondition( win_shape.y % 2 == 1 , "vigra::applyWindowFunction(): Filter window height has to be of odd size!");
+    
+    vigra_precondition( win_shape.x <= img_shape.x && win_shape.y <= img_shape.y , "vigra::applyWindowFunction(): Filter window is larger than image!");
+    
+    /**********************************************************************************
+     *                                                                                *
+     *  COMPUTE ALL "SAFE" PIXELS, WHERE THE MASK FITS COMPLETELY INTO THE IMAGE      *
+     *                                                                                *
+     **********************************************************************************/
+    
+    
+    SrcIterator     ys  = s_ul, 
+                    xs  = ys;
+    
+    DestIterator    yd  = d_ul, 
+                    xd  = yd;
+    
+    SrcIterator     end = s_ul + img_shape - win_shape/2;
+    
+    ys.y += win_shape.y/2;
+    yd.y += win_shape.y/2;
+    
+    unsigned int y=0;
+    
+    for( ; ys.y != end.y; ys.y++, yd.y++, y++)
+    {   
+        xs = ys;
+        xs.x += win_shape.x/2;
+        
+        xd = yd;
+        xd.x += win_shape.x/2;
+                
+        for( ; xs.x != end.x; xs.x++, xd.x++)
+        {
+            func(xs, s_acc, xd, d_acc);
+        }
+    }
+    
+    
+    
+    /**********************************************************************************
+     *                                                                                *
+     *                      HANDLE THE EIGHT BORDER CASES SEPARATELY                  *
+     *                                                                                *
+     *                                                                                *
+     *  and do this diffently according to the used border treatment type, of course  *
+     *                                                                                *
+     **********************************************************************************/
+    
+    
+    if(border == BORDER_TREATMENT_AVOID)
+        return; // skip processing near the border
+    
+    
+    //Do some preparation for the special cases:
+    //Create window of width = image width and height = win_shape
+    BasicImage<typename SrcIterator::PixelType> temp(img_shape.x, win_shape.y + win_shape.y/2);
+    typedef typename BasicImage<typename SrcIterator::PixelType>::Iterator TempIterator;
+    
+    TempIterator    t_ul  = temp.upperLeft(), 
+                    t_lr  = temp.lowerRight();
+    
+    DestAccessor    t_acc = temp.accessor();
+    
+    TempIterator    yt = t_ul,
+                    xt = yt;
+    
+    
+    /**********************************************************************************
+     *                                                                                * 
+     *                             SIDE CASE 1 (1/8):                                 * 
+     *                                                                                *                                                                               *
+     *       HANDLE UPPER PIXELS WHERE THE MASK IS MISSING MINIMUM y-COORDINATES      *
+     *                                                                                *
+     **********************************************************************************/
+    if(border == BORDER_TREATMENT_REPEAT)
+    {
+        ys = s_ul;
+        Diff2D lineDiff(img_shape.x,1);
+        
+        for( ; yt.y != t_lr.y - win_shape.y; ++yt.y)
+        {
+            copyImage(ys, ys+lineDiff, s_acc, yt, t_acc);
+        }
+        copyImage(ys, ys+Diff2D(img_shape.x,win_shape.y), s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_REFLECT)
+    {
+        reflectImage(s_ul, s_ul+Diff2D(img_shape.x,win_shape.y/2), s_acc, t_ul, t_acc, horizontal);
+        copyImage(s_ul, s_ul+Diff2D(img_shape.x,win_shape.y), s_acc, t_ul+Diff2D(0,win_shape.y/2), t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_WRAP)
+    {
+        copyImage(s_ul+Diff2D(0, img_shape.y-win_shape.y/2), s_lr, s_acc, t_ul, t_acc);
+        copyImage(s_ul, s_ul+Diff2D(img_shape.x,win_shape.y), s_acc, t_ul+Diff2D(0,win_shape.y/2), t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_ZEROPAD)
+    {
+        initImage(t_ul, t_lr, t_acc, 0);
+        copyImage(s_ul, s_ul+Diff2D(img_shape.x,win_shape.y), s_acc, t_ul+Diff2D(0,win_shape.y/2), t_acc);
+        
+    } 
+    
+    yt = t_ul;
+    yt.y += win_shape.y/2;
+    yd = d_ul;
+    
+    for( ; yt.y != t_lr.y-win_shape.y/2; ++yd.y,  ++yt.y)
+    {
+        xt = yt;
+        xt.x += win_shape.x/2;
+        
+        xd = yd;
+        xd.x += win_shape.x/2;
+        
+        for( ; xt.x != t_lr.x-win_shape.x/2; xd.x++, xt.x++)
+        {
+            func(xt, t_acc, xd, d_acc);     
+        }
+    }
+    
+    /**********************************************************************************
+     *                                                                                * 
+     *                             SIDE CASE 2 (2/8):                                 * 
+     *                                                                                *                                                                               *
+     *       HANDLE LOWER PIXELS WHERE THE MASK IS MISSING MAXIMUM y-COORDINATES      *
+     *                                                                                *
+     **********************************************************************************/
+    if(border == BORDER_TREATMENT_REPEAT)
+    {
+        ys = s_ul + Diff2D(0, img_shape.y-1);
+        yt = t_ul + Diff2D(0, win_shape.x);
+        
+        Diff2D lineDiff(img_shape.x,1);
+        
+        for( ; yt.y != t_lr.y ; ++yt.y)
+        {
+            copyImage(ys, ys+lineDiff, s_acc, yt, t_acc);
+        }
+        ys = s_ul + Diff2D(0, img_shape.y-win_shape.y);
+        yt = t_ul;
+        copyImage(ys, ys+Diff2D(img_shape.x,win_shape.y), s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_REFLECT)
+    {
+        reflectImage(s_ul+Diff2D(0, img_shape.y-win_shape.y/2), s_lr, s_acc, t_ul+Diff2D(0, win_shape.y), t_acc, horizontal);
+        copyImage(s_ul+Diff2D(0, img_shape.y-win_shape.y), s_lr, s_acc, t_ul, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_WRAP)
+    {
+        copyImage(s_ul, s_ul + Diff2D(img_shape.x, win_shape.y/2), s_acc, t_ul+Diff2D(0, win_shape.y), t_acc);
+        copyImage(s_ul+Diff2D(0, img_shape.y-win_shape.y), s_lr, s_acc, t_ul, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_ZEROPAD)
+    {
+        initImage(t_ul, t_lr, t_acc, 0);        
+        copyImage(s_ul+Diff2D(0, img_shape.y-win_shape.y), s_lr, s_acc, t_ul, t_acc);
+        
+    } 
+    
+    
+    yt = t_ul;
+    yt.y += win_shape.y/2;
+    yd = d_ul;
+    yd.y += img_shape.y-win_shape.y/2-1;
+    
+    for( ; yt.y != t_lr.y - win_shape.y/2 ; ++yd.y, ++yt.y)
+    {
+        xt = yt;
+        xt.x += win_shape.x/2;
+        
+        xd = yd;
+        xd.x += win_shape.x/2;
+        
+        for( ; xt.x != t_lr.x-win_shape.x/2; xd.x++, xt.x++)
+        {
+            func(xt, t_acc, xd, d_acc);                 
+        }
+    }
+
+
+    //Preparation needed for left and right processing
+    temp.resize(win_shape.x+win_shape.x/2,img_shape.y);
+    t_ul = temp.upperLeft(); t_lr = temp.lowerRight();
+    t_acc = temp.accessor();
+    
+    
+    
+    /**********************************************************************************
+     *                                                                                * 
+     *                             SIDE CASE 3 (3/8):                                 * 
+     *                                                                                *
+     *       HANDLE LEFT PIXELS WHERE THE MASK IS MISSING MINIMUM x-COORDINATES       *
+     *                                                                                *
+     **********************************************************************************/
+    if(border == BORDER_TREATMENT_REPEAT)
+    {
+        xs = s_ul;
+        xt = t_ul;
+        xd = d_ul;
+        
+        Diff2D colDiff(1,img_shape.y);
+        
+        for( ; xt.x != t_lr.x - win_shape.x; ++xt.x)
+        {
+            copyImage(xs, xs+colDiff, s_acc, xt, t_acc);
+        }
+        copyImage(xs, xs+Diff2D(win_shape.x, img_shape.y), s_acc, xt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_REFLECT)
+    {
+        reflectImage(s_ul, s_ul+Diff2D(win_shape.x/2, img_shape.y), s_acc, t_ul, t_acc, vertical);
+        copyImage(s_ul, s_ul+Diff2D(win_shape.x, img_shape.y), s_acc, t_ul + Diff2D(win_shape.x/2, 0), t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_WRAP)
+    {
+        copyImage(s_ul+Diff2D(img_shape.x-win_shape.x/2, 0), s_lr, s_acc, t_ul, t_acc);
+        copyImage(s_ul, s_ul+Diff2D(win_shape.x, img_shape.y), s_acc, t_ul + Diff2D(win_shape.x/2, 0), t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_ZEROPAD)
+    {
+        initImage(t_ul, t_lr, t_acc, 0);        
+        copyImage(s_ul, s_ul+Diff2D(win_shape.x, img_shape.y), s_acc, t_ul + Diff2D(win_shape.x/2, 0), t_acc);
+        
+    } 
+        
+    
+    yt = t_ul;
+    yt.y += win_shape.y/2;
+    yd = d_ul;
+    yd.y += win_shape.y/2;
+    
+    for( ; yt.y != t_lr.y-win_shape.y/2; ++yd.y,  ++yt.y)
+    {
+        xt = yt;
+        xt.x += win_shape.x/2;
+        
+        xd = yd;
+        
+        for( ; xt.x != t_lr.x-win_shape.x/2; xd.x++, xt.x++)
+        {
+            func(xt, t_acc, xd, d_acc);                 
+        }
+    }
+    
+    
+    /**********************************************************************************
+     *                                                                                * 
+     *                             SIDE CASE 4 (4/8):                                 * 
+     *                                                                                *
+     *       HANDLE RIGHT PIXELS WHERE THE MASK IS MISSING MAXIMUM x-COORDINATES      *
+     *                                                                                *
+     **********************************************************************************/
+    if(border == BORDER_TREATMENT_REPEAT)
+    {
+        xs = s_ul + Diff2D(img_shape.x-1,0);
+        xt = t_ul + Diff2D(win_shape.x,0);
+        xd = d_ul;
+        
+        Diff2D colDiff(1,img_shape.y);
+        
+        for( ; xt.x != t_lr.x ; ++xt.x)
+        {
+            copyImage(xs, xs+colDiff, s_acc, xt, t_acc);
+        }
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,0);
+        yt = t_ul;
+        copyImage(ys, ys+Diff2D(win_shape.x,img_shape.y), s_acc, yt, t_acc);
+        
+        
+    }
+    else if(border == BORDER_TREATMENT_REFLECT)
+    {
+        reflectImage(s_ul+Diff2D(img_shape.x-win_shape.x/2,0), s_lr, s_acc, t_ul+Diff2D(win_shape.x,0), t_acc, vertical);
+        copyImage(s_ul+Diff2D(img_shape.x-win_shape.x,0), s_lr, s_acc, t_ul, t_acc);
+        
+        
+    }   
+    else if(border == BORDER_TREATMENT_WRAP)
+    {
+        copyImage(s_ul, s_ul+Diff2D(win_shape.x/2,img_shape.y), s_acc, t_ul+Diff2D(win_shape.x,0), t_acc);
+        copyImage(s_ul+Diff2D(img_shape.x-win_shape.x,0), s_lr, s_acc, t_ul, t_acc);
+        
+        
+    }   
+    else if(border == BORDER_TREATMENT_ZEROPAD)
+    {
+        initImage(t_ul, t_lr, t_acc, 0);        
+        copyImage(s_ul+Diff2D(img_shape.x-win_shape.x,0), s_lr, s_acc, t_ul, t_acc);
+        
+    } 
+    
+    
+    yt = t_ul;
+    yt.y += win_shape.x/2;
+    yd = d_ul;
+    yd.x += img_shape.x-win_shape.x/2-1;
+    yd.y += win_shape.y/2;
+    
+    for( ; yt.y != t_lr.y-win_shape.y/2; ++yd.y,  ++yt.y)
+    {
+        xt = yt;
+        xt.x += win_shape.x/2;
+        
+        xd = yd;
+        
+        for( ; xt.x != t_lr.x-win_shape.x/2; xd.x++, xt.x++)
+        {
+            func(xt, t_acc, xd, d_acc);             
+        }
+    }
+    
+    //Do some preaparations for the corner cases
+    temp.resize(win_shape+win_shape/2);
+    t_ul = temp.upperLeft(); t_lr = temp.lowerRight();
+    t_acc = temp.accessor();
+    
+    
+    
+    /**********************************************************************************
+     *                                                                                * 
+     *                             CORNER CASE 1 (5/8):                               * 
+     *                                                                                *
+     *            HANDLE UPPERLEFT PIXELS WHERE THE MASK IS MISSING MINIMUM           *
+     *                 x-COORDINATES AND MINIMUM y-COORDINATES                        *
+     *                                                                                *
+     **********************************************************************************/
+    if(border == BORDER_TREATMENT_REPEAT)
+    {
+        //init upperleft rect with single value
+        ys = s_ul;
+        yt = t_ul;
+        initImage(yt,yt+win_shape/2, t_acc, s_acc(ys));
+        
+        //init upperright rect with vertical stripes
+        ys = s_ul;
+        yt = t_ul + Diff2D(win_shape.x/2,0);
+        Diff2D lineDiff(win_shape.x,1);
+        for( ; yt.y != t_lr.y-win_shape.y ; ++yt.y)
+        {
+            copyImage(ys, ys+lineDiff, s_acc, yt, t_acc);
+        }
+        
+        //init lowerleft rect with horizontal stripes
+        xs = s_ul;
+        xt = t_ul + Diff2D(0,win_shape.y/2);
+        Diff2D rowDiff(1, win_shape.y);
+        for( ; xt.x != t_lr.x-win_shape.x ; ++xt.x)
+        {
+            copyImage(xs, xs+rowDiff, s_acc, xt, t_acc);
+        }
+        
+        //copy image patch in lower right patch
+        ys = s_ul;
+        yt = t_ul + win_shape/2;
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_REFLECT)
+    {
+        //init upperleft rect with double reflect image
+        ys = s_ul;
+        yt = t_ul;
+        rotateImage(ys,ys+win_shape/2, s_acc, yt, t_acc, 180);
+        
+        //init upperright rect with horizontal reflected image
+        ys = s_ul;
+        yt = t_ul + Diff2D(win_shape.x/2,0);
+        reflectImage(ys, ys+Diff2D(win_shape.x, win_shape.y/2), s_acc, yt, t_acc, horizontal);
+        
+        //init lowerleft rect with vertical reflected image
+        xs = s_ul;
+        xt = t_ul + Diff2D(0,win_shape.y/2);
+        reflectImage(xs, xs+Diff2D(win_shape.x/2, win_shape.y), s_acc, xt, t_acc,vertical);
+        
+        //copy image patch in lower right patch
+        ys = s_ul;
+        yt = t_ul + win_shape/2;
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_WRAP)
+    {   
+        //init upperleft rect with lower right image part
+        ys = s_ul+ img_shape - win_shape/2;
+        yt = t_ul;
+        copyImage(ys, s_lr, s_acc, yt, t_acc);
+        
+        //init upperright rect with images lower left part
+        ys = s_ul + Diff2D(0, img_shape.y-win_shape.y/2);
+        yt = t_ul + Diff2D(win_shape.x/2,0);
+        copyImage(ys, ys+Diff2D(win_shape.x, win_shape.y/2), s_acc, yt, t_acc);
+        
+        //init lowerleft rect with with images upper right part
+        xs = s_ul + Diff2D(img_shape.x-win_shape.x/2, 0);
+        xt = t_ul + Diff2D(0,win_shape.y/2);
+        copyImage(xs, xs+Diff2D(win_shape.x/2, win_shape.y), s_acc, xt, t_acc);
+        
+        //copy image patch in lower right patch
+        ys = s_ul;
+        yt = t_ul + win_shape/2;
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_ZEROPAD)
+    {
+        initImage(t_ul, t_lr, t_acc, 0);
+        
+        //copy image patch in lower right patch
+        ys = s_ul;
+        yt = t_ul + win_shape/2;
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    } 
+    
+    
+    yt = t_ul;
+    yt.y += win_shape.y/2;
+    yd = d_ul;
+    
+    for( ; yt.y != t_lr.y-win_shape.y/2; ++yd.y,  ++yt.y)
+    {
+        xt = yt;
+        xt.x += win_shape.x/2;
+        
+        xd = yd;
+        
+        for( ; xt.x != t_lr.x-win_shape.x/2; xd.x++, xt.x++)
+        {
+            func(xt, t_acc, xd, d_acc);             
+        }
+    }
+    
+    
+    /**********************************************************************************
+     *                                                                                * 
+     *                             CORNER CASE 2 (6/8):                               * 
+     *                                                                                *
+     *            HANDLE UPPERRIGHT PIXELS WHERE THE MASK IS MISSING MAXIMUM          *
+     *                 x-COORDINATES AND MINIMUM y-COORDINATES                        *
+     *                                                                                *
+     **********************************************************************************/
+    if(border == BORDER_TREATMENT_REPEAT)
+    {
+        //init upperright rect with single value
+        ys = s_ul + Diff2D(img_shape.x-1,0);
+        yt = t_ul + Diff2D(win_shape.x,0);
+        initImage(yt, yt+win_shape/2, t_acc, s_acc(ys));
+        
+        //init upperleft rect with vertical stripes
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,0);;
+        yt = t_ul;      
+        Diff2D lineDiff(win_shape.x,1);
+        for( ; yt.y != t_lr.y-win_shape.y ; ++yt.y)
+        {
+            copyImage(ys, ys+lineDiff, s_acc, yt, t_acc);
+        }
+        
+        //init lowerright rect with horizontal stripes
+        xs = s_ul + Diff2D(img_shape.x-1,0);;
+        xt = t_ul + Diff2D(win_shape.x,win_shape.y/2);
+        Diff2D rowDiff(1, win_shape.y);
+        for( ; xt.x != t_lr.x; ++xt.x)
+        {
+            copyImage(xs, xs+rowDiff, s_acc, xt, t_acc);
+        }
+        
+        //copy image patch in lower left patch
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,0);
+        yt = t_ul + Diff2D(0, win_shape.y/2);
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_REFLECT)
+    {
+        //init upperright rect with double flipped image
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x/2,0);
+        yt = t_ul + Diff2D(win_shape.x,0);      
+        rotateImage(ys, ys+win_shape/2, s_acc, yt, t_acc, 180);
+        
+        //init upperleft rect with horizontal reflected image
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,0);
+        yt = t_ul;
+        reflectImage(ys, ys+Diff2D(win_shape.x, win_shape.y/2), s_acc, yt, t_acc, horizontal);
+        
+        //init lowerright rect with  vertical reflected image
+        xs = s_ul + Diff2D(img_shape.x-win_shape.x/2,0);
+        xt = t_ul + Diff2D(win_shape.x,win_shape.y/2);      
+        reflectImage(xs, xs+Diff2D(win_shape.x/2, win_shape.y), s_acc, xt, t_acc,vertical);
+        
+        //copy image patch in lower left patch
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,0);
+        yt = t_ul + Diff2D(0, win_shape.y/2);
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_WRAP)
+    {
+        //init upperright rect with lower left image part
+        ys = s_ul + Diff2D(0, img_shape.y-win_shape.y/2);
+        yt = t_ul + Diff2D(win_shape.x,0);      
+        copyImage(ys, ys+win_shape/2, s_acc, yt, t_acc);
+        
+        //init upperleft rect with lower right image part
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x, img_shape.y-win_shape.y/2);
+        yt = t_ul;
+        copyImage(ys, ys+Diff2D(win_shape.x, win_shape.y/2), s_acc, yt, t_acc);
+        
+        //init lowerright rect with upperleft image part
+        xs = s_ul;
+        xt = t_ul + Diff2D(win_shape.x,win_shape.y/2);      
+        copyImage(xs, xs+Diff2D(win_shape.x/2, win_shape.y), s_acc, xt, t_acc);
+        
+        //copy image patch in lower left patch
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,0);
+        yt = t_ul + Diff2D(0, win_shape.y/2);
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_ZEROPAD)
+    {
+        initImage(t_ul, t_lr, t_acc, 0);
+        
+        //copy image patch in lower left patch
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,0);
+        yt = t_ul + Diff2D(0, win_shape.y/2);
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    } 
+
+    
+    yt = t_ul;
+    yt.y += win_shape.y/2;
+    yd = d_ul + Diff2D(img_shape.x-win_shape.x/2-1, 0);     
+    
+    for( ; yt.y != t_lr.y-win_shape.y/2; ++yd.y,  ++yt.y)
+    {
+        xt = yt;
+        xt.x += win_shape.x/2;
+        
+        xd = yd;
+        
+        for( ; xt.x != t_lr.x-win_shape.x/2; xd.x++, xt.x++)
+        {
+            func(xt, t_acc, xd, d_acc);                         
+        }
+    }
+    
+    /**********************************************************************************
+     *                                                                                * 
+     *                             CORNER CASE 3 (7/8):                               * 
+     *                                                                                *
+     *            HANDLE LOWERLEFT PIXELS WHERE THE MASK IS MISSING MINIMUM           *
+     *                 x-COORDINATES AND MAXIMUM y-COORDINATES                        *
+     *                                                                                *
+     **********************************************************************************/
+    if(border == BORDER_TREATMENT_REPEAT)
+    {
+        //init lowerleft rect with single value
+        ys = s_ul + Diff2D(0,img_shape.y-1);
+        yt = t_ul + Diff2D(0,win_shape.y);
+        initImage(yt, yt+win_shape/2, t_acc, s_acc(ys));
+        
+        //init lowerright rect with vertical stripes
+        ys = s_ul + Diff2D(0,img_shape.y-1);
+        yt = t_ul + Diff2D(win_shape.x/2,win_shape.y);
+        Diff2D lineDiff(win_shape.x,1);
+        for( ; yt.y != t_lr.y ; ++yt.y)
+        {
+            copyImage(ys, ys+lineDiff, s_acc, yt, t_acc);
+        }
+        
+        //init upperleft rect with horizontal stripes
+        xs = s_ul + Diff2D(0,img_shape.y-win_shape.y);
+        xt = t_ul;
+        Diff2D rowDiff(1, win_shape.y);
+        for( ; xt.x != t_lr.x-win_shape.x; ++xt.x)
+        {
+            copyImage(xs, xs+rowDiff, s_acc, xt, t_acc);
+        }
+        
+        //copy image patch in upper right patch
+        yt = t_ul + Diff2D(win_shape.x/2,0);
+        ys = s_ul + Diff2D(0,img_shape.y-win_shape.y);
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_REFLECT)
+    {
+        //init lowerleft rect with double reflected image
+        ys = s_ul + Diff2D(0,img_shape.y-win_shape.y/2);
+        yt = t_ul + Diff2D(0,win_shape.y);
+        rotateImage(ys, ys+win_shape/2, s_acc, yt, t_acc, 180);
+        
+        //init lowerright rect with horizontal reflected image
+        ys = s_ul + Diff2D(0,img_shape.y-win_shape.y/2);
+        yt = t_ul + Diff2D(win_shape.x/2,win_shape.y);
+        reflectImage(ys, ys+Diff2D(win_shape.x, win_shape.y/2), s_acc, yt, t_acc, horizontal);
+        
+        //init upperleft rect with vertical reflected image
+        xs = s_ul + Diff2D(0,img_shape.y-win_shape.y);
+        xt = t_ul;
+        reflectImage(xs, xs+Diff2D(win_shape.x/2, win_shape.y), s_acc, xt, t_acc,vertical);
+        
+        //copy image patch in upper right patch
+        yt = t_ul + Diff2D(win_shape.x/2,0);
+        ys = s_ul + Diff2D(0,img_shape.y-win_shape.y);
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_WRAP)
+    {
+        //init lowerleft rect with upper right image part
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x/2,0);
+        yt = t_ul + Diff2D(0,win_shape.y);
+        copyImage(ys, ys+win_shape/2, s_acc, yt, t_acc);
+        
+        //init lowerright rect with upper left image part
+        ys = s_ul;
+        yt = t_ul + Diff2D(win_shape.x/2,win_shape.y);
+        copyImage(ys, ys+Diff2D(win_shape.x, win_shape.y/2), s_acc, yt, t_acc);
+        
+        //init upperleft rect with lower right image part
+        xs = s_ul + Diff2D(img_shape.x-win_shape.x/2,img_shape.y-win_shape.y);
+        xt = t_ul;
+        copyImage(xs, xs+Diff2D(win_shape.x/2, win_shape.y), s_acc, xt, t_acc);
+        
+        //copy image patch in upper right patch
+        yt = t_ul + Diff2D(win_shape.x/2,0);
+        ys = s_ul + Diff2D(0,img_shape.y-win_shape.y);
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_ZEROPAD)
+    {
+        initImage(t_ul, t_lr, t_acc, 0);
+        
+        //copy image patch in upper right patch
+        yt = t_ul + Diff2D(win_shape.x/2,0);
+        ys = s_ul + Diff2D(0,img_shape.y-win_shape.y);
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    } 
+    
+    
+    yt = t_ul;
+    yt.y += win_shape.y/2;
+    yd = d_ul + Diff2D(0, img_shape.y-win_shape.y/2-1);
+    
+    for( ; yt.y != t_lr.y-win_shape.y/2; ++yd.y,  ++yt.y)
+    {
+        xt = yt;
+        xt.x += win_shape.x/2;
+        
+        xd = yd;
+        
+        for( ; xt.x != t_lr.x-win_shape.x/2; xd.x++, xt.x++)
+        {
+            func(xt, t_acc, xd, d_acc);                             
+        }
+    }
+    
+    /**********************************************************************************
+     *                                                                                * 
+     *                             CORNER CASE 4 (8/8):                               * 
+     *                                                                                *
+     *            HANDLE LOWERRIGHT PIXELS WHERE THE MASK IS MISSING MAXIMUM          *
+     *                 x-COORDINATES AND MAXIMUM y-COORDINATES                        *
+     *                                                                                *
+     **********************************************************************************/
+    if(border == BORDER_TREATMENT_REPEAT)
+    {
+        //init lowerright rect with single value
+        ys = s_ul + Diff2D(img_shape.x-1,img_shape.y-1);
+        yt = t_ul + win_shape;
+        initImage(yt,yt+win_shape/2, t_acc, s_acc(ys));
+        
+        //init lowerleft rect with vertical stripes
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,img_shape.y-1);
+        yt = t_ul + Diff2D(0,win_shape.y);
+        Diff2D lineDiff(win_shape.x,1);
+        for( ; yt.y != t_lr.y ; ++yt.y)
+        {
+            copyImage(ys, ys+lineDiff, s_acc, yt, t_acc);
+        }
+        
+        //init upperright rect with horizontal stripes
+        xs = s_ul + Diff2D(img_shape.x-1,img_shape.y-win_shape.y);
+        xt = t_ul + Diff2D(win_shape.x,0);
+        Diff2D rowDiff(1, win_shape.y);
+        for( ; xt.x != t_lr.x; ++xt.x)
+        {
+            copyImage(xs, xs+rowDiff, s_acc, xt, t_acc);
+        }
+        
+        //copy image patch in upperleft patch
+        ys = s_ul  + img_shape - win_shape;
+        yt = t_ul;
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_REFLECT)
+    {
+        //init lowerright rect  with double reflected image
+        ys = s_ul + img_shape-win_shape/2;
+        yt = t_ul + win_shape;
+        rotateImage(ys, ys+win_shape/2, s_acc, yt, t_acc, 180);
+        
+        //init lowerleft rect with horizontal reflected image
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,img_shape.y-win_shape.y/2);
+        yt = t_ul + Diff2D(0,win_shape.y);
+        reflectImage(ys, ys+Diff2D(win_shape.x, win_shape.y/2), s_acc, yt, t_acc, horizontal);
+        
+        //init upperright rect with vertical reflected image
+        xs = s_ul + Diff2D(img_shape.x-win_shape.x/2,img_shape.y-win_shape.y);
+        xt = t_ul + Diff2D(win_shape.x,0);
+        reflectImage(xs, xs+Diff2D(win_shape.x/2, win_shape.y), s_acc, xt, t_acc,vertical);
+        
+        //copy image patch in upperleft patch
+        ys = s_ul  + img_shape - win_shape;
+        yt = t_ul;
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_WRAP)
+    {
+        //init lowerright with upperleft image part
+        ys = s_ul;
+        yt = t_ul + win_shape;
+        copyImage(ys, ys+win_shape/2, s_acc, yt, t_acc);
+        
+        //init lowerleft rect with upper right image part
+        ys = s_ul + Diff2D(img_shape.x-win_shape.x,0);
+        yt = t_ul + Diff2D(0,win_shape.y);
+        copyImage(ys, ys+Diff2D(win_shape.x, win_shape.y/2), s_acc, yt, t_acc);
+        
+        //init upperright rect with lower left image part
+        xs = s_ul + Diff2D(0,img_shape.y-win_shape.y);
+        xt = t_ul + Diff2D(win_shape.x,0);
+        copyImage(xs, xs+Diff2D(win_shape.x/2, win_shape.y), s_acc, xt, t_acc);
+        
+        //copy image patch in upperleft patch
+        ys = s_ul  + img_shape-win_shape;
+        yt = t_ul;
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    }
+    else if(border == BORDER_TREATMENT_ZEROPAD)
+    {
+        initImage(t_ul, t_lr, t_acc, 0);        
+        
+        //copy image patch in upperleft patch
+        ys = s_ul  + img_shape - win_shape;
+        yt = t_ul;
+        copyImage(ys, ys+win_shape, s_acc, yt, t_acc);
+        
+    } 
+    
+    
+    yt = t_ul;
+    yt.y += win_shape.y/2;
+    yd = d_ul + img_shape-win_shape/2-Diff2D(1,1);
+    
+    for( ; yt.y != t_lr.y-win_shape.y/2; ++yd.y,  ++yt.y)
+    {
+        xt = yt;
+        xt.x += win_shape.x/2;
+        
+        xd = yd;
+        
+        for( ; xt.x != t_lr.x-win_shape.x/2; xd.x++, xt.x++)
+        {
+            func(xt, t_acc, xd, d_acc);                             
+        }
+    }
+}
+
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor,
+          class ProcessingFunctor>
+inline void applyWindowFunction(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+                                pair<DestIterator, DestAccessor> d, 
+                                ProcessingFunctor func, 
+                                BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    applyWindowFunction(s.first, s.second, s.third,
+                         d.first, d.second, 
+                         func, 
+                         border);
+}
+
+template <class T1, class S1, 
+          class T2, class S2,
+          class ProcessingFunctor>
+inline void applyWindowFunction(MultiArrayView<2, T1, S1> const & src,
+                                MultiArrayView<2, T2, S2> dest, 
+                                ProcessingFunctor func, 
+                                BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    vigra_precondition(src.shape() == dest.shape(),
+                        "vigra::applyWindowFunction(): shape mismatch between input and output.");
+    applyWindowFunction(srcImageRange(src),
+                            destImage(dest), 
+                            func, 
+                            border);
+}
+
+//@}
+
+} //end of namespace vigra
+
+#endif //VIGRA_APPLYWINDOWFUNCTION_HXX
diff --git a/include/vigra/array_vector.hxx b/include/vigra/array_vector.hxx
index 04816bc..bdeee06 100644
--- a/include/vigra/array_vector.hxx
+++ b/include/vigra/array_vector.hxx
@@ -46,7 +46,7 @@
 #ifdef VIGRA_CHECK_BOUNDS
 #define VIGRA_ASSERT_INSIDE(diff) \
   vigra_precondition(diff >= 0, "Index out of bounds");\
-  vigra_precondition((unsigned int)diff < size_, "Index out of bounds");
+  vigra_precondition(diff < (difference_type)size_, "Index out of bounds");
 #else
 #define VIGRA_ASSERT_INSIDE(diff)
 #endif
@@ -246,6 +246,20 @@ public:
         return data() + size();
     }
 
+        /** Get const iterator referring to the first array element.
+        */
+    inline const_iterator cbegin() const
+    {
+        return data();
+    }
+
+        /** Get const iterator pointing beyond the last array element.
+        */
+    inline const_iterator cend() const
+    {
+        return data() + size();
+    }
+
         /** Get reverse iterator referring to the last array element.
         */
     inline reverse_iterator rbegin()
@@ -274,6 +288,20 @@ public:
         return (const_reverse_iterator(begin()));
     }
 
+        /** Get const reverse iterator referring to the last array element.
+        */
+    inline const_reverse_iterator crbegin() const
+    {
+        return (const_reverse_iterator(end()));
+    }
+
+        /** Get const reverse iterator pointing before the first array element.
+        */
+    inline const_reverse_iterator crend() const
+    {
+        return (const_reverse_iterator(begin()));
+    }
+
         /** Access first array element.
         */
     reference front()
@@ -387,7 +415,7 @@ bool ArrayVectorView<T>::operator==(ArrayVectorView<U> const & rhs) const
 {
     if(size() != rhs.size())
         return false;
-    for(unsigned int k=0; k<size(); ++k)
+    for(size_type k=0; k<size(); ++k)
         if(data_[k] != rhs[k])
             return false;
     return true;
@@ -399,7 +427,7 @@ ArrayVectorView <T>::copyImpl(const ArrayVectorView & rhs)
 {
     vigra_precondition (size() == rhs.size(),
         "ArrayVectorView::copy(): shape mismatch.");
-    if(size() == 0)  // needed because MSVC debug assertions in std::copy() may fire  
+    if(size() == 0)  // needed because MSVC debug assertions in std::copy() may fire
         return;      // "invalid address: data_ == NULL" even when nothing is to be copied
     // use copy() or copy_backward() according to possible overlap of this and rhs
     if(data_ <= rhs.data())
@@ -433,21 +461,21 @@ ArrayVectorView <T>::swapDataImpl(const ArrayVectorView <U>& rhs)
     // check for overlap
     if(data_ + size_ <= rhs.data_ || rhs.data_ + size_ <= data_)
     {
-        for(unsigned int k=0; k<size_; ++k)
+        for(size_type k=0; k<size_; ++k)
             std::swap(data_[k], rhs.data_[k]);
     }
     else
     {
         ArrayVector<T> t(*this);
         copyImpl(rhs);
-        rhs.copyImpl(*this);
+        rhs.copyImpl(t);
     }
 }
 
 
 /** Replacement for <tt>std::vector</tt>.
 
-    This template implements the same functionality as <tt>a href="http://www.sgi.com/tech/stl/Vector.html">std::vector</a></tt> (see there for detailed documentation).
+    This template implements the same functionality as <tt><a href="http://www.sgi.com/tech/stl/Vector.html">std::vector</a></tt> (see there for detailed documentation).
     However, it gives two useful guarantees, that <tt>std::vector</tt> fails
     to provide:
 
@@ -581,7 +609,7 @@ public:
 
     ~ArrayVector()
     {
-        deallocate(this->data_, this->size_);
+        deallocate(this->data_, this->size_, this->capacity_);
     }
 
     void pop_back();
@@ -601,9 +629,19 @@ public:
 
     void clear();
 
-    void reserve( size_type new_capacity );
+    pointer reserveImpl( bool dealloc, size_type new_capacity );
+
+    pointer reserveImpl( bool dealloc);
+
+    void reserve()
+    {
+        reserveImpl(true);
+    }
 
-    void reserve();
+    void reserve( size_type new_capacity )
+    {
+        reserveImpl(true, new_capacity);
+    }
 
     void resize( size_type new_size, value_type const & initial );
 
@@ -621,7 +659,7 @@ public:
 
   private:
 
-    void deallocate(pointer data, size_type size);
+    void deallocate(pointer data, size_type size, size_type capacity);
 
     pointer reserve_raw(size_type capacity);
 
@@ -664,15 +702,19 @@ inline void ArrayVector<T, Alloc>::pop_back()
 template <class T, class Alloc>
 inline void ArrayVector<T, Alloc>::push_back( value_type const & t )
 {
-    reserve();
+	size_type old_capacity = this->capacity_;
+	pointer old_data = reserveImpl(false);
     alloc_.construct(this->data_ + this->size_, t);
+    // deallocate old data _after_ construction of new element, so that
+    // 't' can refer to the old data as in 'push_back(front())'
+    deallocate(old_data, this->size_, old_capacity);
     ++this->size_;
 }
 
 template <class T, class Alloc>
 inline void ArrayVector<T, Alloc>::clear()
 {
-    detail::destroy_n(this->data_, (int)this->size_);
+    detail::destroy_n(this->data_, this->size_);
     this->size_ = 0;
 }
 
@@ -718,7 +760,7 @@ ArrayVector<T, Alloc>::insert(iterator p, size_type n, value_type const & v)
             alloc_.deallocate(new_data, new_capacity);
             throw;
         }
-        deallocate(this->data_, this->size_);
+        deallocate(this->data_, this->size_, this->capacity_);
         capacity_ = new_capacity;
         this->data_ = new_data;
     }
@@ -763,7 +805,7 @@ ArrayVector<T, Alloc>::insert(iterator p, InputIterator i, InputIterator iend)
             alloc_.deallocate(new_data, new_capacity);
             throw;
         }
-        deallocate(this->data_, this->size_);
+        deallocate(this->data_, this->size_, this->capacity_);
         capacity_ = new_capacity;
         this->data_ = new_data;
     }
@@ -808,27 +850,36 @@ ArrayVector<T, Alloc>::erase(iterator p, iterator q)
 }
 
 template <class T, class Alloc>
-inline void
-ArrayVector<T, Alloc>::reserve( size_type new_capacity )
+typename ArrayVector<T, Alloc>::pointer
+ArrayVector<T, Alloc>::reserveImpl( bool dealloc, size_type new_capacity)
 {
     if(new_capacity <= capacity_)
-        return;
-    pointer new_data = reserve_raw(new_capacity);
+        return 0;
+    pointer new_data = reserve_raw(new_capacity),
+            old_data = this->data_;
     if(this->size_ > 0)
-        std::uninitialized_copy(this->data_, this->data_+this->size_, new_data);
-    deallocate(this->data_, this->size_);
+        std::uninitialized_copy(old_data, old_data+this->size_, new_data);
     this->data_ = new_data;
-    capacity_ = new_capacity;
+    if(!dealloc)
+    {
+        this->capacity_ = new_capacity;
+        return old_data;
+    }
+    deallocate(old_data, this->size_, this->capacity_);
+    this->capacity_ = new_capacity;
+    return 0;
 }
 
 template <class T, class Alloc>
-inline void
-ArrayVector<T, Alloc>::reserve()
+inline typename ArrayVector<T, Alloc>::pointer
+ArrayVector<T, Alloc>::reserveImpl(bool dealloc)
 {
     if(capacity_ == 0)
-        reserve(minimumCapacity);
+        return reserveImpl(dealloc, minimumCapacity);
     else if(this->size_ == capacity_)
-        reserve(resizeFactor*capacity_);
+        return reserveImpl(dealloc, resizeFactor*capacity_);
+    else
+        return 0;
 }
 
 template <class T, class Alloc>
@@ -877,12 +928,12 @@ ArrayVector<T, Alloc>::swap(this_type & rhs)
 
 template <class T, class Alloc>
 inline void
-ArrayVector<T, Alloc>::deallocate(pointer data, size_type size)
+ArrayVector<T, Alloc>::deallocate(pointer data, size_type size, size_type capacity)
 {
     if(data)
     {
-        detail::destroy_n(data, (int)size);
-        alloc_.deallocate(data, size);
+        detail::destroy_n(data, size);
+        alloc_.deallocate(data, capacity);
     }
 }
 
@@ -905,7 +956,7 @@ namespace std {
 template <class T>
 ostream & operator<<(ostream & s, vigra::ArrayVectorView<T> const & a)
 {
-    for(int k=0; k<(int)a.size()-1; ++k)
+    for(std::size_t k=0; k<a.size()-1; ++k)
         s << a[k] << ", ";
     if(a.size())
             s << a.back();
diff --git a/include/vigra/axistags.hxx b/include/vigra/axistags.hxx
index 4bb44e1..454c7c1 100644
--- a/include/vigra/axistags.hxx
+++ b/include/vigra/axistags.hxx
@@ -58,7 +58,8 @@ class AxisInfo
                     Angle = 4, 
                     Time = 8, 
                     Frequency = 16, 
-                    UnknownAxisType = 32, 
+                    Edge = 32,
+                    UnknownAxisType = 64, 
                     NonChannel = Space | Angle | Time | Frequency | UnknownAxisType,
                     AllAxes = 2*UnknownAxisType-1 };
 
@@ -126,6 +127,11 @@ class AxisInfo
     {
         return isType(Frequency);
     }
+
+    bool isEdge() const
+    {
+        return isType(Edge);
+    }
     
     bool isAngular() const
     {
@@ -255,7 +261,17 @@ class AxisInfo
     {
         return AxisInfo("z", Space, resolution, description);
     }
+
+    static AxisInfo n(double resolution = 0.0, std::string const & description = "")
+    {
+        return AxisInfo("n", Space, resolution, description);
+    }
     
+    static AxisInfo e(double resolution = 0.0, std::string const & description = "")
+    {
+        return AxisInfo("e", Edge, resolution, description);
+    }
+
     static AxisInfo t(double resolution = 0.0, std::string const & description = "")
     {
         return AxisInfo("t", Time, resolution, description);
@@ -339,6 +355,57 @@ class AxisTags
         push_back(i5);
     }
     
+    AxisTags(std::string const & tags)
+    {
+        for(int k=0; k<tags.size(); ++k)
+        {
+            switch(tags[k])
+            {
+              case 'x':
+                push_back(AxisInfo::x());
+                break;
+              case 'y':
+                push_back(AxisInfo::y());
+                break;
+              case 'z':
+                push_back(AxisInfo::z());
+                break;
+              case 't':
+                push_back(AxisInfo::t());
+                break;
+              case 'c':
+                push_back(AxisInfo::c());
+                break;
+              case 'f':
+                ++k;
+                vigra_precondition(k < tags.size(),
+                    "AxisTags(string): invalid input");
+                switch(tags[k])
+                {
+                  case 'x':
+                    push_back(AxisInfo::fx());
+                    break;
+                  case 'y':
+                    push_back(AxisInfo::fy());
+                    break;
+                  case 'z':
+                    push_back(AxisInfo::fz());
+                    break;
+                  case 't':
+                    push_back(AxisInfo::ft());
+                    break;
+                  default:
+                    vigra_precondition(false,
+                        "AxisTags(string): invalid input");
+                }
+                break;
+              default:
+                vigra_precondition(false,
+                    "AxisTags(string): invalid input");
+            }
+        }
+    }
+    
     // static AxisTags fromJSON(std::string const & repr);
 
     std::string toJSON() const
@@ -388,6 +455,11 @@ class AxisTags
         return res;
     }
     
+    bool contains(std::string const & key) const
+    {
+        return index(key) < (int)size();
+    }
+    
     AxisInfo & get(int k)
     {
         checkIndex(k);
diff --git a/include/vigra/basicimage.hxx b/include/vigra/basicimage.hxx
index a646fc0..ecd8676 100644
--- a/include/vigra/basicimage.hxx
+++ b/include/vigra/basicimage.hxx
@@ -141,7 +141,7 @@ class BasicImageIteratorBase
     typedef IteratorAdaptor<LineBasedColumnIteratorPolicy<IMAGEITERATOR> >
                                  column_iterator;
 
-    typedef int                  MoveX;
+    typedef std::ptrdiff_t       MoveX;
     typedef LINESTARTITERATOR    MoveY;
 
     MoveX x;
@@ -210,12 +210,12 @@ class BasicImageIteratorBase
         return *(*(y + d.y) + x + d.x);
     }
 
-    index_reference operator()(int dx, int dy) const
+    index_reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy) const
     {
         return *(*(y + dy) + x + dx);
     }
 
-    pointer operator[](int dy) const
+    pointer operator[](std::ptrdiff_t dy) const
     {
         return y[dy] + x;
     }
@@ -235,7 +235,7 @@ class BasicImageIteratorBase
       y(line)
     {}
 
-    BasicImageIteratorBase(int ix, LINESTARTITERATOR const & line)
+    BasicImageIteratorBase(std::ptrdiff_t ix, LINESTARTITERATOR const & line)
     : x(ix),
       y(line)
     {}
@@ -602,7 +602,7 @@ class BasicImage
 
         /** construct image of size width x height, use the specified allocator.
         */
-    BasicImage(int width, int height, Alloc const & alloc = Alloc())
+    BasicImage(std::ptrdiff_t width, std::ptrdiff_t height, Alloc const & alloc = Alloc())
     : data_(0),
       width_(0),
       height_(0),
@@ -637,7 +637,7 @@ class BasicImage
         value_type doesn't have a default constructor).
         Use the specified allocator.
         */
-    BasicImage(int width, int height, value_type const & d, Alloc const & alloc = Alloc())
+    BasicImage(std::ptrdiff_t width, std::ptrdiff_t height, value_type const & d, Alloc const & alloc = Alloc())
     : data_(0),
       width_(0),
       height_(0),
@@ -655,7 +655,7 @@ class BasicImage
             of the memory (see BasicImage::resize for details).
             Use the specified allocator.
         */
-    BasicImage(int width, int height, SkipInitializationTag, Alloc const & alloc = Alloc())
+    BasicImage(std::ptrdiff_t width, std::ptrdiff_t height, SkipInitializationTag, Alloc const & alloc = Alloc())
     : data_(0),
       width_(0),
       height_(0),
@@ -708,7 +708,7 @@ class BasicImage
         /** construct image of size width*height and copy the data from the
             given C-style array \a d. Use the specified allocator.
         */
-    BasicImage(int width, int height, const_pointer d, Alloc const & alloc = Alloc())
+    BasicImage(std::ptrdiff_t width, std::ptrdiff_t height, const_pointer d, Alloc const & alloc = Alloc())
     : data_(0),
       width_(0),
       height_(0),
@@ -773,7 +773,7 @@ class BasicImage
         /** reset image to specified size (dimensions must not be negative)
             (old data are kept if new size matches old size)
         */
-    void resize(int width, int height)
+    void resize(std::ptrdiff_t width, std::ptrdiff_t height)
     {
         if(width != width_ || height != height_)
             resize(width, height, value_type());
@@ -795,7 +795,7 @@ class BasicImage
             constructor, dimensions must not be negative,
             old data are kept if new size matches old size)
         */
-    void resize(int width, int height, value_type const & d)
+    void resize(std::ptrdiff_t width, std::ptrdiff_t height, value_type const & d)
     {
         resizeImpl(width, height, d, false);
     }
@@ -811,7 +811,7 @@ class BasicImage
             image.resize(new_width, new_height, SkipInitialization);
             \endcode
         */
-    void resize(int width, int height, SkipInitializationTag)
+    void resize(std::ptrdiff_t width, std::ptrdiff_t height, SkipInitializationTag)
     {
         resizeImpl(width, height, NumericTraits<value_type>::zero(), 
                    CanSkipInitialization<value_type>::value);
@@ -820,7 +820,7 @@ class BasicImage
         /** resize image to given size and initialize by copying data
             from the C-style array \a data.
         */
-    void resizeCopy(int width, int height, const_pointer data);
+    void resizeCopy(std::ptrdiff_t width, std::ptrdiff_t height, const_pointer data);
 
         /** resize image to size of other image and copy its data
         */
@@ -835,14 +835,14 @@ class BasicImage
 
         /** width of Image
         */
-    int width() const
+    std::ptrdiff_t width() const
     {
         return width_;
     }
 
         /** height of Image
         */
-    int height() const
+    std::ptrdiff_t height() const
     {
         return height_;
     }
@@ -883,7 +883,7 @@ class BasicImage
         /** access pixel at given location. <br>
         usage: <TT> value_type value = image(1,2) </TT>
         */
-    reference operator()(int dx, int dy)
+    reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy)
     {
         VIGRA_ASSERT_INSIDE(difference_type(dx,dy));
         return lines_[dy][dx];
@@ -892,7 +892,7 @@ class BasicImage
         /** read pixel at given location. <br>
         usage: <TT> value_type value = image(1,2) </TT>
         */
-    const_reference operator()(int dx, int dy) const
+    const_reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy) const
     {
         VIGRA_ASSERT_INSIDE(difference_type(dx,dy));
         return lines_[dy][dx];
@@ -902,7 +902,7 @@ class BasicImage
             Note that the 'x' index is the trailing index. <br>
         usage: <TT> value_type value = image[2][1] </TT>
         */
-    pointer operator[](int dy)
+    pointer operator[](std::ptrdiff_t dy)
     {
         VIGRA_ASSERT_INSIDE(difference_type(0,dy));
         return lines_[dy];
@@ -912,7 +912,7 @@ class BasicImage
             Note that the 'x' index is the trailing index. <br>
         usage: <TT> value_type value = image[2][1] </TT>
         */
-    const_pointer operator[](int dy) const
+    const_pointer operator[](std::ptrdiff_t dy) const
     {
         VIGRA_ASSERT_INSIDE(difference_type(0,dy));
         return lines_[dy];
@@ -996,35 +996,35 @@ class BasicImage
 
         /** init 1D random access iterator pointing to first pixel of row \a y
         */
-    row_iterator rowBegin(int y)
+    row_iterator rowBegin(std::ptrdiff_t y)
     {
         return lines_[y];
     }
 
         /** init 1D random access iterator pointing past the end of row \a y
         */
-    row_iterator rowEnd(int y)
+    row_iterator rowEnd(std::ptrdiff_t y)
     {
         return rowBegin(y) + width();
     }
 
         /** init 1D random access const iterator pointing to first pixel of row \a y
         */
-    const_row_iterator rowBegin(int y) const
+    const_row_iterator rowBegin(std::ptrdiff_t y) const
     {
         return lines_[y];
     }
 
         /** init 1D random access const iterator pointing past the end of row \a y
         */
-    const_row_iterator rowEnd(int y) const
+    const_row_iterator rowEnd(std::ptrdiff_t y) const
     {
         return rowBegin(y) + width();
     }
 
         /** init 1D random access iterator pointing to first pixel of column \a x
         */
-    column_iterator columnBegin(int x)
+    column_iterator columnBegin(std::ptrdiff_t x)
     {
         typedef typename column_iterator::BaseType Iter;
         return column_iterator(Iter(lines_, x));
@@ -1032,14 +1032,14 @@ class BasicImage
 
         /** init 1D random access iterator pointing past the end of column \a x
         */
-    column_iterator columnEnd(int x)
+    column_iterator columnEnd(std::ptrdiff_t x)
     {
         return columnBegin(x) + height();
     }
 
         /** init 1D random access const iterator pointing to first pixel of column \a x
         */
-    const_column_iterator columnBegin(int x) const
+    const_column_iterator columnBegin(std::ptrdiff_t x) const
     {
         typedef typename const_column_iterator::BaseType Iter;
         return const_column_iterator(Iter(lines_, x));
@@ -1047,7 +1047,7 @@ class BasicImage
 
         /** init 1D random access const iterator pointing past the end of column \a x
         */
-    const_column_iterator columnEnd(int x) const
+    const_column_iterator columnEnd(std::ptrdiff_t x) const
     {
         return columnBegin(x) + height();
     }
@@ -1076,14 +1076,14 @@ class BasicImage
   private:
 
     void deallocate();
-    void resizeImpl(int width, int height, value_type const & d, bool skipInit);
+    void resizeImpl(std::ptrdiff_t width, std::ptrdiff_t height, value_type const & d, bool skipInit);
 
 
-    value_type ** initLineStartArray(value_type * data, int width, int height);
+    value_type ** initLineStartArray(value_type * data, std::ptrdiff_t width, std::ptrdiff_t height);
 
     PIXELTYPE * data_;
     PIXELTYPE ** lines_;
-    int width_, height_;
+    std::ptrdiff_t width_, height_;
     Alloc allocator_;
     LineAllocator pallocator_;
 };
@@ -1137,7 +1137,7 @@ BasicImage<PIXELTYPE, Alloc>::init(value_type const & pixel)
 
 template <class PIXELTYPE, class Alloc>
 void
-BasicImage<PIXELTYPE, Alloc>::resizeImpl(int width, int height, value_type const & d, bool skipInit)
+BasicImage<PIXELTYPE, Alloc>::resizeImpl(std::ptrdiff_t width, std::ptrdiff_t height, value_type const & d, bool skipInit)
 {
     vigra_precondition((width >= 0) && (height >= 0),
          "BasicImage::resize(int width, int height, value_type const &): "
@@ -1188,9 +1188,9 @@ BasicImage<PIXELTYPE, Alloc>::resizeImpl(int width, int height, value_type const
 
 template <class PIXELTYPE, class Alloc>
 void
-BasicImage<PIXELTYPE, Alloc>::resizeCopy(int width, int height, const_pointer data)
+BasicImage<PIXELTYPE, Alloc>::resizeCopy(std::ptrdiff_t width, std::ptrdiff_t height, const_pointer data)
 {
-    int newsize = width*height;
+    std::ptrdiff_t newsize = width*height;
     if (width_ != width || height_ != height)  // change size?
     {
         value_type * newdata = 0;
@@ -1259,10 +1259,10 @@ BasicImage<PIXELTYPE, Alloc>::deallocate()
 
 template <class PIXELTYPE, class Alloc>
 PIXELTYPE **
-BasicImage<PIXELTYPE, Alloc>::initLineStartArray(value_type * data, int width, int height)
+BasicImage<PIXELTYPE, Alloc>::initLineStartArray(value_type * data, std::ptrdiff_t width, std::ptrdiff_t height)
 {
     value_type ** lines = pallocator_.allocate(typename Alloc::size_type(height));
-    for(int y=0; y<height; ++y)
+    for(std::ptrdiff_t y=0; y<height; ++y)
          lines[y] = data + y*width;
     return lines;
 }
diff --git a/include/vigra/basicimageview.hxx b/include/vigra/basicimageview.hxx
index bc9f04b..db4a9ea 100644
--- a/include/vigra/basicimageview.hxx
+++ b/include/vigra/basicimageview.hxx
@@ -182,7 +182,7 @@ class BasicImageView
 
         /** construct view of size w x h
         */
-    BasicImageView(const_pointer data, int w, int h, int stride = 0)
+    BasicImageView(const_pointer data, std::ptrdiff_t w, std::ptrdiff_t h, std::ptrdiff_t stride = 0)
     : data_(const_cast<pointer>(data)),
       width_(w),
       height_(h),
@@ -191,7 +191,7 @@ class BasicImageView
 
         /** construct view of size size.x x size.y
         */
-    BasicImageView(const_pointer data, difference_type const & size, int stride = 0)
+    BasicImageView(const_pointer data, difference_type const & size, std::ptrdiff_t stride = 0)
     : data_(const_cast<pointer>(data)),
       width_(size.x),
       height_(size.y),
@@ -209,14 +209,14 @@ class BasicImageView
 
         /** width of Image
         */
-    int width() const
+    std::ptrdiff_t width() const
     {
         return width_;
     }
 
         /** height of Image
         */
-    int height() const
+    std::ptrdiff_t height() const
     {
         return height_;
     }
@@ -224,7 +224,7 @@ class BasicImageView
         /** stride of Image.
             Memory offset between the start of two successive rows.
         */
-    int stride() const
+    std::ptrdiff_t stride() const
     {
         return stride_;
     }
@@ -265,7 +265,7 @@ class BasicImageView
         /** access pixel at given location. <br>
         usage: <TT> value_type value = image(1,2) </TT>
         */
-    reference operator()(int dx, int dy)
+    reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy)
     {
         VIGRA_ASSERT_INSIDE(difference_type(dx,dy));
         return data_[dy*stride_ + dx];
@@ -274,7 +274,7 @@ class BasicImageView
         /** read pixel at given location. <br>
         usage: <TT> value_type value = image(1,2) </TT>
         */
-    const_reference operator()(int dx, int dy) const
+    const_reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy) const
     {
         VIGRA_ASSERT_INSIDE(difference_type(dx, dy));
         return data_[dy*stride_ + dx];
@@ -284,7 +284,7 @@ class BasicImageView
             Note that the 'x' index is the trailing index. <br>
         usage: <TT> value_type value = image[2][1] </TT>
         */
-    pointer operator[](int dy)
+    pointer operator[](std::ptrdiff_t dy)
     {
         VIGRA_ASSERT_INSIDE(difference_type(0, dy));
         return data_ + dy*stride_;
@@ -294,7 +294,7 @@ class BasicImageView
             Note that the 'x' index is the trailing index. <br>
         usage: <TT> value_type value = image[2][1] </TT>
         */
-    const_pointer operator[](int dy) const
+    const_pointer operator[](std::ptrdiff_t dy) const
     {
         VIGRA_ASSERT_INSIDE(difference_type(0,dy));
         return data_ + dy*stride_;
@@ -378,35 +378,35 @@ class BasicImageView
 
         /** init 1D random access iterator pointing to first pixel of row \a y
         */
-    row_iterator rowBegin(int y)
+    row_iterator rowBegin(std::ptrdiff_t y)
     {
         return data_ + stride_ * y;
     }
 
         /** init 1D random access iterator pointing past the end of row \a y
         */
-    row_iterator rowEnd(int y)
+    row_iterator rowEnd(std::ptrdiff_t y)
     {
         return rowBegin(y) + width();
     }
 
         /** init 1D random access const iterator pointing to first pixel of row \a y
         */
-    const_row_iterator rowBegin(int y) const
+    const_row_iterator rowBegin(std::ptrdiff_t y) const
     {
         return data_ + stride_ * y;
     }
 
         /** init 1D random access const iterator pointing past the end of row \a y
         */
-    const_row_iterator rowEnd(int y) const
+    const_row_iterator rowEnd(std::ptrdiff_t y) const
     {
         return rowBegin(y) + width();
     }
 
         /** init 1D random access iterator pointing to first pixel of column \a x
         */
-    column_iterator columnBegin(int x)
+    column_iterator columnBegin(std::ptrdiff_t x)
     {
         typedef typename column_iterator::BaseType Iter;
         return column_iterator(Iter(data_ + x, stride_));
@@ -414,14 +414,14 @@ class BasicImageView
 
         /** init 1D random access iterator pointing past the end of column \a x
         */
-    column_iterator columnEnd(int x)
+    column_iterator columnEnd(std::ptrdiff_t x)
     {
         return columnBegin(x) + height();
     }
 
         /** init 1D random access const iterator pointing to first pixel of column \a x
         */
-    const_column_iterator columnBegin(int x) const
+    const_column_iterator columnBegin(std::ptrdiff_t x) const
     {
         typedef typename const_column_iterator::BaseType Iter;
         return const_column_iterator(Iter(data_ + x, stride_));
@@ -429,7 +429,7 @@ class BasicImageView
 
         /** init 1D random access const iterator pointing past the end of column \a x
         */
-    const_column_iterator columnEnd(int x) const
+    const_column_iterator columnEnd(std::ptrdiff_t x) const
     {
         return columnBegin(x) + height();
     }
@@ -458,7 +458,7 @@ class BasicImageView
   private:
 
     pointer data_;
-    int width_, height_, stride_;
+    std::ptrdiff_t width_, height_, stride_;
 };
 
 
diff --git a/include/vigra/blockify.hxx b/include/vigra/blockify.hxx
new file mode 100644
index 0000000..122f31f
--- /dev/null
+++ b/include/vigra/blockify.hxx
@@ -0,0 +1,121 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_BLOCKIFY_HXX
+#define VIGRA_BLOCKIFY_HXX
+
+#include "multi_array.hxx"
+
+namespace vigra
+{
+
+namespace blockify_detail
+{
+
+template <unsigned int CurrentDimensions>
+struct blockify_impl
+{
+    // for CurrentDimension >= 1
+    template <unsigned int N, class T, class S, class Shape>
+    static void make(MultiArrayView<N, T, S>& source, 
+                     MultiArrayView<N, MultiArrayView<N, T, S> >& blocks,
+                     Shape current_block_begin,
+                     Shape current_block_end,
+                     Shape current_block_pos,
+                     Shape block_shape)
+    {
+        typedef typename Shape::value_type size_type;
+        enum{ n = CurrentDimensions - 1};
+
+        size_type blocks_extend = blocks.shape(n);
+        
+        vigra_assert(blocks_extend != 0, "");
+        for(current_block_pos[n] = 0, current_block_begin[n] = 0, current_block_end[n] = block_shape[n];
+            current_block_pos[n] != blocks_extend - 1;
+            ++current_block_pos[n],
+                current_block_begin[n] += block_shape[n], 
+                current_block_end[n] += block_shape[n])
+        {
+            blockify_impl<n>::make(source, blocks, current_block_begin, current_block_end, current_block_pos, block_shape);
+        }
+        current_block_end[n] = source.shape(n);
+        blockify_impl<n>::make(source, blocks, current_block_begin, current_block_end, current_block_pos, block_shape);
+    }
+};
+
+template <>
+struct blockify_impl<0>
+{
+    template <unsigned int N, class T, class S, class Shape>
+    static void make(MultiArrayView<N, T, S>& source, 
+                     MultiArrayView<N, MultiArrayView<N, T, S> >& blocks,
+                     Shape current_block_begin,
+                     Shape current_block_end,
+                     Shape current_block_pos,
+                     Shape block_shape)
+    {
+        blocks[current_block_pos] = source.subarray(current_block_begin, current_block_end);
+    }
+};
+
+} // namespace blockify_detail
+
+template <unsigned int N, class T, class S>
+MultiArray<N, MultiArrayView<N, T, S> >
+blockify(MultiArrayView<N, T, S> source, typename MultiArrayView<N, T, S>::difference_type block_shape)
+{
+    using namespace blockify_detail;
+    typedef typename MultiArrayView<N, T, S>::difference_type Shape;
+
+    Shape blocks_shape;
+    for(unsigned int n = 0; n != N; ++n)
+    {
+        blocks_shape[n] = source.shape(n) / block_shape[n];
+        if(blocks_shape[n] * block_shape[n] != source.shape(n))
+            ++blocks_shape[n];
+    }
+    MultiArray<N, MultiArrayView<N, T, S> > blocks(blocks_shape);
+    if(source.size() == 0)
+        return blocks;
+    Shape a;
+    Shape b;
+    Shape c;
+    blockify_impl<N>::make(source, blocks, a, b, c, block_shape);
+    return blocks;
+}
+
+} // namespace vigra
+
+#endif // VIGRA_BLOCKIFY_HXX
diff --git a/include/vigra/blockwise_convolution.hxx b/include/vigra/blockwise_convolution.hxx
new file mode 100644
index 0000000..1ca7151
--- /dev/null
+++ b/include/vigra/blockwise_convolution.hxx
@@ -0,0 +1,140 @@
+#ifndef VIGRA_BLOCKWISE_CONVOLUTION_HXX_
+#define VIGRA_BLOCKWISE_CONVOLUTION_HXX_
+
+#include <vigra/overlapped_blocks.hxx>
+#include <vigra/multi_convolution.hxx>
+#include <vigra/blockify.hxx>
+#include <vigra/multi_array.hxx>
+
+namespace vigra
+{
+
+namespace blockwise_convolution_detail
+{
+
+template <class DataArray, class OutputBlocksIterator, class KernelIterator>
+void convolveImpl(const Overlaps<DataArray>& overlaps, OutputBlocksIterator output_blocks_begin, KernelIterator kit)
+{
+    static const unsigned int N = DataArray::actual_dimension;
+    typedef typename MultiArrayShape<N>::type Shape;
+    typedef typename OutputBlocksIterator::value_type OutputBlock;
+
+    Shape shape = overlaps.shape();
+    vigra_assert(shape == output_blocks_begin.shape(), "");
+
+    MultiCoordinateIterator<N> it(shape);
+    MultiCoordinateIterator<N> end = it.getEndIterator();
+    for( ; it != end; ++it)
+    {
+        OutputBlock output_block = output_blocks_begin[*it];
+        OverlappingBlock<DataArray> data_block = overlaps[*it];
+        separableConvolveMultiArray(data_block.block, output_block, kit, data_block.inner_bounds.first, data_block.inner_bounds.second);
+    }
+}
+
+template <class Shape, class KernelIterator>
+std::pair<Shape, Shape> kernelOverlap(KernelIterator kit)
+{
+    Shape before;
+    Shape after;
+
+    for(unsigned int i = 0; i != Shape::static_size; ++i, ++kit)
+    {
+        // FIXME: is this correct?
+        before[i] = kit->right();
+        after[i] = -kit->left();
+    }
+    return std::make_pair(before, after);
+}
+
+}
+
+
+template <unsigned int N, class T1, class S1,
+                          class T2, class S2,
+          class KernelIterator>
+void separableConvolveBlockwise(MultiArrayView<N, T1, S1> source, MultiArrayView<N, T2, S2> dest, KernelIterator kit,
+                                const typename MultiArrayView<N, T1, S1>::difference_type& block_shape =
+                                     typename MultiArrayView<N, T1, S1>::difference_type(128))
+{
+    using namespace blockwise_convolution_detail;
+
+    typedef typename MultiArrayView<N, T1, S1>::difference_type Shape;
+    
+    Shape shape = source.shape();
+    vigra_precondition(shape == dest.shape(), "shape mismatch of source and destination");
+    
+    std::pair<Shape, Shape> overlap = kernelOverlap<Shape, KernelIterator>(kit);
+    Overlaps<MultiArrayView<N, T2, S2> > overlaps(source, block_shape, overlap.first, overlap.second);
+
+    MultiArray<N, MultiArrayView<N, T2, S2> > destination_blocks = blockify(dest, block_shape);
+    
+    convolveImpl(overlaps, destination_blocks.begin(), kit);
+}
+template <unsigned int N, class T1, class S1,
+                          class T2, class S2,
+          class T3>
+void separableConvolveBlockwise(MultiArrayView<N, T1, S1> source, MultiArrayView<N, T2, S2> dest, const Kernel1D<T3>& kernel,
+                                const typename MultiArrayView<N, T1, S1>::difference_type& block_shape =
+                                     typename MultiArrayView<N, T1, S1>::difference_type(128))
+{
+    std::vector<Kernel1D<T3> > kernels(N, kernel);
+    separableConvolveBlockwise(source, dest, kernels.begin(), block_shape);
+}
+
+
+/*******************************************************/
+/*                                                     */
+/*              separableConvolveBlockwise             */
+/*                                                     */
+/*******************************************************/
+
+/** \brief Separated convolution on ChunkedArrays.
+
+    <b> Declarations:</b>
+
+    \code
+    namespace vigra {
+        // apply each kernel from the sequence 'kernels' in turn
+        template <unsigned int N, class T1, class T2, class KernelIterator>
+        void separableConvolveBlockwise(const ChunkedArra<N, T1>& source, ChunkedArray<N, T2>& destination, KernelIterator kernels);
+        // apply the same kernel to all dimensions
+        template <unsigned int N, class T1, class T2, class T3>
+        void separableConvolveBlockwise(const ChunkedArra<N, T1>& source, ChunkedArray<N, T2>& destination, Kernel1D<T3> const & kernel);
+    }
+    \endcode
+
+    This function computes a separated convolution for a given \ref ChunkedArray. For infinite precision T1, this is equivalent to
+    \ref separableConvolveMultiArray. In practice, floating point inaccuracies will make the result differ slightly.
+*/
+doxygen_overloaded_function(template <...> void separableConvolveBlockwise)
+
+template <unsigned int N, class T1, class T2, class KernelIterator>
+void separableConvolveBlockwise(const ChunkedArray<N, T1>& source, ChunkedArray<N, T2>& destination, KernelIterator kit)
+{
+    using namespace blockwise_convolution_detail;
+
+    typedef typename ChunkedArray<N, T1>::shape_type Shape;
+    
+    Shape shape = source.shape();
+    vigra_precondition(shape == destination.shape(), "shape mismatch of source and destination");
+
+    std::pair<Shape, Shape> overlap = kernelOverlap<Shape, KernelIterator>(kit);
+    Shape block_shape = source.chunkShape();
+    vigra_precondition(block_shape == destination.chunkShape(), "chunk shapes do not match");
+    Overlaps<ChunkedArray<N, T1> > overlaps(source, block_shape, overlap.first, overlap.second);
+    
+    convolveImpl(overlaps, destination.chunk_begin(Shape(0), shape), kit);
+}
+template <unsigned int N, class T1, class T2, class T>
+void separableConvolveBlockwise(const ChunkedArray<N, T1>& source, ChunkedArray<N, T2>& destination, const Kernel1D<T>& kernel)
+{
+    std::vector<Kernel1D<T> > kernels(N, kernel);
+    separableConvolveBlockse(source, destination, kernels.begin());
+}
+
+
+}
+
+#endif
+
diff --git a/include/vigra/blockwise_labeling.hxx b/include/vigra/blockwise_labeling.hxx
new file mode 100644
index 0000000..5f4756d
--- /dev/null
+++ b/include/vigra/blockwise_labeling.hxx
@@ -0,0 +1,502 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_BLOCKWISE_LABELING_HXX
+#define VIGRA_BLOCKWISE_LABELING_HXX
+
+#include <algorithm>
+
+#include "threadpool.hxx"
+#include "counting_iterator.hxx"
+#include "multi_gridgraph.hxx"
+#include "multi_labeling.hxx"
+#include "multi_blockwise.hxx"
+#include "union_find.hxx"
+#include "multi_array_chunked.hxx"
+#include "metaprogramming.hxx"
+
+#include "visit_border.hxx"
+#include "blockify.hxx"
+
+namespace vigra
+{
+
+/** \addtogroup Labeling
+*/
+//@{
+
+    /** Options object for labelMultiArrayBlockwise().
+
+        It is simply a subclass of both \ref vigra::LabelOptions
+        and \ref vigra::BlockwiseOptions. See there for
+        detailed documentation.
+    */
+class BlockwiseLabelOptions
+: public LabelOptions
+, public BlockwiseOptions
+{
+public:
+    typedef BlockwiseOptions::Shape Shape;
+
+    // reimplement setter functions to allow chaining
+
+    template <class T>
+    BlockwiseLabelOptions& ignoreBackgroundValue(const T& value)
+    {
+        LabelOptions::ignoreBackgroundValue(value);
+        return *this;
+    }
+
+    BlockwiseLabelOptions & neighborhood(NeighborhoodType n)
+    {
+        LabelOptions::neighborhood(n);
+        return *this;
+    }
+
+    BlockwiseLabelOptions & blockShape(const Shape & shape)
+    {
+        BlockwiseOptions::blockShape(shape);
+        return *this;
+    }
+
+    template <class T, int N>
+    BlockwiseLabelOptions & blockShape(const TinyVector<T, N> & shape)
+    {
+        BlockwiseOptions::blockShape(shape);
+        return *this;
+    }
+
+    BlockwiseLabelOptions & numThreads(const int n)
+    {
+        BlockwiseOptions::numThreads(n);
+        return *this;
+    }
+};
+
+namespace blockwise_labeling_detail
+{
+
+template <class Equal, class Label>
+struct BorderVisitor
+{
+    Label u_label_offset;
+    Label v_label_offset;
+    UnionFindArray<Label>* global_unions;
+    Equal* equal;
+
+    template <class Data, class Shape>
+    void operator()(const Data& u_data, Label& u_label, const Data& v_data, Label& v_label, const Shape& diff)
+    {
+        if(labeling_equality::callEqual(*equal, u_data, v_data, diff))
+        {
+            global_unions->makeUnion(u_label + u_label_offset, v_label + v_label_offset);
+        }
+    }
+};
+
+// needed by MSVC
+template <class LabelBlocksIterator>
+struct BlockwiseLabelingResult
+{
+    typedef typename LabelBlocksIterator::value_type::value_type type;
+};
+
+template <class DataBlocksIterator, class LabelBlocksIterator,
+          class Equal, class Mapping>
+typename BlockwiseLabelingResult<LabelBlocksIterator>::type
+blockwiseLabeling(DataBlocksIterator data_blocks_begin, DataBlocksIterator data_blocks_end,
+                  LabelBlocksIterator label_blocks_begin, LabelBlocksIterator label_blocks_end,
+                  BlockwiseLabelOptions const & options,
+                  Equal equal,
+                  Mapping& mapping)
+{
+    typedef typename LabelBlocksIterator::value_type::value_type Label;
+    typedef typename DataBlocksIterator::shape_type Shape;
+
+    Shape blocks_shape = data_blocks_begin.shape();
+    vigra_precondition(blocks_shape == label_blocks_begin.shape() &&
+                       blocks_shape == mapping.shape(),
+                       "shapes of blocks of blocks do not match");
+
+    static const unsigned int Dimensions = DataBlocksIterator::dimension + 1;
+    MultiArray<Dimensions, Label> label_offsets(label_blocks_begin.shape());
+
+    bool has_background = options.hasBackgroundValue();
+
+    // mapping stage: label each block and save number of labels assigned in blocks before the current block in label_offsets
+    Label unmerged_label_number;
+    {
+        DataBlocksIterator data_blocks_it = data_blocks_begin;
+        LabelBlocksIterator label_blocks_it = label_blocks_begin;
+        typename MultiArray<Dimensions, Label>::iterator offsets_it = label_offsets.begin();
+        Label current_offset = 0;
+        // a la OPENMP_PRAGMA FOR
+
+        auto d = std::distance(data_blocks_begin, data_blocks_end);
+
+
+        std::vector<Label> nSeg(d);
+        //std::vector<int> ids(d);
+        //std::iota(ids.begin(), ids.end(), 0 );
+
+        parallel_foreach(options.getNumThreads(), d,
+            [&](const int threadId, const uint64_t i){
+                Label resVal = labelMultiArray(data_blocks_it[i], label_blocks_it[i],
+                                               options, equal);
+                if(has_background) // FIXME: reversed condition?
+                    ++resVal;
+                nSeg[i] = resVal;
+            }
+        );
+
+        for(int i=0; i<d;++i){
+            offsets_it[i] = current_offset;
+            current_offset+=nSeg[i];
+        }
+
+
+        unmerged_label_number = current_offset;
+        if(!has_background)
+            ++unmerged_label_number;
+    }
+
+    // reduce stage: merge adjacent labels if the region overlaps
+    UnionFindArray<Label> global_unions(unmerged_label_number);
+    if(has_background)
+    {
+        // merge all labels that refer to background
+        for(typename MultiArray<Dimensions, Label>::iterator offsets_it = label_offsets.begin();
+                offsets_it != label_offsets.end();
+                ++offsets_it)
+        {
+            global_unions.makeUnion(0, *offsets_it);
+        }
+    }
+
+    typedef GridGraph<Dimensions, undirected_tag> Graph;
+    typedef typename Graph::edge_iterator EdgeIterator;
+    Graph blocks_graph(blocks_shape, options.getNeighborhood());
+    for(EdgeIterator it = blocks_graph.get_edge_iterator(); it != blocks_graph.get_edge_end_iterator(); ++it)
+    {
+        Shape u = blocks_graph.u(*it);
+        Shape v = blocks_graph.v(*it);
+        Shape difference = v - u;
+
+        BorderVisitor<Equal, Label> border_visitor;
+        border_visitor.u_label_offset = label_offsets[u];
+        border_visitor.v_label_offset = label_offsets[v];
+        border_visitor.global_unions = &global_unions;
+        border_visitor.equal = &equal;
+        visitBorder(data_blocks_begin[u], label_blocks_begin[u],
+                    data_blocks_begin[v], label_blocks_begin[v],
+                    difference, options.getNeighborhood(), border_visitor);
+    }
+
+    // fill mapping (local labels) -> (global labels)
+    Label last_label = global_unions.makeContiguous();
+    {
+        typename MultiArray<Dimensions, Label>::iterator offsets_it = label_offsets.begin();
+        Label offset = *offsets_it;
+        ++offsets_it;
+        typename Mapping::iterator mapping_it = mapping.begin();
+        for( ; offsets_it != label_offsets.end(); ++offsets_it, ++mapping_it)
+        {
+            mapping_it->clear();
+            Label next_offset = *offsets_it;
+            if(has_background)
+            {
+                for(Label current_label = offset; current_label != next_offset; ++current_label)
+                {
+                    mapping_it->push_back(global_unions.findLabel(current_label));
+                }
+            }
+            else
+            {
+                mapping_it->push_back(0); // local labels start at 1
+                for(Label current_label = offset + 1; current_label != next_offset + 1; ++current_label)
+                {
+                    mapping_it->push_back(global_unions.findLabel(current_label));
+                }
+            }
+
+            offset = next_offset;
+        }
+        // last block:
+        // instead of next_offset, use last_label+1
+        mapping_it->clear();
+        if(has_background)
+        {
+            for(Label current_label = offset; current_label != unmerged_label_number; ++current_label)
+            {
+                mapping_it->push_back(global_unions.findLabel(current_label));
+            }
+        }
+        else
+        {
+            mapping_it->push_back(0);
+            for(Label current_label = offset + 1; current_label != unmerged_label_number; ++current_label)
+            {
+                mapping_it->push_back(global_unions.findLabel(current_label));
+            }
+        }
+    }
+    return last_label;
+}
+
+
+template <class LabelBlocksIterator, class MappingIterator>
+void toGlobalLabels(LabelBlocksIterator label_blocks_begin, LabelBlocksIterator label_blocks_end,
+                    MappingIterator mapping_begin, MappingIterator mapping_end)
+{
+    typedef typename LabelBlocksIterator::value_type LabelBlock;
+    for( ; label_blocks_begin != label_blocks_end; ++label_blocks_begin, ++mapping_begin)
+    {
+        vigra_assert(mapping_begin != mapping_end, "");
+        for(typename LabelBlock::iterator labels_it = label_blocks_begin->begin();
+            labels_it != label_blocks_begin->end();
+            ++labels_it)
+        {
+            vigra_assert(*labels_it < mapping_begin->size(), "");
+            *labels_it = (*mapping_begin)[*labels_it];
+        }
+    }
+}
+
+} // namespace blockwise_labeling_detail
+
+/*************************************************************/
+/*                                                           */
+/*                      labelMultiArrayBlockwise             */
+/*                                                           */
+/*************************************************************/
+
+/** \brief Connected components labeling for MultiArrays and ChunkedArrays.
+
+    <b> Declarations:</b>
+
+    \code
+    namespace vigra {
+        // assign local labels and generate mapping (local labels) -> (global labels) for each chunk
+        template <unsigned int N, class Data, class S1,
+                                  class Label, class S2,
+                  class Equal, class S3>
+        Label labelMultiArrayBlockwise(const MultiArrayView<N, Data, S1>& data,
+                                       MultiArrayView<N, Label, S2> labels,
+                                       const BlockwiseLabelOptions& options,
+                                       Equal equal,
+                                       MultiArrayView<N, std::vector<Label>, S3>& mapping);
+
+        // assign local labels and generate mapping (local labels) -> (global labels) for each chunk
+        template <unsigned int N, class T, class S1,
+                                  class Label, class S2,
+                  class EqualityFunctor>
+        Label labelMultiArrayBlockwise(const ChunkedArray<N, Data>& data,
+                                       ChunkedArray<N, Label>& labels,
+                                       const BlockwiseLabelOptions& options,
+                                       Equal equal,
+                                       MultiArrayView<N, std::vector<Label>, S3>& mapping);
+
+        // assign global labels
+        template <unsigned int N, class Data, class S1,
+                                  class Label, class S2,
+                  class Equal>
+        Label labelMultiArrayBlockwise(const MultiArrayView<N, Data, S1>& data,
+                                       MultiArrayView<N, Label, S2> labels,
+                                       const BlockwiseLabelOptions& options,
+                                       Equal equal);
+
+        // assign global labels
+        template <unsigned int N, class T, class S1,
+                                  class Label, class S2,
+                  class EqualityFunctor = std::equal_to<T> >
+        Label labelMultiArrayBlockwise(const ChunkedArray<N, Data>& data,
+                                       ChunkedArray<N, Label>& labels,
+                                       const BlockwiseLabelOptions& options = BlockwiseLabelOptions(),
+                                       Equal equal = std::equal_to<T>());
+    }
+    \endcode
+
+    The resulting labeling is equivalent to a labeling by \ref labelMultiArray, that is, the connected components are the same but may have different ids.
+    \ref NeighborhoodType and background value (if any) can be specified with the LabelOptions object.
+    If the \a mapping parameter is provided, each chunk is labeled seperately and contiguously (starting at one, zero for background),
+    with \a mapping containing a mapping of local labels to global labels for each chunk.
+    Thus, the shape of 'mapping' has to be large enough to hold each chunk coordinate.
+
+    Return: the number of regions found (=largest global region label)
+
+    <b> Usage: </b>
+
+    <b>\#include </b> \<vigra/blockwise_labeling.hxx\><br>
+    Namespace: vigra
+
+    \code
+    Shape3 shape = Shape3(10);
+    Shape3 chunk_shape = Shape3(4);
+    ChunkedArrayLazy<3, int> data(shape, chunk_shape);
+    // fill data ...
+
+    ChunkedArrayLazy<3, size_t> labels(shape, chunk_shape);
+
+    MultiArray<3, std::vector<size_t> > mapping(Shape3(3)); // there are 3 chunks in each dimension
+
+    labelMultiArrayBlockwise(data, labels, LabelOptions().neighborhood(DirectNeighborhood).background(0),
+                             std::equal_to<int>(), mapping);
+
+    // check out chunk in the middle
+    MultiArray<3, size_t> middle_chunk(Shape3(4));
+    labels.checkoutSubarray(Shape3(4), middle_chunk);
+
+    // print number of non-background labels assigned in middle_chunk
+    cout << mapping[Shape3(1)].size() << endl;
+
+    // get local label for voxel
+    // this may be the same value assigned to different component in another chunk
+    size_t local_label = middle_chunk[Shape3(2)];
+    // get global label for voxel
+    // if another voxel has the same label, they are in the same connected component albeit they may be in different chunks
+    size_t global_label = mapping[Shape3(1)][local_label
+    \endcode
+    */
+doxygen_overloaded_function(template <...> unsigned int labelMultiArrayBlockwise)
+
+template <unsigned int N, class Data, class S1,
+                          class Label, class S2,
+          class Equal, class S3>
+Label labelMultiArrayBlockwise(const MultiArrayView<N, Data, S1>& data,
+                               MultiArrayView<N, Label, S2> labels,
+                               const BlockwiseLabelOptions& options,
+                               Equal equal,
+                               MultiArrayView<N, std::vector<Label>, S3>& mapping)
+{
+    using namespace blockwise_labeling_detail;
+
+    typedef typename MultiArrayShape<N>::type Shape;
+    Shape block_shape(options.getBlockShapeN<N>());
+
+    MultiArray<N, MultiArrayView<N, Data, S1> > data_blocks = blockify(data, block_shape);
+    MultiArray<N, MultiArrayView<N, Label, S2> > label_blocks = blockify(labels, block_shape);
+    return blockwiseLabeling(data_blocks.begin(), data_blocks.end(),
+                             label_blocks.begin(), label_blocks.end(),
+                             options, equal, mapping);
+}
+
+template <unsigned int N, class Data, class S1,
+                          class Label, class S2,
+          class Equal>
+Label labelMultiArrayBlockwise(const MultiArrayView<N, Data, S1>& data,
+                               MultiArrayView<N, Label, S2> labels,
+                               const BlockwiseLabelOptions& options,
+                               Equal equal)
+{
+    using namespace blockwise_labeling_detail;
+
+    typedef typename MultiArrayShape<N>::type Shape;
+    Shape block_shape(options.getBlockShapeN<N>());
+
+    MultiArray<N, MultiArrayView<N, Data, S1> > data_blocks = blockify(data, block_shape);
+    MultiArray<N, MultiArrayView<N, Label, S2> > label_blocks = blockify(labels, block_shape);
+    MultiArray<N, std::vector<Label> > mapping(data_blocks.shape());
+    Label last_label = blockwiseLabeling(data_blocks.begin(), data_blocks.end(),
+                                         label_blocks.begin(), label_blocks.end(),
+                                         options, equal, mapping);
+
+    // replace local labels by global labels
+    toGlobalLabels(label_blocks.begin(), label_blocks.end(), mapping.begin(), mapping.end());
+    return last_label;
+}
+
+template <unsigned int N, class Data, class S1,
+                          class Label, class S2>
+Label labelMultiArrayBlockwise(const MultiArrayView<N, Data, S1>& data,
+                               MultiArrayView<N, Label, S2> labels,
+                               const BlockwiseLabelOptions& options = BlockwiseLabelOptions())
+{
+    return labelMultiArrayBlockwise(data, labels, options, std::equal_to<Data>());
+}
+
+
+template <unsigned int N, class Data, class Label, class Equal, class S3>
+Label labelMultiArrayBlockwise(const ChunkedArray<N, Data>& data,
+                               ChunkedArray<N, Label>& labels,
+                               const BlockwiseLabelOptions& options,
+                               Equal equal,
+                               MultiArrayView<N, std::vector<Label>, S3> mapping)
+{
+    using namespace blockwise_labeling_detail;
+
+    vigra_precondition(options.getBlockShape().size() == 0,
+        "labelMultiArrayBlockwise(ChunkedArray, ...): custom block shapes not supported "
+        "(always uses the array's chunk shape).");
+
+    typedef typename ChunkedArray<N, Data>::shape_type Shape;
+
+    typedef typename ChunkedArray<N, Data>::chunk_const_iterator DataChunkIterator;
+    typedef typename ChunkedArray<N, Label>::chunk_iterator LabelChunkIterator;
+
+    DataChunkIterator data_chunks_begin = data.chunk_begin(Shape(0), data.shape());
+    LabelChunkIterator label_chunks_begin = labels.chunk_begin(Shape(0), labels.shape());
+
+    return blockwiseLabeling(data_chunks_begin, data_chunks_begin.getEndIterator(),
+                             label_chunks_begin, label_chunks_begin.getEndIterator(),
+                             options, equal, mapping);
+}
+
+template <unsigned int N, class Data, class Label, class Equal>
+Label labelMultiArrayBlockwise(const ChunkedArray<N, Data>& data,
+                               ChunkedArray<N, Label>& labels,
+                               const BlockwiseLabelOptions& options,
+                               Equal equal)
+{
+    using namespace blockwise_labeling_detail;
+    MultiArray<N, std::vector<Label> > mapping(data.chunkArrayShape());
+    Label result = labelMultiArrayBlockwise(data, labels, options, equal, mapping);
+    typedef typename ChunkedArray<N, Data>::shape_type Shape;
+    toGlobalLabels(labels.chunk_begin(Shape(0), data.shape()), labels.chunk_end(Shape(0), data.shape()), mapping.begin(), mapping.end());
+    return result;
+}
+
+template <unsigned int N, class Data, class Label>
+Label labelMultiArrayBlockwise(const ChunkedArray<N, Data>& data,
+                               ChunkedArray<N, Label>& labels,
+                               const BlockwiseLabelOptions& options = BlockwiseLabelOptions())
+{
+    return labelMultiArrayBlockwise(data, labels, options, std::equal_to<Data>());
+}
+
+//@}
+
+} // namespace vigra
+
+#endif // VIGRA_BLOCKWISE_LABELING_HXX
diff --git a/include/vigra/blockwise_watersheds.hxx b/include/vigra/blockwise_watersheds.hxx
new file mode 100644
index 0000000..5ff25df
--- /dev/null
+++ b/include/vigra/blockwise_watersheds.hxx
@@ -0,0 +1,258 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_BLOCKWISE_WATERSHEDS_HXX
+#define VIGRA_BLOCKWISE_WATERSHEDS_HXX
+
+#include "threadpool.hxx"
+#include "multi_array.hxx"
+#include "multi_gridgraph.hxx"
+#include "blockify.hxx"
+#include "blockwise_labeling.hxx"
+#include "overlapped_blocks.hxx"
+
+#include <limits>
+
+namespace vigra
+{
+
+/** \addtogroup SeededRegionGrowing
+*/
+//@{
+
+namespace blockwise_watersheds_detail
+{
+
+template <class DataArray, class DirectionsBlocksIterator>
+void prepareBlockwiseWatersheds(const Overlaps<DataArray>& overlaps,
+                                DirectionsBlocksIterator directions_blocks_begin,
+                                BlockwiseLabelOptions const & options)
+{
+    static const unsigned int N = DataArray::actual_dimension;
+    typedef typename MultiArrayShape<DataArray::actual_dimension>::type Shape;
+    typedef typename DirectionsBlocksIterator::value_type DirectionsBlock;
+    Shape shape = overlaps.shape();
+    vigra_assert(shape == directions_blocks_begin.shape(), "");
+
+    MultiCoordinateIterator<DataArray::actual_dimension> itBegin(shape);
+    MultiCoordinateIterator<DataArray::actual_dimension> end = itBegin.getEndIterator();
+    typedef typename MultiCoordinateIterator<DataArray::actual_dimension>::value_type Coordinate;
+
+    parallel_foreach(options.getNumThreads(),
+        itBegin,end,
+        [&](const int threadId, const Coordinate  iterVal){
+
+            DirectionsBlock directions_block = directions_blocks_begin[iterVal];
+            OverlappingBlock<DataArray> data_block = overlaps[iterVal];
+
+            typedef GridGraph<DataArray::actual_dimension, undirected_tag> Graph;
+            typedef typename Graph::NodeIt GraphScanner;
+            typedef typename Graph::OutArcIt NeighborIterator;
+
+            Graph graph(data_block.block.shape(), options.getNeighborhood());
+            for(GraphScanner node(graph); node != lemon::INVALID; ++node)
+            {
+                if(within(*node, data_block.inner_bounds))
+                {
+                    typedef typename DataArray::value_type Data;
+                    Data lowest_neighbor = data_block.block[*node];
+
+                    typedef typename DirectionsBlock::value_type Direction;
+                    Direction lowest_neighbor_direction = std::numeric_limits<unsigned short>::max();
+
+                    for(NeighborIterator arc(graph, *node); arc != lemon::INVALID; ++arc)
+                    {
+                        Shape neighbor_coordinates = graph.target(*arc);
+                        Data neighbor_data = data_block.block[neighbor_coordinates];
+                        if(neighbor_data < lowest_neighbor)
+                        {
+                            lowest_neighbor = neighbor_data;
+                            lowest_neighbor_direction = arc.neighborIndex();
+                        }
+                    }
+                    directions_block[*node - data_block.inner_bounds.first] = lowest_neighbor_direction;
+                }
+            }
+        }
+    );
+}
+
+template <unsigned int N>
+struct UnionFindWatershedsEquality
+{
+    // FIXME: this graph object shouldn't be necessary, most functions (and state) of graph are not used
+    // this probably needs some refactoring in GridGraph
+    GridGraph<N, undirected_tag>* graph;
+
+    template <class Shape>
+    bool operator()(unsigned short u, const unsigned short v, const Shape& diff) const
+    {
+        static const unsigned short plateau_id = std::numeric_limits<unsigned short>::max();
+        return (u == plateau_id && v == plateau_id) ||
+               (u != plateau_id && graph->neighborOffset(u) == diff) ||
+               (v != plateau_id && graph->neighborOffset(graph->oppositeIndex(v)) == diff);
+    }
+
+    struct WithDiffTag
+    {};
+};
+
+} // namespace blockwise_watersheds_detail
+
+/*************************************************************/
+/*                                                           */
+/*                      unionFindWatershedsBlockwise         */
+/*                                                           */
+/*************************************************************/
+
+/** \brief Blockwise union-find watersheds transform for MultiArrays and ChunkedArrays.
+
+    <b> Declaration:</b>
+
+    \code
+    namespace vigra { namespace blockwise {
+        template <unsigned int N, class Data, class S1,
+                                  class Label, class S2>
+        Label
+        unionFindWatershedsBlockwise(MultiArrayView<N, Data, S1> data,
+                                     MultiArrayView<N, Label, S2> labels,
+                                     BlockwiseLabelOptions const & options);
+
+        template <unsigned int N, class Data, class Label>
+        Label
+        unionFindWatershedsBlockwise(const ChunkedArray<N, Data>& data,
+                                     ChunkedArray<N, Label>& labels,
+                                     BlockwiseLabelOptions const & options = BlockwiseLabelOptions());
+
+        // provide temporary directions storage
+        template <unsigned int N, class Data, class Label>
+        Label
+        unionFindWatershedsBlockwise(const ChunkedArray<N, Data>& data,
+                                     ChunkedArray<N, Label>& labels,
+                                     BlockwiseLabelOptions const & options,
+                                     ChunkedArray<N, unsigned short>& temporary_storage);
+    }}
+    \endcode
+
+    The resulting labeling is equivalent to a labeling by \ref watershedsUnionFind, that is,
+    the components are the same but may have different ids.
+    If \a temporary_storage is provided, this array is used for intermediate result storage.
+    Otherwise, a newly created \ref vigra::ChunkedArrayLazy is used.
+
+    Return: the number of labels assigned (=largest label, because labels start at one)
+
+    <b> Usage: </b>
+
+    <b>\#include </b> \<vigra/blockwise_watersheds.hxx\><br>
+    Namespace: vigra
+
+    \code
+    Shape3 shape = Shape3(10);
+    Shape3 chunk_shape = Shape3(4);
+    ChunkedArrayLazy<3, int> data(shape, chunk_shape);
+    // fill data ...
+
+    ChunkedArrayLazy<3, size_t> labels(shape, chunk_shape);
+
+    unionFindWatershedsBlockwise(data, labels, IndirectNeighborhood);
+    \endcode
+    */
+doxygen_overloaded_function(template <...> unsigned int unionFindWatershedsBlockwise)
+
+template <unsigned int N, class Data, class S1,
+                          class Label, class S2>
+Label unionFindWatershedsBlockwise(MultiArrayView<N, Data, S1> data,
+                                   MultiArrayView<N, Label, S2> labels,
+                                   BlockwiseLabelOptions const & options = BlockwiseLabelOptions())
+{
+    using namespace blockwise_watersheds_detail;
+
+    typedef typename MultiArrayView<N, Data, S1>::difference_type Shape;
+    Shape shape = data.shape();
+    vigra_precondition(shape == labels.shape(), "shapes of data and labels do not match");
+
+    MultiArray<N, unsigned short> directions(shape);
+    Shape block_shape = options.getBlockShapeN<N>();
+
+    MultiArray<N, MultiArrayView<N, unsigned short> > directions_blocks = blockify(directions, block_shape);
+
+    Overlaps<MultiArrayView<N, Data, S1> > overlaps(data, block_shape, Shape(1), Shape(1));
+    prepareBlockwiseWatersheds(overlaps, directions_blocks.begin(), options);
+    GridGraph<N, undirected_tag> graph(data.shape(), options.getNeighborhood());
+    UnionFindWatershedsEquality<N> equal = {&graph};
+    return labelMultiArrayBlockwise(directions, labels, options, equal);
+}
+
+template <unsigned int N, class Data, class Label>
+Label unionFindWatershedsBlockwise(const ChunkedArray<N, Data>& data,
+                                   ChunkedArray<N, Label>& labels,
+                                   BlockwiseLabelOptions const & options,
+                                   ChunkedArray<N, unsigned short>& directions)
+{
+    using namespace blockwise_watersheds_detail;
+
+    typedef typename ChunkedArray<N, Data>::shape_type Shape;
+    Shape shape = data.shape();
+    vigra_precondition(shape == labels.shape() && shape == directions.shape(),
+        "unionFindWatershedsBlockwise(): shapes of data and labels do not match");
+    Shape chunk_shape = data.chunkShape();
+    vigra_precondition(chunk_shape == labels.chunkShape() && chunk_shape == directions.chunkShape(),
+        "unionFindWatershedsBlockwise(): chunk shapes do not match");
+
+    Overlaps<ChunkedArray<N, Data> > overlaps(data, data.chunkShape(), Shape(1), Shape(1));
+
+    prepareBlockwiseWatersheds(overlaps, directions.chunk_begin(Shape(0), shape), options);
+
+    GridGraph<N, undirected_tag> graph(shape, options.getNeighborhood());
+    UnionFindWatershedsEquality<N> equal = {&graph};
+    return labelMultiArrayBlockwise(directions, labels, options, equal);
+}
+
+template <unsigned int N, class Data,
+                          class Label>
+inline Label
+unionFindWatershedsBlockwise(const ChunkedArray<N, Data>& data,
+                                   ChunkedArray<N, Label>& labels,
+                                   BlockwiseLabelOptions const & options = BlockwiseLabelOptions())
+{
+    ChunkedArrayLazy<N, unsigned short> directions(data.shape(), data.chunkShape());
+    return unionFindWatershedsBlockwise(data, labels, options, directions);
+}
+
+//@}
+
+} // namespace vigra
+
+#endif // VIGRA_BLOCKWISE_WATERSHEDS_HXX
diff --git a/include/vigra/box.hxx b/include/vigra/box.hxx
index 2faa609..ed3bf05 100644
--- a/include/vigra/box.hxx
+++ b/include/vigra/box.hxx
@@ -266,6 +266,19 @@ class Box
         }
     }
 
+        /** Adds a border of the given width around the box. That
+         * means, begin()'s components are moved by -borderWidth
+         * and end()'s by borderWidth. (If borderWidth is
+         * negative, the box will get smaller accordingly.)
+         */
+    void addBorder(const Vector & borderWidth)
+    {
+        begin_ -= borderWidth;
+        end_   += borderWidth;
+    }
+
+
+
         /// equality check
     bool operator==(Box const &r) const
     {
@@ -461,7 +474,7 @@ class Box
          * Return box scaled by given factor.  The same scalar
          * multiplication will be performed on both begin() and end().
          */
-    Box operator*(double scale)
+    Box operator*(double scale)const
     {
         Box result(*this);
         result *= scale;
@@ -484,7 +497,7 @@ class Box
          * Return box scaled by inverse of given factor.  The same scalar
          * division will be performed on both begin() and end().
          */
-    Box operator/(double scale)
+    Box operator/(double scale)const
     {
         Box result(*this);
         result /= scale;
@@ -507,7 +520,7 @@ class Box
          * Translate box by vector addition.  The same vector addition
          * operation will be performed on both begin() and end().
          */
-    Box operator+(const Vector &offset)
+    Box operator+(const Vector &offset)const
     {
         Box result(*this);
         result += offset;
@@ -530,7 +543,7 @@ class Box
          * Translate box by vector subtract.  The same vector subtract
          * operation will be performed on both begin() and end().
          */
-    Box operator-(const Vector &offset)
+    Box operator-(const Vector &offset)const
     {
         Box result(*this);
         result -= offset;
@@ -538,6 +551,12 @@ class Box
     }
 };
 
+template<class VALUETYPE, unsigned int DIMENSION>
+std::ostream& operator<< (std::ostream& stream, const Box<VALUETYPE, DIMENSION> & box) {
+    stream<<"["<<box.begin()<<", "<<box.end()<<" ]";
+    return stream;
+}
+
 //@}
 
 } // namespace vigra
diff --git a/include/vigra/bucket_queue.hxx b/include/vigra/bucket_queue.hxx
index dc9192c..fed7fe9 100644
--- a/include/vigra/bucket_queue.hxx
+++ b/include/vigra/bucket_queue.hxx
@@ -37,368 +37,8 @@
 #ifndef VIGRA_BUCKET_QUEUE_HXX
 #define VIGRA_BUCKET_QUEUE_HXX
 
-#include "config.hxx"
-#include "error.hxx"
-#include "array_vector.hxx"
-#include <queue>
+#include "priority_queue.hxx"
 
-namespace vigra {
 
-/** \brief Priority queue implemented using bucket sort.
-
-    This template implements functionality similar to <tt><a href="http://www.sgi.com/tech/stl/priority_queue.html">std::priority_queue</a></tt>,
-    but uses a more efficient algorithm based on bucket sort. It can be used
-    when all priorities are positive integers in a given range (typically, 0...255).
-    By default, <tt>BucketQueue\<ValueType\></tt> sorts the elements in descending order,
-    i.e. like in <tt>std::priority_queue</tt> the largest element has highest priority.
-    An ascending queue can be specified as <tt>BucketQueue\<ValueType, true\></tt>.
-    Elements with equal priorities are returned in a first-in first-out fashion.
-    
-    The main difference to <tt>std::priority_queue</tt> is the function <tt>push</tt>
-    which explicitly takes the priority of the element to be added as a second argument.
-    This allows optimization of <tt>ValueType</tt>: since the bucket uniquely
-    determines an element's priority, there is no need for <tt>ValueType</tt> to
-    store redundant priority information. If compatibility to <tt>std::priority_queue</tt>
-    is more important, use \ref vigra::MappedBucketQueue.
-
-    <b>\#include</b> \<vigra/bucket_queue.hxx\><br>
-    Namespace: vigra
-*/
-template <class ValueType,
-          bool Ascending = false>  // std::priority_queue is descending
-class BucketQueue
-{
-    ArrayVector<std::queue<ValueType> > buckets_;
-    std::size_t size_;
-    std::ptrdiff_t top_;
-    
-  public:
-  
-    typedef ValueType value_type;
-    typedef ValueType & reference;
-    typedef ValueType const & const_reference;
-    typedef std::size_t size_type;
-    typedef std::ptrdiff_t priority_type;
-    
-        /** \brief Create bucket queue with \arg bucket_count entries.
-            Priorities must be integers in the range <tt>[0, ..., bucket_count-1]</tt>.
-        */
-    BucketQueue(size_type bucket_count = 256)
-    : buckets_(bucket_count),
-      size_(0), top_(0)
-    {}
-    
-        /** \brief Number of elements in this queue.
-        */
-    size_type size() const
-    {
-        return size_;
-    }
-    
-        /** \brief Queue contains no elements.
-             Equivalent to <tt>size() == 0</tt>.
-        */
-    bool empty() const
-    {
-        return size() == 0;
-    }
-    
-        /** \brief Maximum index (i.e. priority) allowed in this queue.
-             Equivalent to <tt>bucket_count - 1</tt>.
-        */
-    priority_type maxIndex() const
-    {
-        return (priority_type)buckets_.size() - 1;
-    }
-    
-        /** \brief Priority of the current top element.
-        */
-    priority_type topPriority() const
-    {
-        return top_;
-    }
-    
-        /** \brief The current top element.
-        */
-    const_reference top() const
-    {
-        
-        return buckets_[top_].front();
-    }
-
-        /** \brief Remove the current top element.
-        */
-    void pop()
-    {
-        --size_;
-        buckets_[top_].pop();
-        
-        while(top_ > 0 && buckets_[top_].size() == 0)
-            --top_;
-    }
-    
-        /** \brief Insert new element \arg v with given \arg priority.
-        */
-    void push(value_type const & v, priority_type priority)
-    {
-        ++size_;
-        buckets_[priority].push(v);
-        
-        if(priority > top_)
-            top_ = priority;
-    }
-};
-
-template <class ValueType> 
-class BucketQueue<ValueType, true> // ascending queue
-{
-    ArrayVector<std::queue<ValueType> > buckets_;
-    std::size_t size_;
-    std::ptrdiff_t top_;
-    
-  public:
-  
-    typedef ValueType value_type;
-    typedef ValueType & reference;
-    typedef ValueType const & const_reference;
-    typedef std::size_t size_type;
-    typedef std::ptrdiff_t priority_type;
-    
-    BucketQueue(size_type bucket_count = 256)
-    : buckets_(bucket_count),
-      size_(0), top_((priority_type)bucket_count)
-    {}
-    
-    size_type size() const
-    {
-        return size_;
-    }
-    
-    bool empty() const
-    {
-        return size() == 0;
-    }
-    
-    priority_type maxIndex() const
-    {
-        return (priority_type)buckets_.size() - 1;
-    }
-    
-    priority_type topPriority() const
-    {
-        return top_;
-    }
-    
-    const_reference top() const
-    {
-        
-        return buckets_[top_].front();
-    }
-
-    void pop()
-    {
-        --size_;
-        buckets_[top_].pop();
-        
-        while(top_ < (priority_type)buckets_.size() && buckets_[top_].size() == 0)
-            ++top_;
-    }
-    
-    void push(value_type const & v, priority_type priority)
-    {
-        ++size_;
-        buckets_[priority].push(v);
-        
-        if(priority < top_)
-            top_ = priority;
-    }
-};
-
-/** \brief Priority queue implemented using bucket sort (STL compatible).
-
-    This template is compatible to <tt><a href="http://www.sgi.com/tech/stl/priority_queue.html">std::priority_queue</a></tt>,
-    but uses a more efficient algorithm based on bucket sort. It us used
-    like \ref vigra::BucketQueue, but has an additional <tt>PriorityFunctor</tt>
-    which extracts the priority value of an element of type <tt>ValueType</tt>.
-    Thus functor is called within <tt>push</tt> so that it does not need an
-    extra argument.
-
-    <b>\#include</b> \<vigra/bucket_queue.hxx\><br>
-    Namespace: vigra
-*/
-template <class ValueType,
-          class PriorityFunctor, 
-          bool Ascending = false> 
-class MappedBucketQueue
-: public BucketQueue<ValueType, Ascending>
-{
-    PriorityFunctor get_priority_;
-    
-  public:
-
-    typedef BucketQueue<ValueType, Ascending> BaseType;
-    typedef typename BaseType::value_type value_type;
-    typedef typename BaseType::reference reference;
-    typedef typename BaseType::const_reference const_reference;
-    typedef typename BaseType::size_type size_type;
-    typedef typename BaseType::priority_type priority_type;
-    
-        /** \brief Create a queue with \arg bucket_count entries.
-            Priorities will be computed by the <tt>PriorityFunctor</tt>
-            given in \arg priority (i.e. <tt>priority(v)</tt> must result in an integer,
-            where <tt>v</tt> is an instance of <tt>ValueType</tt>).
-        */
-    MappedBucketQueue(unsigned int bucket_count = 256,
-                      PriorityFunctor const & priority = PriorityFunctor())
-    : BaseType(bucket_count),
-      get_priority_(priority)
-    {}
-    
-        /** \brief Insert new element \arg v.
-            Its priority is calculated by <tt>priority(v)</tt>,
-            where <tt>priority</tt> is an instance of the 
-            <tt>PriorityFunctor</tt> passed in the constructor.
-            If the priority is outside the range <tt>[0, ..., bucket_count-1]</tt>,
-            it is clamped to the range borders.
-        */
-    void push(value_type const & v)
-    {
-        priority_type index = get_priority_(v);
-        
-        // clamp index to the allowed range
-        if(index > BaseType::maxIndex())
-            index = BaseType::maxIndex();
-        else if (index < 0)
-            index = 0;
-        
-        BaseType::push(v, index);
-    }
-};
-
-/** \brief Heap-based priority queue compatible to BucketQueue.
-
-    This template is compatible to \ref vigra::BucketQueue, but accepts arbitrary priority
-    types. Internally, it uses a <tt>std::priority_queue</tt>, but implements an 
-    API where priorities and payload data are separate, like in \ref vigra::BucketQueue.
-
-    <b>\#include</b> \<vigra/bucket_queue.hxx\><br>
-    Namespace: vigra
-*/
-template <class ValueType,
-          class PriorityType,
-          bool Ascending = false>  // std::priority_queue is descending
-class PriorityQueue
-{
-    typedef std::pair<ValueType, PriorityType> ElementType;
-    
-    struct Compare
-    {
-        typename IfBool<Ascending, std::greater<PriorityType>, 
-                                   std::less<PriorityType> >::type cmp;
-        
-        bool operator()(ElementType const & l, ElementType const & r) const
-        {
-            return cmp(l.second, r.second);
-        }
-    };
-    
-    typedef std::priority_queue<ElementType, std::vector<ElementType>, Compare> Heap;
-    
-    Heap heap_;
-    
-  public:
-  
-    typedef ValueType value_type;
-    typedef ValueType & reference;
-    typedef ValueType const & const_reference;
-    typedef typename Heap::size_type size_type;
-    typedef PriorityType priority_type;
-    
-        /** \brief Create empty priority queue.
-        */
-    PriorityQueue()
-    : heap_()
-    {}
-    
-        /** \brief Number of elements in this queue.
-        */
-    size_type size() const
-    {
-        return heap_.size();
-    }
-    
-        /** \brief Queue contains no elements.
-             Equivalent to <tt>size() == 0</tt>.
-        */
-    bool empty() const
-    {
-        return size() == 0;
-    }
-    
-        /** \brief Maximum index (i.e. priority) allowed in this queue.
-             Equivalent to <tt>bucket_count - 1</tt>.
-        */
-    priority_type maxIndex() const
-    {
-        return NumericTraits<priority_type>::max();
-    }
-    
-        /** \brief Priority of the current top element.
-        */
-    priority_type topPriority() const
-    {
-        return heap_.top().second;
-    }
-    
-        /** \brief The current top element.
-        */
-    const_reference top() const
-    {
-        
-        return heap_.top().first;
-    }
-
-        /** \brief Remove the current top element.
-        */
-    void pop()
-    {
-        heap_.pop();
-    }
-    
-        /** \brief Insert new element \arg v with given \arg priority.
-        */
-    void push(value_type const & v, priority_type priority)
-    {
-        heap_.push(ElementType(v, priority));
-    }
-};
-
-template <class ValueType,
-          bool Ascending>
-class PriorityQueue<ValueType, unsigned char, Ascending>
-: public BucketQueue<ValueType, Ascending>
-{
-  public:
-    typedef BucketQueue<ValueType, Ascending> BaseType;
-    
-    PriorityQueue()
-    : BaseType(NumericTraits<unsigned char>::max()+1)
-    {}
-};
-
-template <class ValueType,
-          bool Ascending>
-class PriorityQueue<ValueType, unsigned short, Ascending>
-: public BucketQueue<ValueType, Ascending>
-{
-  public:
-    typedef BucketQueue<ValueType, Ascending> BaseType;
-    
-    PriorityQueue()
-    : BaseType(NumericTraits<unsigned short>::max()+1)
-    {}
-};
-
-} // namespace vigra
 
 #endif // VIGRA_BUCKET_QUEUE_HXX
diff --git a/include/vigra/combineimages.hxx b/include/vigra/combineimages.hxx
index 44a6c63..d27e8d8 100644
--- a/include/vigra/combineimages.hxx
+++ b/include/vigra/combineimages.hxx
@@ -114,7 +114,7 @@ combineThreeLines(SrcIterator1 s1,
 
 /** \brief Combine two source images into destination image.
 
-    After the introduction of arithmetic and algebraic \ref MultiMathModule "array experessions",
+    After the introduction of arithmetic and algebraic \ref MultiMathModule "array expressions",
     this function is rarely needed. Moreover, \ref combineTwoMultiArrays() provides the 
     same functionality for arbitrary dimensional arrays.
 
@@ -491,7 +491,7 @@ combineTwoImagesIf(MultiArrayView<2, T11, S11> const & src1,
 
 /** \brief Combine three source images into destination image.
 
-    After the introduction of arithmetic and algebraic \ref MultiMathModule "array experessions",
+    After the introduction of arithmetic and algebraic \ref MultiMathModule "array expressions",
     this function is rarely needed. Moreover, \ref combineThreeMultiArrays() provides the 
     same functionality for arbitrary dimensional arrays.
 
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/include/vigra/compression.hxx
similarity index 64%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to include/vigra/compression.hxx
index 37a8c81..9d464a2 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/include/vigra/compression.hxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*               Copyright 2013-2014 by Ullrich Koethe                  */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,41 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
-#include <vigra/numpy_array.hxx>
-#include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
+#ifndef VIGRA_COMPRESSION_HXX
+#define VIGRA_COMPRESSION_HXX
 
-namespace python = boost::python;
+#include "config.hxx"
+#include "error.hxx"
+#include "array_vector.hxx"
+#include <vector>
 
 namespace vigra {
 
-UInt32 pychecksum(python::str const & s)
-{
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
+enum CompressionMethod {  DEFAULT_COMPRESSION=-2,  // use default method (depending on context)
+                          NO_COMPRESSION=-1,       // don't compress
+                          ZLIB_NONE=0, // no compression using zlib
+                          ZLIB_FAST=1, // fastest compression using zlib
+                          ZLIB=6,      // zlib default compression level
+                          ZLIB_BEST=9, // highest compression using zlib
+                          LZ4          // very fast LZ4 algorithm
+                       };
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+/** Compress the source buffer.
 
-} // namespace vigra
+    The destination array will be resized as required.
+*/
+VIGRA_EXPORT void compress(char const * source, std::size_t size, ArrayVector<char> & dest, CompressionMethod method);
+VIGRA_EXPORT void compress(char const * source, std::size_t size, std::vector<char> & dest, CompressionMethod method);
+
+/** Uncompress the source buffer when the uncompressed size is known.
 
-using namespace boost::python;
-using namespace vigra;
+    The destination buffer must be allocated to the correct size.
+*/
+VIGRA_EXPORT void uncompress(char const * source, std::size_t srcSize, 
+                             char * dest, std::size_t destSize, CompressionMethod method);
+
+
+} // namespace vigra
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
-{
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
-}
+#endif // VIGRA_COMPRESSION_HXX
diff --git a/include/vigra/config.hxx b/include/vigra/config.hxx
index 82e231c..4362f29 100644
--- a/include/vigra/config.hxx
+++ b/include/vigra/config.hxx
@@ -37,7 +37,7 @@
 #ifndef VIGRA_CONFIG_HXX
 #define VIGRA_CONFIG_HXX
 
-#include "configVersion.hxx"
+#include "config_version.hxx"
 #include <stdexcept>
 
 ///////////////////////////////////////////////////////////
@@ -107,8 +107,8 @@
         #define VIGRA_NO_WORKING_STRINGSTREAM
     #endif
     
-    #if _MSC_VER >= 1600
-        #define VIGRA_HAS_UNIQUE_PTR
+    #if _MSC_VER < 1600
+        #define VIGRA_NO_UNIQUE_PTR
     #endif
     
     #define VIGRA_NEED_BIN_STREAMS
@@ -149,7 +149,7 @@
 //                                                       //
 ///////////////////////////////////////////////////////////
 
-#if defined(__GNUC__)
+#if defined(__GNUC__) && !defined(__clang__)
     #if  __GNUC__ < 2 || ((__GNUC__ == 2) && (__GNUC_MINOR__ <= 8))
         #error "Need at least g++ 2.95"
     #endif
@@ -159,17 +159,63 @@
     #define HAS_HASH_CONTAINERS
     
     // these warnings produce too many false positives to be useful
-    #pragma GCC diagnostic ignored "-Wstrict-aliasing"  
     #pragma GCC diagnostic ignored "-Wshadow"  
     
     #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
-        #define VIGRA_HAS_UNIQUE_PTR
+        #if defined(__APPLE__)
+            #define VIGRA_NO_UNIQUE_PTR
+        #endif
+    #else
+        // C++98 mode.  No native unique_ptr support
+        #define VIGRA_NO_UNIQUE_PTR
+        #define VIGRA_SHARED_PTR_IN_TR1
     #endif
-
 #endif  // __GNUC__
 
 ///////////////////////////////////////////////////////////
 //                                                       //
+//                         clang                         //
+//                                                       //
+///////////////////////////////////////////////////////////
+#if defined(__clang__)
+    // In Apple builds of clang, __clang_major__ and __clang_minor__
+    // have totally different values than in other builds of clang.
+    #if defined(__apple_build_version__)
+        // (For Apple builds of clang, __clang_major__ tracks the XCode version.)
+        // For Apple builds, C++11 only works well with libc++, not stdlibc++
+        #define VIGRA_NO_UNIQUE_PTR
+        #if __cplusplus >= 201103L
+            // Must have at least XCode 4 and use libc++ to use std::shared_ptr, etc.
+            // Otherwise, use tr1.
+            #if !((__clang_major__ >= 4) && defined(_LIBCPP_VERSION))
+                #define VIGRA_SHARED_PTR_IN_TR1
+            #endif
+        #else
+            // C++98 mode.  No native unique_ptr support
+            #define VIGRA_NO_UNIQUE_PTR
+            #if !defined(_LIBCPP_VERSION)
+                #define VIGRA_SHARED_PTR_IN_TR1
+            #endif
+        #endif
+    #else
+        // This is a conservative constraint:
+        // Full C++11 support was achieved in clang-3.3,
+        // but most support was available in 3.1 and 3.2
+        #if __cplusplus >= 201103L
+            #if (__clang_major__ < 3) || ((__clang_major__ == 3) && (__clang_minor__ < 3))
+                #define VIGRA_SHARED_PTR_IN_TR1
+                #define VIGRA_NO_UNIQUE_PTR
+            #endif
+        #else
+            // C++98 mode.  No native shared_ptr/unique_ptr support
+            #define VIGRA_NO_UNIQUE_PTR
+            #define VIGRA_SHARED_PTR_IN_TR1
+        #endif
+    #endif
+#endif // __clang__
+
+///////////////////////////////////////////////////////////
+//                                                       //
 //                         MingW                         //
 //                                                       //
 ///////////////////////////////////////////////////////////
@@ -242,10 +288,20 @@
     #define VIGRA_EXPORT
 #endif
 
-#ifdef VIGRA_HAS_UNIQUE_PTR
-#  define VIGRA_UNIQUE_PTR  std::unique_ptr
-#else
+#ifdef VIGRA_NO_UNIQUE_PTR
 #  define VIGRA_UNIQUE_PTR  std::auto_ptr
+#else
+#  ifdef _GLIBCXX_INCLUDE_AS_TR1
+#    define VIGRA_UNIQUE_PTR  std::tr1::unique_ptr
+#  else
+#    define VIGRA_UNIQUE_PTR  std::unique_ptr
+#  endif
+#endif
+
+#ifdef VIGRA_SHARED_PTR_IN_TR1
+#  define VIGRA_SHARED_PTR  std::tr1::shared_ptr
+#else
+#  define VIGRA_SHARED_PTR  std::shared_ptr
 #endif
 
 #ifndef VIGRA_NO_THREADSAFE_STATIC_INIT    
diff --git a/include/vigra/configVersion.hxx b/include/vigra/config_version.hxx
similarity index 100%
rename from include/vigra/configVersion.hxx
rename to include/vigra/config_version.hxx
diff --git a/include/vigra/convolution.hxx b/include/vigra/convolution.hxx
index 8b59335..9ce9b73 100644
--- a/include/vigra/convolution.hxx
+++ b/include/vigra/convolution.hxx
@@ -29,7 +29,7 @@
 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
-/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
 
@@ -184,7 +184,7 @@ namespace vigra {
 
 /** \addtogroup CommonConvolutionFilters Common Filters
 
-    These functions calculate common filters by appropriate sequences of calls 
+    These functions calculate common filters by appropriate sequences of calls
     to \ref separableConvolveX() and \ref separableConvolveY() or explicit 2-dimensional
     convolution.
 */
@@ -192,7 +192,7 @@ namespace vigra {
 
 /** \brief Convolve an image with the given kernel(s).
 
-    If you pass \ref vigra::Kernel2D to this function, it will perform an explicit 2-dimensional 
+    If you pass \ref vigra::Kernel2D to this function, it will perform an explicit 2-dimensional
     convolution. If you pass a single \ref vigra::Kernel1D, it performs a separable convolution,
     i.e. it concatenates two 1D convolutions (along the x-axis and along the y-axis) with the same
     kernel via internal calls to \ref separableConvolveX() and \ref separableConvolveY(). If two
@@ -200,12 +200,12 @@ namespace vigra {
 
     All \ref BorderTreatmentMode "border treatment modes" are supported.
 
-    The unput pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over 
+    The input pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over
     the kernel's value_type <tt>T</tt>, i.e. addition of source values, multiplication with kernel values,
     and NumericTraits must be defined. The kernel's value_type must be an \ref AlgebraicField "algebraic field",
-    i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be defined. Typically, you will use 
+    i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be defined. Typically, you will use
     <tt>double</tt> for the kernel type.
-    
+
     <b> Declarations:</b>
 
     pass 2D array views:
@@ -228,7 +228,7 @@ namespace vigra {
         convolveImage(MultiArrayView<2, T1, S1> const & src,
                       MultiArrayView<2, T2, S2> dest,
                       Kernel1D<T> const & kx, Kernel1D<T> const & ky);
-                      
+
         // use a non-separable 2D kernel
         template <class T1, class S1,
                   class T2, class S2,
@@ -300,17 +300,17 @@ namespace vigra {
     Kernel1D<double> kx, ky;
     kx.initSymmetricDifference();
     ky.initBinomial(1);
-    
+
     // calls separable convolution with the two 1D kernels
     convolveImage(src, dest1, kx, ky);
-    
+
     // create a 3x3 Laplacian filter
     Kernel2D<double> laplace;
     laplace.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
             0.375,  0.25, 0.375,
             0.25,  -2.5,  0.25,
             0.375,  0.25, 0.375;
-    
+
     // calls 2D convolution
     convolveImage(src, dest2, laplace);
     \endcode
@@ -324,10 +324,10 @@ namespace vigra {
     Kernel1D<double> kx, ky;
     kx.initSymmetricDifference();
     ky.initBinomial(1);
-    
+
     // calls separable convolution with the two 1D kernels
     vigra::convolveImage(srcImageRange(src), destImage(dest), kx, ky);
-    
+
     // create a 3x3 Laplacian filter
     Kernel2D<double> laplace;
     laplace.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
@@ -342,11 +342,11 @@ namespace vigra {
 
     <b> Preconditions:</b>
 
-    The image must be larger than the kernel radius. 
+    The image must be larger than the kernel radius.
     <ul>
-    <li>For 1D kernels, <tt>w > std::max(xkernel.right(), -xkernel.keft())</tt> and 
+    <li>For 1D kernels, <tt>w > std::max(xkernel.right(), -xkernel.keft())</tt> and
          <tt>h > std::max(ykernel.right(), -ykernel.left())</tt> are required.
-    <li>For 2D kernels, <tt>w > std::max(kernel.lowerRight().x, -kernel.upperLeft().x)</tt> and 
+    <li>For 2D kernels, <tt>w > std::max(kernel.lowerRight().x, -kernel.upperLeft().x)</tt> and
          <tt>h > std::max(kernel.lowerRight().y, -kernel.upperLeft().y)</tt> are required.
     </ul>
     If <tt>BORDER_TREATMENT_CLIP</tt> is requested: the sum of kernel elements must be != 0.
@@ -421,17 +421,17 @@ convolveImage(MultiArrayView<2, T1, S1> const & src,
 /** \brief Perform simple sharpening function.
 
     This function uses \ref convolveImage() with the following 3x3 filter:
-    
+
     \code
     -sharpening_factor/16.0,    -sharpening_factor/8.0,    -sharpening_factor/16.0,
     -sharpening_factor/8.0,   1.0+sharpening_factor*0.75,  -sharpening_factor/8.0,
-    -sharpening_factor/16.0,    -sharpening_factor/8.0,    -sharpening_factor/16.0;    
+    -sharpening_factor/16.0,    -sharpening_factor/8.0,    -sharpening_factor/16.0;
     \endcode
-    
+
     and uses <TT>BORDER_TREATMENT_REFLECT</TT> as border treatment mode.
 
     <b> Preconditions:</b>
-    \code  
+    \code
     1. sharpening_factor >= 0
     2. scale >= 0
     \endcode
@@ -441,11 +441,11 @@ convolveImage(MultiArrayView<2, T1, S1> const & src,
     pass 2D array views:
     \code
     namespace vigra {
-        template <class T1, class S1, 
+        template <class T1, class S1,
                   class T2, class S2>
         void
         simpleSharpening(MultiArrayView<2, T1, S1> const & src,
-                         MultiArrayView<2, T2, S2> dest, 
+                         MultiArrayView<2, T2, S2> dest,
                          double sharpening_factor);
     }
     \endcode
@@ -463,7 +463,7 @@ convolveImage(MultiArrayView<2, T1, S1> const & src,
     use argument objects in conjunction with \ref ArgumentObjectFactories :
     \code
     namespace vigra {
-        template <class SrcIterator, class SrcAccessor, 
+        template <class SrcIterator, class SrcAccessor,
                   class DestIterator, class DestAccessor>
         void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                               pair<DestIterator, DestAccessor> dest, double sharpening_factor);
@@ -494,7 +494,7 @@ convolveImage(MultiArrayView<2, T1, S1> const & src,
 
     \endcode
     \deprecatedEnd
-*/    
+*/
 doxygen_overloaded_function(template <...> void simpleSharpening)
 
 template <class SrcIterator, class SrcAccessor,
@@ -512,12 +512,12 @@ void simpleSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_ac
                                                         -sharpening_factor/8.0,   1.0+sharpening_factor*0.75,  -sharpening_factor/8.0,
                                                         -sharpening_factor/16.0,    -sharpening_factor/8.0,    -sharpening_factor/16.0;
 
-    convolveImage(src_ul, src_lr, src_acc, dest_ul, dest_acc, 
-                  kernel.center(), kernel.accessor(), 
+    convolveImage(src_ul, src_lr, src_acc, dest_ul, dest_acc,
+                  kernel.center(), kernel.accessor(),
                   kernel.upperLeft(), kernel.lowerRight() , BORDER_TREATMENT_REFLECT );
 }
 
-template <class SrcIterator, class SrcAccessor, 
+template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
 inline
 void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
@@ -527,11 +527,11 @@ void simpleSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                      dest.first, dest.second, sharpening_factor);
 }
 
-template <class T1, class S1, 
+template <class T1, class S1,
           class T2, class S2>
 inline void
 simpleSharpening(MultiArrayView<2, T1, S1> const & src,
-                 MultiArrayView<2, T2, S2> dest, 
+                 MultiArrayView<2, T2, S2> dest,
                  double sharpening_factor)
 {
     vigra_precondition(src.shape() == dest.shape(),
@@ -551,15 +551,15 @@ simpleSharpening(MultiArrayView<2, T1, S1> const & src,
 
 
     This function uses \ref gaussianSmoothing() at the given scale to create a
-    temporary image 'smooth' and than blends the original and smoothed image 
-    according to the formula    
+    temporary image 'smooth' and than blends the original and smoothed image
+    according to the formula
 
     \code
     dest = (1 + sharpening_factor)*src - sharpening_factor*smooth
     \endcode
 
     <b> Preconditions:</b>
-    \code  
+    \code
     1. sharpening_factor >= 0
     2. scale >= 0
     \endcode
@@ -573,8 +573,8 @@ simpleSharpening(MultiArrayView<2, T1, S1> const & src,
                   class T2, class S2>
         void
         gaussianSharpening(MultiArrayView<2, T1, S1> const & src,
-                           MultiArrayView<2, T2, S2> dest, 
-                           double sharpening_factor, 
+                           MultiArrayView<2, T2, S2> dest,
+                           double sharpening_factor,
                            double scale);
     }
     \endcode
@@ -586,7 +586,7 @@ simpleSharpening(MultiArrayView<2, T1, S1> const & src,
       template <class SrcIterator, class SrcAccessor,
                 class DestIterator, class DestAccessor>
       void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
-                              DestIterator dest_ul, DestAccessor dest_acc, 
+                              DestIterator dest_ul, DestAccessor dest_acc,
                               double sharpening_factor, double scale)
     }
     \endcode
@@ -596,7 +596,7 @@ simpleSharpening(MultiArrayView<2, T1, S1> const & src,
       template <class SrcIterator, class SrcAccessor,
                 class DestIterator, class DestAccessor>
       void gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
-                               pair<DestIterator, DestAccessor> dest, 
+                               pair<DestIterator, DestAccessor> dest,
                                double sharpening_factor, double scale)
     }
     \endcode
@@ -626,13 +626,13 @@ simpleSharpening(MultiArrayView<2, T1, S1> const & src,
     vigra::gaussianSharpening(srcImageRange(src), destImage(dest), 3.0, 0.5);
     \endcode
     \deprecatedEnd
-*/    
+*/
 doxygen_overloaded_function(template <...> void gaussianSharpening)
 
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
 void gaussianSharpening(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
-                        DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor, 
+                        DestIterator dest_ul, DestAccessor dest_acc, double sharpening_factor,
                         double scale)
 {
     vigra_precondition(sharpening_factor >= 0.0,
@@ -668,7 +668,7 @@ template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
 inline void
 gaussianSharpening(triple<SrcIterator, SrcIterator, SrcAccessor> src,
-                   pair<DestIterator, DestAccessor> dest, double sharpening_factor, 
+                   pair<DestIterator, DestAccessor> dest, double sharpening_factor,
                    double scale)
 {
     gaussianSharpening(src.first, src.second, src.third,
@@ -680,8 +680,8 @@ template <class T1, class S1,
           class T2, class S2>
 inline void
 gaussianSharpening(MultiArrayView<2, T1, S1> const & src,
-                   MultiArrayView<2, T2, S2> dest, 
-                   double sharpening_factor, 
+                   MultiArrayView<2, T2, S2> dest,
+                   double sharpening_factor,
                    double scale)
 {
     vigra_precondition(src.shape() == dest.shape(),
@@ -703,10 +703,10 @@ gaussianSharpening(MultiArrayView<2, T1, S1> const & src,
 
     This function is a shorthand for the concatenation of a call to
     \ref separableConvolveX() and \ref separableConvolveY() with a
-    Gaussian kernel of the given scale. If two scales are provided, 
-    smoothing in x and y direction will have different strength. 
-    The function uses <TT>BORDER_TREATMENT_REFLECT</TT>. 
-    
+    Gaussian kernel of the given scale. If two scales are provided,
+    smoothing in x and y direction will have different strength.
+    The function uses <TT>BORDER_TREATMENT_REFLECT</TT>.
+
     Function \ref gaussianSmoothMultiArray() performs the same filter operation
     on arbitrary dimensional arrays.
 
@@ -776,7 +776,7 @@ doxygen_overloaded_function(template <...> void gaussianSmoothing)
 
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
-void 
+void
 gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAccessor sa,
                   DestIterator dupperleft, DestAccessor da,
                   double scale_x, double scale_y)
@@ -800,7 +800,7 @@ gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAccessor s
 
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
-inline void 
+inline void
 gaussianSmoothing(SrcIterator supperleft, SrcIterator slowerright, SrcAccessor sa,
                   DestIterator dupperleft, DestAccessor da,
                   double scale)
@@ -959,7 +959,7 @@ gaussianSmoothing(MultiArrayView<2, T1, S1> const & src,
 
     // calculate gradient vector at scale = 3.0
     gaussianGradient(src, gradx, grady, 3.0);
-    
+
     // likewise, but use a vector image to store the gradient
     MultiArray<2, TinyVector<float, 2> > dest(w,h);
     gaussianGradient(src, dest, 3.0);
@@ -1014,7 +1014,7 @@ void gaussianGradient(SrcIterator supperleft,
                         double scale)
 {
     VectorElementAccessor<DestAccessor> gradx(0, dest), grady(1, dest);
-    gaussianGradient(supperleft, slowerright, src, 
+    gaussianGradient(supperleft, slowerright, src,
                      dupperleft, gradx, dupperleft, grady, scale);
 }
 
@@ -1078,6 +1078,17 @@ gaussianGradient(MultiArrayView<2, T1, S1> const & src,
     the squared gradient magnitude is computed for each band separately, and the
     return value is the square root of the sum of these squared magnitudes.
 
+    Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
+    to adjust the filter sizes for the resolution of each axis.
+    Otherwise, the parameter <tt>opt</tt> is optional unless the parameter
+    <tt>sigma</tt> is omitted.
+
+    If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
+    be executed in parallel on data blocks of a certain size. The block size can be
+    customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
+    usually work reasonably. By default, the number of threads equals the capabilities
+    of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
+
     <b> Declarations:</b>
 
     use arbitrary-dimensional arrays:
@@ -1086,40 +1097,50 @@ gaussianGradient(MultiArrayView<2, T1, S1> const & src,
         // pass filter scale explicitly
         template <unsigned int N, class T1, class S1,
                                   class T2, class S2>
-        void 
+        void
         gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
                                   MultiArrayView<N, T2, S2> dest,
                                   double sigma,
                                   ConvolutionOptions<N> opt = ConvolutionOptions<N>());
 
+        // likewise, but sum the contributions of each band
         template <unsigned int N, class MT, class S1,
                                   class T2, class S2>
-        void 
+        void
         gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> const & src,
                                   MultiArrayView<N,   T2, S2> dest,
                                   double sigma,
                                   ConvolutionOptions<N> opt = ConvolutionOptions<N>());
-                                  
+
         // pass filter scale(s) in option object
         template <unsigned int N, class T1, class S1,
                                   class T2, class S2>
-        void 
+        void
         gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
                                   MultiArrayView<N, T2, S2> dest,
                                   ConvolutionOptions<N> const & opt);
 
+        // likewise, but execute algorithm in parallel
+        template <unsigned int N, class T1, class S1,
+                                  class T2, class S2>
+        void
+        gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
+                                  MultiArrayView<N, T2, S2> dest,
+                                  BlockwiseConvolutionOptions<N> const & opt);
+
+        // pass filter scale(s) in option object and sum the contributions of each band
         template <unsigned int N, class MT, class S1,
                                   class T2, class S2>
-        void 
+        void
         gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<MT>, S1> const & src,
                                   MultiArrayView<N,   T2, S2> dest,
                                   ConvolutionOptions<N> const & opt);
     }
     \endcode
-    Here, the input element types <tt>T1</tt> and <tt>MT</tt> can be arbitrary scalar types, and <tt>T1</tt> 
-    may also be <tt>TinyVector</tt> or <tt>RGBValue</tt>. The output element type <tt>T2</tt> should 
+    Here, the input element types <tt>T1</tt> and <tt>MT</tt> can be arbitrary scalar types, and <tt>T1</tt>
+    may also be <tt>TinyVector</tt> or <tt>RGBValue</tt>. The output element type <tt>T2</tt> should
     be the corresponding norm type (see \ref NormTraits "NormTraits"). In the <tt>Multiband<MT></tt>-version,
-    the input array's right-most dimension is interpreted as a channel axis, therefore it must 
+    the input array's right-most dimension is interpreted as a channel axis, therefore it must
     have one dimension more than the output array.
 
     \deprecatedAPI{gaussianGradientMagnitude}
@@ -1149,7 +1170,9 @@ gaussianGradient(MultiArrayView<2, T1, S1> const & src,
 
     <b> Usage:</b>
 
-    <b>\#include</b> \<vigra/convolution.hxx\><br/>
+    <b>\#include</b> \<vigra/multi_convolution.hxx\> (sequential version)<br/>
+    <b>\#include</b> \<vigra/multi_blockwise.hxx\> (parallel version)<br/>
+    <b>\#include</b> \<vigra/convolution.hxx\> (deprecated API version)<br/>
     Namespace: vigra
 
     \code
@@ -1162,7 +1185,7 @@ gaussianGradient(MultiArrayView<2, T1, S1> const & src,
         // calculate gradient magnitude at scale = 3.0
         gaussianGradientMagnitude(volume, grad, 3.0);
     }
-    
+
     // example 2
     {
         // use a 2-dimensional RGB array
@@ -1173,10 +1196,10 @@ gaussianGradient(MultiArrayView<2, T1, S1> const & src,
         // calculate the color gradient magnitude at scale = 3.0
         gaussianGradientMagnitude(rgb, grad, 3.0);
     }
-    
+
     // example 3
     {
-        // use a 3-dimensional array whose right-most axis is interpreted as 
+        // use a 3-dimensional array whose right-most axis is interpreted as
         // a multi-spectral axis with arbitrary many channels
         MultiArray<3, Multiband<float> > spectral(Shape3(w, h, channelCount));
         MultiArray<2, float> grad(Shape2(w, h));
@@ -1199,7 +1222,7 @@ gaussianGradient(MultiArrayView<2, T1, S1> const & src,
 
     // calculate gradient magnitude at scale = 3.0
     gaussianGradientMagnitude(srcImageRange(image), destImage(grad), 3.0);
-    
+
     // calculate color gradient magnitude at scale = 3.0
     gaussianGradientMagnitude(srcImageRange(rgb), destImage(grad), 3.0);
     \endcode
@@ -1246,7 +1269,7 @@ gaussianGradientMagnitude(triple<SrcIterator, SrcIterator, SrcAccessor> src,
     This function calls \ref separableConvolveX() and \ref separableConvolveY() with the appropriate 2nd derivative
     of Gaussian kernels in x- and y-direction and then sums the results
     to get the Laplacian.
-    
+
     Function \ref laplacianOfGaussianMultiArray() performs the same filter operation
     on arbitrary dimensional arrays.
 
@@ -1396,7 +1419,7 @@ laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
     the three destination images. The first destination image will
     contain the second derivative in x-direction, the second one the mixed
     derivative, and the third one holds the derivative in y-direction.
-    
+
     Function \ref hessianOfGaussianMultiArray() performs the same filter operation
     on arbitrary dimensional arrays.
 
@@ -1463,7 +1486,7 @@ laplacianOfGaussian(MultiArrayView<2, T1, S1> const & src,
 
     \deprecatedUsage{hessianMatrixOfGaussian}
     \code
-    vigra::FImage src(w,h), 
+    vigra::FImage src(w,h),
                   hxx(w,h), hxy(w,h), hyy(w,h); // use a separate image for each component of the Hessian
     ...
 
@@ -1557,13 +1580,16 @@ hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
 {
     vigra_precondition(src.shape() == dest.shape(),
         "hessianMatrixOfGaussian(): shape mismatch between input and output.");
-        
+
     MultiArrayView<3, T2> expanded(dest.expandElements(0));
-    
+    MultiArrayView<2, T2> dxx(expanded.template bind<0>(0));
+    MultiArrayView<2, T2> dxy(expanded.template bind<0>(1));
+    MultiArrayView<2, T2> dyy(expanded.template bind<0>(2));
+
     hessianMatrixOfGaussian(srcImageRange(src),
-                            destImage(expanded.bind<0>(0)),
-                            destImage(expanded.bind<0>(1)),
-                            destImage(expanded.bind<0>(2)),
+                            destImage(dxx),
+                            destImage(dxy),
+                            destImage(dyy),
                             scale);
 }
 
@@ -1603,7 +1629,7 @@ hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
     hold the result in the same order as above). The latter form is also applicable when
     the source image is a multi-band image (e.g. RGB). In this case, tensors are
     first computed for each band separately, and then summed up to get a single result tensor.
-    
+
     Function \ref structureTensorMultiArray() performs the same filter operation
     on arbitrary dimensional arrays.
 
@@ -1691,7 +1717,7 @@ hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
     Namespace: vigra
 
     \code
-    MultiArray<2, flost> src(w,h), 
+    MultiArray<2, flost> src(w,h),
                          stxx(w,h), stxy(w,h), styy(w,h);  // use a separate image for each component
     ...
 
@@ -1705,7 +1731,7 @@ hessianMatrixOfGaussian(MultiArrayView<2, T1, S1> const & src,
 
     \deprecatedUsage{structureTensor}
     \code
-    vigra::FImage src(w,h), 
+    vigra::FImage src(w,h),
                   stxx(w,h), stxy(w,h), styy(w,h);
     vigra::BasicImage<TinyVector<float, 3> > st(w,h);
     ...
@@ -1817,12 +1843,12 @@ void structureTensor(SrcIterator supperleft,
 {
     int bands = src.size(supperleft);
     typedef VectorElementAccessor<SrcAccessor> SA;
-    
+
     structureTensor(supperleft, slowerright, SA(0, src),
                     dupperleft, dest,
                     inner_scale, outer_scale,
                     VigraTrueType() /* isScalar */);
-                    
+
     BasicImage<typename DestAccessor::value_type> st(slowerright - supperleft, SkipInitialization);
     for(int k=1; k < bands; ++k)
     {
@@ -1844,7 +1870,7 @@ void structureTensor(SrcIterator supperleft,
                         DestIterator dupperleft, DestAccessor dest,
                         double inner_scale, double outer_scale)
 {
-    typedef typename 
+    typedef typename
         NumericTraits<typename SrcAccessor::value_type>::isScalar isScalar;
     detail::structureTensor(supperleft, slowerright, src,
                             dupperleft, dest, inner_scale, outer_scale, isScalar());
diff --git a/include/vigra/coordinate_iterator.hxx b/include/vigra/coordinate_iterator.hxx
index f5b5635..fc55794 100644
--- a/include/vigra/coordinate_iterator.hxx
+++ b/include/vigra/coordinate_iterator.hxx
@@ -121,6 +121,7 @@ struct StridePair
     {
         return index;
     }
+    
     double & dim0()
     {
         return coord[0];
@@ -230,7 +231,7 @@ struct StridePairPointer : public StridePairCoord<N>
     {
         return index;
     }
-
+    
     void operator+=(stride_type x)
     {
         index += x.c;
diff --git a/include/vigra/correlation.hxx b/include/vigra/correlation.hxx
new file mode 100755
index 0000000..c936f80
--- /dev/null
+++ b/include/vigra/correlation.hxx
@@ -0,0 +1,718 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2007-2014 by Benjamin Seppke                 */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_CORRELATION_HXX
+#define VIGRA_CORRELATION_HXX
+
+#include "stdimage.hxx"
+#include "inspectimage.hxx"
+#include "functorexpression.hxx"
+#include "multi_math.hxx"
+#include "multi_fft.hxx"
+#include "integral_image.hxx"
+
+// "slow" correlation algorithms are performed using the windowing filter env.
+#include "applywindowfunction.hxx"
+
+namespace vigra
+{
+
+/** \addtogroup Correlation Image Correlation
+
+    Fast (FFT-based) and slow algorithms to estimate the correlation between images.
+*/
+//@{
+
+/********************************************************/
+/*                                                      */
+/*    Fast cross correlation of an image w.r.t a mask   */
+/*                                                      */
+/********************************************************/
+
+/** \brief This function performes a fast cross-correlation
+
+ This function performes a fast cross-correlation using the Fast Fourier Transform and
+ the dependency of the convolution and the correlation in Fourier space.
+
+ The input pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over
+ the window functions' value_type <tt>T</tt>, i.e. addition of source values, multiplication with functions' values,
+ and NumericTraits must be defined. The mask's value_type must be an \ref AlgebraicField "algebraic field",
+ i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be defined.
+
+ By default, the borders are filled with zeros. Use the clearBorders switch to change that behavior if you need to.
+
+ <b> Declarations:</b>
+
+ pass 2D array views:
+ \code
+ namespace vigra {
+   template <class T1, class S1,
+            class T2, class S2,
+            class T3, class S3,
+            unsigned int N>
+   void
+   fastCrossCorrelation(MultiArrayView<N, T1, S1> const & in,
+                        MultiArrayView<N, T2, S2> const & mask,
+                        MultiArrayView<N, T3, S3> out,
+                        bool clearBorders=true);
+
+ }
+ \endcode
+
+
+ <b> Usage:</b>
+
+ <b>\#include</b> \<vigra/correlation.hxx\><br/>
+ Namespace: vigra
+
+ \code
+ unsigned int m_w=51, m_h=51;
+ unsigned int w=1000, h=1000;
+ MultiArray<2, float> mask(m_w,m_h), src(w,h), dest(w,h);
+ ...
+
+ //compute fast cross correlation of mask and image -> dest
+ fastCrossCorrelation(mask, src, dest);
+ \endcode
+
+ <b> Preconditions:</b>
+
+ The image must be larger than the size of the mask.
+ */
+doxygen_overloaded_function(template <...> void fastCrossCorrelation)
+
+template <class T1, class S1,
+class T2, class S2,
+class T3, class S3,
+unsigned int N>
+inline void fastCrossCorrelation(MultiArrayView<N, T1, S1> const & in,
+                                 MultiArrayView<N, T2, S2> const & mask,
+                                 MultiArrayView<N, T3, S3> out,
+                                 bool clearBorders=true)
+{
+    vigra_precondition(in.shape() == out.shape(),
+                       "vigra::fastCrossCorrelation(): shape mismatch between input and output.");
+    correlateFFT(in, mask, out);
+
+    if(clearBorders)
+    {
+        typedef typename MultiArrayShape<N>::type Shape;
+        Shape maskRadius(floor(mask.shape()/2));
+        initMultiArrayBorder(out, maskRadius, maskRadius, T3());
+    }
+}
+
+namespace detail {
+
+template<class T1, class S1>
+inline double integralMultiArrayWindowMean(MultiArrayView<1, T1, S1> const & in,
+                                           typename MultiArrayView<1, T1, S1>::difference_type const & left,
+                                           typename MultiArrayView<1, T1, S1>::difference_type const & right)
+{
+    return in[right]-in[left];
+}
+
+template<class T1, class S1>
+inline double integralMultiArrayWindowMean(MultiArrayView<2, T1, S1> const & in,
+                                           typename MultiArrayView<2, T1, S1>::difference_type const & ul,
+                                           typename MultiArrayView<2, T1, S1>::difference_type const & lr)
+{
+    return in[lr] - in(lr[0],ul[1]) - in(ul[0],lr[1]) + in[ul];
+}
+
+template<class T1, class S1>
+inline double integralMultiArrayWindowMean(MultiArrayView<3, T1, S1> const & in,
+                                           typename MultiArrayView<3, T1, S1>::difference_type const & ul,
+                                           typename MultiArrayView<3, T1, S1>::difference_type const & lr)
+{
+    return (in[lr] - in(lr[0],ul[1],lr[2]) - in(ul[0],lr[1],lr[2]) + in(ul[0],ul[1],lr[2]))
+         - (in(lr[0],lr[1],ul[2]) - in(lr[0],ul[1],ul[2]) - in(ul[0],lr[1],ul[2]) + in[ul]);
+}
+
+} // namespace detail
+
+/********************************************************/
+/*                                                      */
+/*  Fast normalized cross correlation of mask to image  */
+/*                                                      */
+/********************************************************/
+
+/** \brief This function performes a fast normalized cross-correlation
+
+    To compute the normalized cross correlation in a fast way, it is using the Fast Fourier Transform     and sum-image look-up-tables as it is suggested by J.P.Lewis (1995):
+    <i>"Fast Normalized Cross-Correlation"</i>.
+
+    The input pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over
+    the window functions' value_type <tt>T</tt>, i.e. addition of source values, multiplication with functions' values,
+    and NumericTraits must be defined. The mask's value_type must be an \ref AlgebraicField "algebraic field",
+    i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be defined.
+
+    By default, the borders are filled with zeros. Use the clearBorders switch to change that behavior if you need to.
+
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2,
+                  class T3, class S3>
+        void
+        fastNormalizedCrossCorrelation(MultiArrayView<2, T1, S1> const & in,
+                                       MultiArrayView<2, T2, S2> const & mask,
+                                       MultiArrayView<2, T3, S3> out,
+                                       bool clearBorders=true);
+
+    }
+    \endcode
+
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/correlation.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int m_w=51, m_h=51;
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> mask(m_w,m_h), src(w,h), dest(w,h);
+    ...
+
+    //compute normalized cross correlation of mask and image -> dest
+    fastNormalizedCrossCorrelation(mask, src, dest);
+    \endcode
+
+    <b> Preconditions:</b>
+
+    The image must be larger than the size of the mask.
+*/
+doxygen_overloaded_function(template <...> void fastNormalizedCrossCorrelation)
+
+template <class T1, class S1,
+          class T2, class S2,
+          class T3, class S3,
+          unsigned int N>
+inline void fastNormalizedCrossCorrelation(MultiArrayView<N, T1, S1> const & in,
+                                           MultiArrayView<N, T2, S2> const & mask,
+                                           MultiArrayView<N, T3, S3> out,
+                                           bool clearBorders=true)
+{
+    using namespace vigra::multi_math;
+    typedef typename MultiArrayShape<N>::type Shape;
+
+    vigra_precondition(in.shape() == out.shape(),
+                       "vigra::fastNormalizedCrossCorrelation(): shape mismatch between input and output.");
+
+    vigra_precondition(N>0 && N<=3,
+                       "vigra::fastNormalizedCrossCorrelation(): only implemented for arrays of 1, 2 or 3 dimensions.");
+
+    for(unsigned int dim=0; dim<N; dim++)
+    {
+        vigra_precondition(mask.shape()[dim] % 2 == 1, "vigra::fastNormalizedCrossCorrelation(): Mask width has to be of odd size!");
+        vigra_precondition(in.shape()[dim] >= mask.shape()[dim] , "vigra::fastNormalizedCrossCorrelation(): Mask is larger than image!");
+    }
+
+    //find mask mean and variance
+    double mask_mean = 0.0,
+           mask_var  = 0.0,
+           mask_size = prod(mask.shape());
+    mask.meanVariance(&mask_mean, &mask_var);
+
+    //calculate the fix part of the denumerator a.k.a. the mask std. deviation
+    double fix_denumerator = mask_size*sqrt(mask_var);
+
+    if(fix_denumerator == 0)
+    {
+        out = 0;
+    }
+    else
+    {
+        //pre-normalize the mask
+        MultiArray<N, double> norm_mask(mask.shape());
+        norm_mask = mask;
+        norm_mask -= mask_mean;
+
+        //calculate (semi-normalized) numerator:
+        MultiArray<N, double> corr_result(in.shape());
+
+        corr_result=in;
+        fastCrossCorrelation(corr_result, norm_mask, corr_result, clearBorders);
+
+
+        //Create fast sum tables for the variable denumerator
+        MultiArray<N, double> sum_table(in.shape()+1),
+                              sum_table2(in.shape()+1);
+
+        typename MultiArray<N, double>::difference_type zero_diff;
+
+        // now finally fill the sum tables
+        // keep a zero line/coloum at the beginning to avoid border computations and conditionals
+        integralMultiArray(in,sum_table.subarray(zero_diff+1, in.shape()+1));
+        integralMultiArraySquared(in, sum_table2.subarray(zero_diff+1, in.shape()+1));
+
+        MultiCoordinateIterator<N> i(in.shape()-mask.shape()+1), end = i.getEndIterator();
+
+        Shape maskRadius(floor(mask.shape()/2));
+        for(; i != end; ++i)
+        {
+            //calculate e(window) and e(window^2)
+            double window_mean         = detail::integralMultiArrayWindowMean(sum_table,  *i, *i+mask.shape()),
+                   window_squared_mean = detail::integralMultiArrayWindowMean(sum_table2, *i, *i+mask.shape()),
+                   var_denumerator = sqrt(mask_size*window_squared_mean - window_mean*window_mean);
+
+            //calculate overall result
+            if(var_denumerator == 0)
+            {
+                out[*i+maskRadius] = 0;
+            }
+            else
+            {
+                out[*i+maskRadius] = mask_size*corr_result[*i+maskRadius]/(var_denumerator*fix_denumerator);
+            }
+        }
+    }
+}
+
+template<class MaskIterator, class MaskAccessor>
+class CorrelationFunctor
+{
+public:
+    CorrelationFunctor(MaskIterator m_ul, MaskIterator m_lr, MaskAccessor m_acc)
+    : m_mask_ul(m_ul),
+      m_mask_lr(m_lr),
+      m_mask_acc(m_acc)
+    {
+    }
+
+    CorrelationFunctor(triple<MaskIterator,MaskIterator,MaskAccessor> m)
+    : m_mask_ul(m.first),
+      m_mask_lr(m.second),
+      m_mask_acc(m.third)
+    {
+    }
+
+    template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+    void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc) const
+    {
+        using namespace vigra;
+
+        SrcIterator s_ul = s - windowShape()/2,
+                    s_lr = s + windowShape()/2+Diff2D(1,1);
+
+        //find img2 mean
+        FindAverage<double> average;
+        inspectImage(srcIterRange(s_ul, s_lr, s_acc), average);
+
+        SrcIterator ys = s_ul;
+        SrcIterator xs = ys;
+
+        MaskIterator ym = m_mask_ul;
+        MaskIterator xm = ym;
+
+        double  res=0;
+
+        for( ; ys.y != s_lr.y; ys.y++, ym.y++)
+        {
+            for(xs = ys, xm = ym; xs.x != s_lr.x; xs.x++, xm.x++)
+            {
+                res += m_mask_acc(xm)*s_acc(xs);
+            }
+        }
+        d_acc.set(res,d);
+    }
+
+    Diff2D windowShape() const
+    {
+        return m_mask_lr - m_mask_ul;
+    }
+
+private:
+    MaskIterator m_mask_ul;
+    MaskIterator m_mask_lr;
+    MaskAccessor m_mask_acc;
+};
+
+/********************************************************/
+/*                                                      */
+/*          Cross correlation of mask to image          */
+/*                                                      */
+/********************************************************/
+
+/** \brief This function performes a (slow) cross-correlation
+
+    This function performes a (slow) cross-correlation using the window function environment
+    and comparison of the mask with the underlying image part for each pixel. This may
+    however be faster for very few comparisons.
+
+    The input pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over
+    the window functions' value_type <tt>T</tt>, i.e. addition of source values, multiplication with functions' values,
+    and NumericTraits must be defined. The mask's value_type must be an \ref AlgebraicField "algebraic field",
+    i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be defined.
+
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2,
+                  class T3, class S3>
+        void
+        crossCorrelation(MultiArrayView<2, T1, S1> const & in,
+                         MultiArrayView<2, T2, S2> const & mask,
+                         MultiArrayView<2, T3, S3> out);
+
+    }
+    \endcode
+
+    \deprecatedAPI{crossCorrelation}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class MaskIterator, class MaskAccessor,
+                  class DestIterator, class DestAccessor>
+        void crossCorrelation(SrcIterator s_ul, SrcIterator s_lr, SrcAccessor s_acc,
+                              MaskIterator m_ul, MaskIterator m_lr, MaskAccessor m_acc,
+                              DestIterator d_ul, DestAccessor d_acc);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class MaskIterator, class MaskAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        crossCorrelation(triple<MaskIterator, MaskIterator, MaskAccessor> src,
+                         triple<SrcIterator, SrcIterator, SrcAccessor> mask,
+                         pair<DestIterator, DestAccessor> dest);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/correlation.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int m_w=51, m_h=51;
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> mask(m_w,m_h), src(w,h), dest(w,h);
+    ...
+
+    //compute (slow) cross correlation of mask and image -> dest
+    crossCorrelation(mask, src, dest);
+    \endcode
+
+    <b> Preconditions:</b>
+
+    The image must be larger than the size of the mask.
+*/
+doxygen_overloaded_function(template <...> void crossCorrelation)
+
+template <class SrcIterator, class SrcAccessor,
+          class MaskIterator, class MaskAccessor,
+          class DestIterator, class DestAccessor>
+inline void crossCorrelation(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+                             MaskIterator m_ul,  MaskIterator m_lr,   MaskAccessor m_acc,
+                             DestIterator d_ul, DestAccessor d_acc,
+                             BorderTreatmentMode border = BORDER_TREATMENT_AVOID)
+{
+    CorrelationFunctor<MaskIterator, MaskAccessor> func(m_ul, m_lr, m_acc);
+    applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
+}
+
+template <class SrcIterator, class SrcAccessor,
+          class MaskIterator, class MaskAccessor,
+          class DestIterator, class DestAccessor>
+inline void crossCorrelation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                             triple<MaskIterator, MaskIterator, MaskAccessor> mask,
+                             pair<DestIterator, DestAccessor> dest,
+                             BorderTreatmentMode border = BORDER_TREATMENT_AVOID)
+{
+    crossCorrelation(src.first, src.second, src.third,
+                     mask.first, mask.second, mask.third,
+                     dest.first, dest.second,
+                     border);
+}
+
+template <class T1, class S1,
+          class T2, class S2,
+          class T3, class S3>
+inline void crossCorrelation(MultiArrayView<2, T1, S1> const & in,
+                             MultiArrayView<2, T2, S2> const & mask,
+                             MultiArrayView<2, T3, S3> out)
+{
+    vigra_precondition(in.shape() == out.shape(),
+                        "vigra::crossCorrelation(): shape mismatch between input and output.");
+    crossCorrelation(srcImageRange(in),
+                     srcImageRange(mask),
+                     destImage(out));
+}
+
+template<class MaskIterator, class MaskAccessor>
+class NormalizedCorrelationFunctor
+{
+public:
+
+    NormalizedCorrelationFunctor(MaskIterator m_ul, MaskIterator m_lr, MaskAccessor m_acc)
+    : m_mask_ul(m_ul),
+      m_mask_lr(m_lr),
+      m_mask_acc(m_acc),
+      m_s11(0.0),
+      m_avg1(0.0)
+    {
+        init_s11();
+    }
+
+    NormalizedCorrelationFunctor(triple<MaskIterator,MaskIterator,MaskAccessor> mask)
+    : m_mask_ul(mask.first),
+      m_mask_lr(mask.second),
+      m_mask_acc(mask.third),
+      m_s11(0.0),
+      m_avg1(0.0)
+    {
+        init_s11();
+    }
+
+    template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+    void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc) const
+    {
+        using namespace vigra;
+
+        SrcIterator s_ul = s - windowShape()/2,
+        s_lr = s + windowShape()/2+Diff2D(1,1);
+
+        if(m_s11 == 0.0)
+        {
+            d_acc.set(0,d);
+        }
+        else
+        {
+            //find img2 mean
+            FindAverage<double> average;
+            inspectImage(srcIterRange(s_ul, s_lr, s_acc), average);
+
+            SrcIterator ys = s_ul;
+            SrcIterator xs = ys;
+
+            MaskIterator ym = m_mask_ul;
+            MaskIterator xm = ym;
+
+            double  s1=0,s2=0, s12=0, s22=0;
+
+            for( ; ys.y != s_lr.y; ys.y++, ym.y++)
+            {
+                for(xs = ys, xm = ym; xs.x != s_lr.x; xs.x++, xm.x++)
+                {
+                    s1 = m_mask_acc(xm);
+                    s2 = s_acc(xs);
+                    s12 += (s1-m_avg1)*(s2-average());
+                    s22 += (s2-average())*(s2-average());
+                }
+            }
+            if(s22 == 0.0)
+            {
+                d_acc.set(0,d);
+            }
+            else
+            {
+                d_acc.set(s12/sqrt(m_s11*s22),d);
+            }
+        }
+    }
+
+    Diff2D windowShape() const
+    {
+        return m_mask_lr - m_mask_ul;
+    }
+
+private:
+    void init_s11()
+    {
+        //find mask mean
+        FindAverage<double> average;
+        inspectImage(srcIterRange(m_mask_ul, m_mask_lr, m_mask_acc), average);
+
+        MaskIterator ym = m_mask_ul;
+        MaskIterator xm = ym;
+
+        m_avg1 = average();
+
+        for( ; ym.y != m_mask_lr.y; ym.y++)
+        {
+            for(xm = ym; xm.x != m_mask_lr.x; xm.x++)
+            {
+                m_s11 += (m_mask_acc(xm)-m_avg1)*(m_mask_acc(xm)-m_avg1);
+            }
+        }
+    }
+
+    MaskIterator m_mask_ul;
+    MaskIterator m_mask_lr;
+    MaskAccessor m_mask_acc;
+
+    double m_s11;
+    double m_avg1;
+};
+
+/********************************************************/
+/*                                                      */
+/*     Normalized Cross correlation of mask to image    */
+/*                                                      */
+/********************************************************/
+
+/** \brief This function performes a (slow) normalized cross-correlation
+
+    This function performes a (slow) normalized cross-correlation using the window function
+    environment and comparison of the mask with the underlying image part for each pixel.
+    This may however be faster for very few comparisons.
+
+    The input pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over
+    the window functions' value_type <tt>T</tt>, i.e. addition of source values, multiplication with functions' values,
+    and NumericTraits must be defined. The mask's value_type must be an \ref AlgebraicField "algebraic field",
+    i.e. the arithmetic operations (+, -, *, /) and NumericTraits must be defined.
+
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2,
+                  class T3, class S3>
+        void
+        normalizedCrossCorrelation(MultiArrayView<2, T1, S1> const & in,
+                                   MultiArrayView<2, T2, S2> const & mask,
+                                   MultiArrayView<2, T3, S3> out);
+
+    }
+    \endcode
+
+    \deprecatedAPI{normalizedCrossCorrelation}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class MaskIterator, class MaskAccessor,
+                  class DestIterator, class DestAccessor>
+        void normalizedCrossCorrelation(SrcIterator s_ul, SrcIterator s_lr, SrcAccessor s_acc,
+                                        MaskIterator m_ul, MaskIterator m_lr, MaskAccessor m_acc,
+                                        DestIterator d_ul, DestAccessor d_acc);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class MaskIterator, class MaskAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        normalizedCrossCorrelation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                                   triple<MaskIterator, MaskIterator, MaskAccessor> mask,
+                                   pair<DestIterator, DestAccessor> dest);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/correlation.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int m_w=51, m_h=51;
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> mask(m_w,m_h), src(w,h), dest(w,h);
+    ...
+
+    //compute (slow) normalized cross correlation of mask and image -> dest
+    normalizedCrossCorrelation(mask, src, dest);
+    \endcode
+
+    <b> Preconditions:</b>
+
+    The image must be larger than the size of the mask.
+*/
+doxygen_overloaded_function(template <...> void normalizedCrossCorrelation)
+
+
+template <class SrcIterator, class SrcAccessor,
+          class MaskIterator, class MaskAccessor,
+          class DestIterator, class DestAccessor>
+inline void normalizedCrossCorrelation(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+                                       MaskIterator m_ul,  MaskIterator m_lr,   MaskAccessor m_acc,
+                                       DestIterator d_ul, DestAccessor d_acc,
+                                       BorderTreatmentMode border = BORDER_TREATMENT_AVOID)
+{
+    NormalizedCorrelationFunctor<MaskIterator, MaskAccessor> func(m_ul, m_lr, m_acc);
+    applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
+}
+
+template <class SrcIterator, class SrcAccessor,
+          class MaskIterator, class MaskAccessor,
+          class DestIterator, class DestAccessor>
+inline void normalizedCrossCorrelation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                                       triple<MaskIterator, MaskIterator, MaskAccessor> mask,
+                                       pair<DestIterator, DestAccessor> dest,
+                                       BorderTreatmentMode border = BORDER_TREATMENT_AVOID)
+{
+    normalizedCrossCorrelation(src.first, src.second, src.third,
+                               mask.first, mask.second, mask.third,
+                               dest.first, dest.second,
+                               border);
+}
+
+template <class T1, class S1,
+          class T2, class S2,
+          class T3, class S3>
+inline void normalizedCrossCorrelation(MultiArrayView<2, T1, S1> const & in,
+                                       MultiArrayView<2, T2, S2> const & mask,
+                                       MultiArrayView<2, T3, S3> out)
+{
+    vigra_precondition(in.shape() == out.shape(),
+                        "vigra::normalizedCrossCorrelation(): shape mismatch between input and output.");
+    normalizedCrossCorrelation(srcImageRange(in),
+                               srcImageRange(mask),
+                               destImage(out));
+}
+
+//@}
+
+} //end of namespace vigra
+
+#endif //VIGRA_CORRELATION_HXX
\ No newline at end of file
diff --git a/include/vigra/counting_iterator.hxx b/include/vigra/counting_iterator.hxx
new file mode 100644
index 0000000..883fd53
--- /dev/null
+++ b/include/vigra/counting_iterator.hxx
@@ -0,0 +1,407 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2015 by Thorsten Beier                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_COUNTING_ITERATOR_HXX
+#define VIGRA_COUNTING_ITERATOR_HXX
+
+
+#include <cmath>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+#include "error.hxx"
+#include "tinyvector.hxx"
+
+namespace vigra {
+
+namespace detail  {
+
+template <class T, bool is_float=false>
+struct CountingIteratorCompare
+{
+    // use exact comparison for integer counting
+    static bool equal(T left, T right, T /* step */)
+    {
+        return left == right;
+    }
+    static bool not_equal(T left, T right, T /* step */)
+    {
+        return left != right;
+    }
+    static bool less(T left, T right, T step)
+    {
+        // NOTE: the more efficient '(right - left)*step > 0'
+        //       fails for unsigned arguments
+        return step > 0
+                ? left < right
+                : left > right;
+    }
+    static bool less_equal(T left, T right, T step)
+    {
+        return step > 0
+                ? left <= right
+                : left >= right;
+    }
+    static bool greater(T left, T right, T step)
+    {
+        return step > 0
+                ? left > right
+                : left < right;
+    }
+    static bool greater_equal(T left, T right, T step)
+    {
+        return step > 0
+                ? left >= right
+                : left <= right;
+    }
+    // integer counting: if the raw distance is not divisible by step,
+    // we must round upwards
+    static std::ptrdiff_t distance(T from, T to, T step)
+    {
+        const double diff = (double(to) - double(from)) / double(step);
+        return diff > 0.0
+                 ? (std::ptrdiff_t)std::ceil(diff)
+                 : (std::ptrdiff_t)std::floor(diff);
+    }
+};
+
+template <class T>
+struct CountingIteratorCompare<T, true>
+{
+    typedef std::numeric_limits<T> limit;
+
+    // use comparison with tolerance for floating-point counting
+    // (the natural epsilon is 0.5*step)
+    static bool equal(T left, T right, T step)
+    {
+        return std::fabs(right-left) <= 0.5*std::fabs(step);
+    }
+    static bool not_equal(T left, T right, T step)
+    {
+        return std::fabs(right-left) > 0.5*std::fabs(step);
+    }
+    static bool less(T left, T right, T step)
+    {
+        return step > 0.0
+                ? right - left > 0.5*step
+                : right - left < 0.5*step;
+    }
+    static bool less_equal(T left, T right, T step)
+    {
+        return step > 0.0
+                ? left - right < 0.5*step
+                : left - right > 0.5*step;
+    }
+    static bool greater(T left, T right, T step)
+    {
+        return step > 0.0
+                ? left - right > 0.5*step
+                : left - right < 0.5*step;
+    }
+    static bool greater_equal(T left, T right, T step)
+    {
+        return step > 0.0
+                ? right - left < 0.5*step
+                : right - left > 0.5*step;
+    }
+    // floating-point counting: if the raw distance is not divisible by step,
+    // we round to nearest if the difference is small, otherwise upwards
+    static std::ptrdiff_t distance(T from, T to, T step)
+    {
+        const double diff = (double(to) - double(from)) / double(step);
+        return diff > 0.0
+                 ? (std::ptrdiff_t)std::ceil(diff*(1.0-2.0*limit::epsilon()))
+                 : (std::ptrdiff_t)std::floor(diff*(1.0-2.0*limit::epsilon()));
+    }
+};
+
+} // namespace detail
+
+/** \addtogroup MathFunctions
+*/
+//@{
+
+    /** \brief Iterator that counts upwards or downwards with a given step size.
+
+        This iterator replicates the functionality of Python's
+        well-known range-function. It is especially convenient in
+        range-based for-loops. <tt>CountingIterator</tt> also works for
+        floating-point counting.
+
+        <b>Usage:</b>
+
+        <b>\#include</b> \<vigra/counting_iterator.hxx\><br>
+        Namespace: vigra
+
+        You will normally construct instances of this iterator with
+        one of the <tt>range()</tt> factory functions. There are three versions
+        of this function <tt>range(end)</tt>, <tt>range(begin, end)</tt>, and
+        <tt>range(begin, end, step)</tt>.
+        \code
+        // count upwards from 0 to 4
+        for(int i: range(5))
+            std::cout << i << " ";  // prints '0 1 2 3 4'
+
+        // count upwards from 4 to 7
+        for(int i: range(4, 8))
+            std::cout << i << " ";  // prints '4 5 6 7'
+
+        // count upwards from 0 to 9 with step 3
+        for(int i: range(0, 9, 3))
+            std::cout << i << " ";  // prints '0 3 6'
+
+        // likewise (note upper bound)
+        for(int i: range(0, 7, 3))
+            std::cout << i << " ";  // prints '0 3 6'
+
+        // count downwards from 4 to 1 with step -1
+        for(int i: range(4, 0))
+            std::cout << i << " ";  // prints '4 3 2 1'
+
+        // count downwards from 8 to 2 with step -2
+        for(int i: range(8, 0, -2))
+            std::cout << i << " ";  // prints '8 6 4 2'
+        \endcode
+
+        Alternatively, you can create a traditional random-access iterator pair.
+        The end iterator can be conveniently constructed by the begin iterator's
+        <tt>end()</tt> function:
+        \code
+        auto iter = range(5),
+             end  = iter.end();
+        std::cout << std::accumulate(iter, end, 0) << std::endl; // prints '10'
+        \endcode
+
+        <tt>range()</tt> and <tt>CountingIterator</tt> also work for floating-point
+        arguments. As in the integer case, the upper bound is excluded from the range
+        if it can be reached by an integer multiple of the step (within machine
+        epsilon):
+        \code
+        for(auto i: range(1.0, 1.6, 0.1))  // 1.6 is excluded
+            std::cout << i << " ";         // prints '1 1.1 1.2 1.3 1.4 1.5'
+
+        for(auto i: range(1.0, 1.61, 0.1)) // 1.6 is included
+            std::cout << i << " ";         // prints '1 1.1 1.2 1.3 1.4 1.5 1.6'
+        \endcode
+
+        If you use an iterator pair, you can make clear which behavior you want
+        by using either <tt>iter < end</tt> or <tt>iter <= end</tt> to terminate
+        the loop:
+        \code
+        auto iter = range(1.0, 1.6, 0.1),
+             end  = iter.end();
+        for(; iter < end; ++iter)       // exclude upper bound
+            std::cout << *iter << " ";  // prints '1 1.1 1.2 1.3 1.4 1.5'
+
+        iter = range(1.0, 1.6, 0.1);
+        for(; iter <= end; ++iter)      // include upper bound
+            std::cout << *iter << " ";  // prints '1 1.1 1.2 1.3 1.4 1.5 1.6'
+        \endcode
+
+        Note that the termination condition is still <tt>iter <= end</tt>, even
+        when the iterator counts downwards:
+        \code
+        auto iter = range(1.6, 1.0, -0.1),
+             end  = iter.end();
+        for(; iter <= end; ++iter)
+            std::cout << *iter << " ";  // prints '1.6 1.5 1.4 1.3 1.2 1.1 1'
+        \endcode
+    */
+template<class T = std::ptrdiff_t>
+class CountingIterator
+: public std::iterator<std::random_access_iterator_tag,
+                       T, std::ptrdiff_t, T const *, T>
+{
+  public:
+    CountingIterator()
+    : begin_(0)
+    , end_(0)
+    , step_(1)
+    {}
+
+    CountingIterator(T begin, T end)
+    : begin_(begin)
+    , end_(end)
+    , step_(1)
+    {
+        vigra_precondition(begin <= end,
+            "CountingIterator(): begin must be less or equal to end.");
+    }
+
+    CountingIterator(T begin, T end, T step)
+    : begin_(begin)
+    , end_(end)
+    , step_(step)
+    {
+        vigra_precondition(step != 0,
+            "CountingIterator(): step must be non-zero.");
+        vigra_precondition((step > 0 && begin <= end) || (step < 0 && begin >= end),
+            "CountingIterator(): sign mismatch between step and (end-begin).");
+    }
+
+    CountingIterator(CountingIterator const & other, ReverseCopyTag)
+    : begin_(other.end_)
+    , end_(other.begin_)
+    , step_(-other.step_)
+    {}
+
+  public:
+
+    CountingIterator begin() const
+    {
+        return *this;
+    }
+
+    CountingIterator end() const
+    {
+        // since the range-based for-loop checks "iter != end",
+        // (end - begin) must be a multiple of step to avoid infinite loops
+        T end = begin_ + step_*Compare::distance(begin_, end_, step_);
+        return CountingIterator(end, end, step_);
+    }
+
+    bool empty() const
+    {
+        return Compare::greater_equal(begin_, end_, step_);
+    }
+
+    CountingIterator& operator++()    {begin_ += step_; return *this;} // prefix++
+    CountingIterator  operator++(int) {CountingIterator tmp(*this); ++(*this); return tmp;} // postfix++
+    CountingIterator& operator--()    {begin_ -= step_; return *this;} // prefix--
+    CountingIterator  operator--(int) {CountingIterator tmp(*this); --(*this); return tmp;} // postfix--
+
+    CountingIterator& operator+=(std::ptrdiff_t n)
+    {
+        begin_ += n*step_;
+        return *this;
+    }
+
+    CountingIterator operator+(std::ptrdiff_t n) const
+    {
+        return CountingIterator(*this) += n;
+    }
+
+    CountingIterator& operator-=(std::ptrdiff_t n)
+    {
+        begin_ -= n*step_;
+        return *this;
+    }
+
+    CountingIterator operator-(std::ptrdiff_t n) const
+    {
+        return CountingIterator(*this) -= n;
+    }
+
+    std::ptrdiff_t operator-(const CountingIterator& other) const
+    {
+        return Compare::distance(other.begin_, begin_, step_);
+    }
+
+    bool operator<(CountingIterator const & other) const
+    {
+        return Compare::less(begin_, other.begin_, step_);
+    }
+
+    bool operator<=(CountingIterator const & other) const
+    {
+        return Compare::less_equal(begin_, other.begin_, step_);
+    }
+
+    bool operator>(CountingIterator const & other) const
+    {
+        return Compare::greater(begin_, other.begin_, step_);
+    }
+
+    bool operator>=(CountingIterator const & other) const
+    {
+        return Compare::greater_equal(begin_, other.begin_, step_);
+    }
+
+    bool operator==(const CountingIterator& other) const
+    {
+        return Compare::equal(begin_, other.begin_, step_);
+    }
+
+    bool operator!=(const CountingIterator& other) const
+    {
+        return Compare::not_equal(begin_, other.begin_, step_);
+    }
+
+    T operator[](std::ptrdiff_t n) const {
+        return begin_ + n*step_;
+    }
+
+    T operator*() const {
+        return  begin_;
+    }
+
+    T const * operator->() const{
+        return &begin_;
+    }
+
+  private:
+
+    typedef detail::CountingIteratorCompare<T, std::is_floating_point<T>::value> Compare;
+
+    T begin_, end_, step_;
+};
+
+
+template <class T1, class T2, class T3>
+inline CountingIterator<T1>
+range(T1 begin, T2 end, T3 step)
+{
+    return CountingIterator<T1>(begin, end, step);
+}
+
+template <class T1, class T2>
+inline CountingIterator<T1>
+range(T1 begin, T2 end)
+{
+    return CountingIterator<T1>(begin, end, 1);
+}
+
+template <class T>
+inline CountingIterator<T>
+range(T end)
+{
+    return CountingIterator<T>(0, end, 1);
+}
+
+//@}
+
+} // namespace vigra
+
+#endif
diff --git a/include/vigra/delegate/delegate.hxx b/include/vigra/delegate/delegate.hxx
new file mode 100644
index 0000000..1c32335
--- /dev/null
+++ b/include/vigra/delegate/delegate.hxx
@@ -0,0 +1,47 @@
+/*
+    (c) Sergey Ryazanov (http://home.onego.ru/~ryazanov)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+For details, see "The Impossibly Fast C++ Delegates" at
+http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates
+*/
+
+#ifndef VIGRA_DELEGATE_INCLUDED
+#define VIGRA_DELEGATE_INCLUDED
+
+namespace vigra
+{
+#ifdef VIGRA_DELEGATE_PREFERRED_SYNTAX
+    template <typename TSignature> class delegate;
+    template <typename TSignature> class delegate_invoker;
+#endif
+}
+
+#ifdef _MSC_VER
+#define VIGRA_DELEGATE_CALLTYPE __fastcall
+#else
+#define VIGRA_DELEGATE_CALLTYPE
+#endif
+
+#include "detail/delegate_list.hxx"
+
+#undef VIGRA_DELEGATE_CALLTYPE
+
+#endif//VIGRA_DELEGATE_INCLUDED
diff --git a/include/vigra/delegate/detail/delegate_list.hxx b/include/vigra/delegate/detail/delegate_list.hxx
new file mode 100644
index 0000000..82bb867
--- /dev/null
+++ b/include/vigra/delegate/detail/delegate_list.hxx
@@ -0,0 +1,189 @@
+// Automaticly generaged by C:\Work\Projects\Delegates\include\srutil\delegate\detail\make_delegates.pl
+
+// 0 params
+#define VIGRA_DELEGATE_PARAM_COUNT 0
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS 
+#define VIGRA_DELEGATE_TEMPLATE_ARGS 
+#define VIGRA_DELEGATE_PARAMS 
+#define VIGRA_DELEGATE_ARGS 
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST 
+#define VIGRA_DELEGATE_INVOKER_DATA 
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 1 params
+#define VIGRA_DELEGATE_PARAM_COUNT 1
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1
+#define VIGRA_DELEGATE_PARAMS A1 a1
+#define VIGRA_DELEGATE_ARGS a1
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 2 params
+#define VIGRA_DELEGATE_PARAM_COUNT 2
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1, typename A2
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1, A2
+#define VIGRA_DELEGATE_PARAMS A1 a1, A2 a2
+#define VIGRA_DELEGATE_ARGS a1,a2
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1),a2(a2)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;A2 a2;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 3 params
+#define VIGRA_DELEGATE_PARAM_COUNT 3
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1, typename A2, typename A3
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1, A2, A3
+#define VIGRA_DELEGATE_PARAMS A1 a1, A2 a2, A3 a3
+#define VIGRA_DELEGATE_ARGS a1,a2,a3
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1),a2(a2),a3(a3)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;A2 a2;A3 a3;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 4 params
+#define VIGRA_DELEGATE_PARAM_COUNT 4
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1, typename A2, typename A3, typename A4
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1, A2, A3, A4
+#define VIGRA_DELEGATE_PARAMS A1 a1, A2 a2, A3 a3, A4 a4
+#define VIGRA_DELEGATE_ARGS a1,a2,a3,a4
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1),a2(a2),a3(a3),a4(a4)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;A2 a2;A3 a3;A4 a4;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 5 params
+#define VIGRA_DELEGATE_PARAM_COUNT 5
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1, typename A2, typename A3, typename A4, typename A5
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1, A2, A3, A4, A5
+#define VIGRA_DELEGATE_PARAMS A1 a1, A2 a2, A3 a3, A4 a4, A5 a5
+#define VIGRA_DELEGATE_ARGS a1,a2,a3,a4,a5
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1),a2(a2),a3(a3),a4(a4),a5(a5)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;A2 a2;A3 a3;A4 a4;A5 a5;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 6 params
+#define VIGRA_DELEGATE_PARAM_COUNT 6
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1, typename A2, typename A3, typename A4, typename A5, typename A6
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1, A2, A3, A4, A5, A6
+#define VIGRA_DELEGATE_PARAMS A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6
+#define VIGRA_DELEGATE_ARGS a1,a2,a3,a4,a5,a6
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1),a2(a2),a3(a3),a4(a4),a5(a5),a6(a6)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;A2 a2;A3 a3;A4 a4;A5 a5;A6 a6;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 7 params
+#define VIGRA_DELEGATE_PARAM_COUNT 7
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1, A2, A3, A4, A5, A6, A7
+#define VIGRA_DELEGATE_PARAMS A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7
+#define VIGRA_DELEGATE_ARGS a1,a2,a3,a4,a5,a6,a7
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1),a2(a2),a3(a3),a4(a4),a5(a5),a6(a6),a7(a7)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;A2 a2;A3 a3;A4 a4;A5 a5;A6 a6;A7 a7;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 8 params
+#define VIGRA_DELEGATE_PARAM_COUNT 8
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1, A2, A3, A4, A5, A6, A7, A8
+#define VIGRA_DELEGATE_PARAMS A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8
+#define VIGRA_DELEGATE_ARGS a1,a2,a3,a4,a5,a6,a7,a8
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1),a2(a2),a3(a3),a4(a4),a5(a5),a6(a6),a7(a7),a8(a8)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;A2 a2;A3 a3;A4 a4;A5 a5;A6 a6;A7 a7;A8 a8;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 9 params
+#define VIGRA_DELEGATE_PARAM_COUNT 9
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1, A2, A3, A4, A5, A6, A7, A8, A9
+#define VIGRA_DELEGATE_PARAMS A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9
+#define VIGRA_DELEGATE_ARGS a1,a2,a3,a4,a5,a6,a7,a8,a9
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1),a2(a2),a3(a3),a4(a4),a5(a5),a6(a6),a7(a7),a8(a8),a9(a9)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;A2 a2;A3 a3;A4 a4;A5 a5;A6 a6;A7 a7;A8 a8;A9 a9;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
+// 10 params
+#define VIGRA_DELEGATE_PARAM_COUNT 10
+#define VIGRA_DELEGATE_TEMPLATE_PARAMS typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10
+#define VIGRA_DELEGATE_TEMPLATE_ARGS A1, A2, A3, A4, A5, A6, A7, A8, A9, A10
+#define VIGRA_DELEGATE_PARAMS A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10
+#define VIGRA_DELEGATE_ARGS a1,a2,a3,a4,a5,a6,a7,a8,a9,a10
+#define VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST a1(a1),a2(a2),a3(a3),a4(a4),a5(a5),a6(a6),a7(a7),a8(a8),a9(a9),a10(a10)
+#define VIGRA_DELEGATE_INVOKER_DATA A1 a1;A2 a2;A3 a3;A4 a4;A5 a5;A6 a6;A7 a7;A8 a8;A9 a9;A10 a10;
+#include "delegate_template.hxx"
+#undef VIGRA_DELEGATE_PARAM_COUNT
+#undef VIGRA_DELEGATE_TEMPLATE_PARAMS
+#undef VIGRA_DELEGATE_TEMPLATE_ARGS
+#undef VIGRA_DELEGATE_PARAMS
+#undef VIGRA_DELEGATE_ARGS
+#undef VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+#undef VIGRA_DELEGATE_INVOKER_DATA
+
diff --git a/include/vigra/delegate/detail/delegate_template.hxx b/include/vigra/delegate/detail/delegate_template.hxx
new file mode 100644
index 0000000..b0c5d39
--- /dev/null
+++ b/include/vigra/delegate/detail/delegate_template.hxx
@@ -0,0 +1,169 @@
+/*
+    (c) Sergey Ryazanov (http://home.onego.ru/~ryazanov)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+For details, see "The Impossibly Fast C++ Delegates" at
+http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates
+*/
+
+#if VIGRA_DELEGATE_PARAM_COUNT > 0
+#define VIGRA_DELEGATE_SEPARATOR ,
+#else
+#define VIGRA_DELEGATE_SEPARATOR
+#endif
+
+// see BOOST_JOIN for explanation
+#define VIGRA_DELEGATE_JOIN_MACRO( X, Y) VIGRA_DELEGATE_DO_JOIN( X, Y )
+#define VIGRA_DELEGATE_DO_JOIN( X, Y ) VIGRA_DELEGATE_DO_JOIN2(X,Y)
+#define VIGRA_DELEGATE_DO_JOIN2( X, Y ) X##Y
+
+namespace vigra
+{
+#ifdef VIGRA_DELEGATE_PREFERRED_SYNTAX
+#define VIGRA_DELEGATE_CLASS_NAME delegate
+#define VIGRA_DELEGATE_INVOKER_CLASS_NAME delegate_invoker
+#else
+#define VIGRA_DELEGATE_CLASS_NAME VIGRA_DELEGATE_JOIN_MACRO(delegate,VIGRA_DELEGATE_PARAM_COUNT)
+#define VIGRA_DELEGATE_INVOKER_CLASS_NAME VIGRA_DELEGATE_JOIN_MACRO(delegate_invoker,VIGRA_DELEGATE_PARAM_COUNT)
+	template <typename R VIGRA_DELEGATE_SEPARATOR VIGRA_DELEGATE_TEMPLATE_PARAMS>
+	class VIGRA_DELEGATE_INVOKER_CLASS_NAME;
+#endif
+
+	template <typename R VIGRA_DELEGATE_SEPARATOR VIGRA_DELEGATE_TEMPLATE_PARAMS>
+#ifdef VIGRA_DELEGATE_PREFERRED_SYNTAX
+	class VIGRA_DELEGATE_CLASS_NAME<R (VIGRA_DELEGATE_TEMPLATE_ARGS)>
+#else
+	class VIGRA_DELEGATE_CLASS_NAME
+#endif
+	{
+	public:
+		typedef R return_type;
+#ifdef VIGRA_DELEGATE_PREFERRED_SYNTAX
+		typedef return_type (VIGRA_DELEGATE_CALLTYPE *signature_type)(VIGRA_DELEGATE_TEMPLATE_ARGS);
+		typedef VIGRA_DELEGATE_INVOKER_CLASS_NAME<signature_type> invoker_type;
+#else
+		typedef VIGRA_DELEGATE_INVOKER_CLASS_NAME<R VIGRA_DELEGATE_SEPARATOR VIGRA_DELEGATE_TEMPLATE_ARGS> invoker_type;
+#endif
+
+		VIGRA_DELEGATE_CLASS_NAME()
+			: object_ptr(0)
+			, stub_ptr(0)
+		{}
+
+		template <return_type (*TMethod)(VIGRA_DELEGATE_TEMPLATE_ARGS)>
+		static VIGRA_DELEGATE_CLASS_NAME from_function()
+		{
+			return from_stub(0, &function_stub<TMethod>);
+		}
+
+		template <class T, return_type (T::*TMethod)(VIGRA_DELEGATE_TEMPLATE_ARGS)>
+		static VIGRA_DELEGATE_CLASS_NAME from_method(T* object_ptr)
+		{
+			return from_stub(object_ptr, &method_stub<T, TMethod>);
+		}
+
+		template <class T, return_type (T::*TMethod)(VIGRA_DELEGATE_TEMPLATE_ARGS) const>
+		static VIGRA_DELEGATE_CLASS_NAME from_const_method(T const* object_ptr)
+		{
+			return from_stub(const_cast<T*>(object_ptr), &const_method_stub<T, TMethod>);
+		}
+
+		return_type operator()(VIGRA_DELEGATE_PARAMS) const
+		{
+			return (*stub_ptr)(object_ptr VIGRA_DELEGATE_SEPARATOR VIGRA_DELEGATE_ARGS);
+		}
+
+		operator bool () const
+		{
+			return stub_ptr != 0;
+		}
+
+		bool operator!() const
+		{
+			return !(operator bool());
+		}
+
+	private:
+		
+		typedef return_type (VIGRA_DELEGATE_CALLTYPE *stub_type)(void* object_ptr VIGRA_DELEGATE_SEPARATOR VIGRA_DELEGATE_PARAMS);
+
+		void* object_ptr;
+		stub_type stub_ptr;
+
+		static VIGRA_DELEGATE_CLASS_NAME from_stub(void* object_ptr, stub_type stub_ptr)
+		{
+			VIGRA_DELEGATE_CLASS_NAME d;
+			d.object_ptr = object_ptr;
+			d.stub_ptr = stub_ptr;
+			return d;
+		}
+
+		template <return_type (*TMethod)(VIGRA_DELEGATE_TEMPLATE_ARGS)>
+		static return_type VIGRA_DELEGATE_CALLTYPE function_stub(void* VIGRA_DELEGATE_SEPARATOR VIGRA_DELEGATE_PARAMS)
+		{
+			return (TMethod)(VIGRA_DELEGATE_ARGS);
+		}
+
+		template <class T, return_type (T::*TMethod)(VIGRA_DELEGATE_TEMPLATE_ARGS)>
+		static return_type VIGRA_DELEGATE_CALLTYPE method_stub(void* object_ptr VIGRA_DELEGATE_SEPARATOR VIGRA_DELEGATE_PARAMS)
+		{
+			T* p = static_cast<T*>(object_ptr);
+			return (p->*TMethod)(VIGRA_DELEGATE_ARGS);
+		}
+
+		template <class T, return_type (T::*TMethod)(VIGRA_DELEGATE_TEMPLATE_ARGS) const>
+		static return_type VIGRA_DELEGATE_CALLTYPE const_method_stub(void* object_ptr VIGRA_DELEGATE_SEPARATOR VIGRA_DELEGATE_PARAMS)
+		{
+			T const* p = static_cast<T*>(object_ptr);
+			return (p->*TMethod)(VIGRA_DELEGATE_ARGS);
+		}
+	};
+
+	template <typename R VIGRA_DELEGATE_SEPARATOR VIGRA_DELEGATE_TEMPLATE_PARAMS>
+#ifdef VIGRA_DELEGATE_PREFERRED_SYNTAX
+	class VIGRA_DELEGATE_INVOKER_CLASS_NAME<R (VIGRA_DELEGATE_TEMPLATE_ARGS)>
+#else
+	class VIGRA_DELEGATE_INVOKER_CLASS_NAME
+#endif
+	{
+		VIGRA_DELEGATE_INVOKER_DATA
+
+	public:
+		VIGRA_DELEGATE_INVOKER_CLASS_NAME(VIGRA_DELEGATE_PARAMS)
+#if VIGRA_DELEGATE_PARAM_COUNT > 0
+			:
+#endif
+			VIGRA_DELEGATE_INVOKER_INITIALIZATION_LIST
+		{
+		}
+
+		template <class TDelegate>
+		R operator()(TDelegate d) const
+		{
+			return d(VIGRA_DELEGATE_ARGS);
+		}
+	};
+}
+
+#undef VIGRA_DELEGATE_CLASS_NAME
+#undef VIGRA_DELEGATE_SEPARATOR
+#undef VIGRA_DELEGATE_JOIN_MACRO
+#undef VIGRA_DELEGATE_DO_JOIN
+#undef VIGRA_DELEGATE_DO_JOIN2
diff --git a/include/vigra/eccentricitytransform.hxx b/include/vigra/eccentricitytransform.hxx
new file mode 100644
index 0000000..facc01e
--- /dev/null
+++ b/include/vigra/eccentricitytransform.hxx
@@ -0,0 +1,293 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2014 by Philip Schill and Ullrich Koethe               */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+
+#ifndef VIGRA_ECCENTRICITYTRANSFORM_HXX
+#define VIGRA_ECCENTRICITYTRANSFORM_HXX
+
+/*std*/
+#include <algorithm>
+#include <set>
+
+/*vigra*/
+#include "accumulator.hxx"
+#include "multi_labeling.hxx"
+#include "multi_distance.hxx"
+#include "multi_resize.hxx"
+#include "graph_algorithms.hxx"
+
+
+namespace vigra
+{
+
+
+template <class Graph, class WeightType, 
+          class EdgeMap, class Shape>
+TinyVector<MultiArrayIndex, Shape::static_size> 
+eccentricityCentersOneRegionImpl(ShortestPathDijkstra<Graph, WeightType> & pathFinder,
+                        const EdgeMap & weights, WeightType maxWeight,
+                        Shape anchor, Shape const & start, Shape const & stop)
+{
+    int maxIterations = 4;
+    for(int k=0; k < maxIterations; ++k)
+    {
+        pathFinder.run(start, stop, weights, anchor, lemon::INVALID, maxWeight);
+        anchor = pathFinder.target();
+        // FIXME: implement early stopping when source and target don't change anymore
+    }
+    
+    Polygon<TinyVector<float, Shape::static_size> > path;
+    path.push_back_unsafe(anchor);
+    while(pathFinder.predecessors()[path.back()] != path.back())
+        path.push_back_unsafe(pathFinder.predecessors()[path.back()]);
+    return path[roundi(path.arcLengthQuantile(0.5))];
+}
+
+template <unsigned int N, class T, class S, class Graph,
+          class ACCUMULATOR, class DIJKSTRA, class Array>
+void 
+eccentricityCentersImpl(const MultiArrayView<N, T, S> & src,
+                        Graph const & g,
+                        ACCUMULATOR const & r,
+                        DIJKSTRA & pathFinder,
+                        Array & centers)
+{
+    using namespace acc;
+    typedef typename MultiArrayShape<N>::type Shape;
+    typedef typename Graph::Node Node;
+    typedef typename Graph::EdgeIt EdgeIt;
+    typedef float WeightType;
+    
+    typename Graph::template EdgeMap<WeightType> weights(g);
+    WeightType maxWeight = 0.0,
+               minWeight = N;
+    {
+        AccumulatorChainArray<CoupledArrays<N, WeightType, T>,
+                              Select< DataArg<1>, LabelArg<2>, Maximum> > a;
+    
+        MultiArray<N, WeightType> distances(src.shape());
+        boundaryMultiDistance(src, distances, true);
+        extractFeatures(distances, src, a);
+        for (EdgeIt edge(g); edge != lemon::INVALID; ++edge)
+        {
+            const Node u(g.u(*edge)), v(g.v(*edge));
+            const T label = src[u];
+            if(label != src[v])
+            {
+                weights[*edge] = NumericTraits<WeightType>::max();
+            }
+            else
+            {
+                WeightType weight = norm(u - v) * 
+                                  (get<Maximum>(a, label) + minWeight - 0.5*(distances[u] + distances[v]));
+                weights[*edge] = weight;
+                maxWeight = std::max(weight, maxWeight);
+            }
+        }
+    }
+    maxWeight *= src.size();
+    
+    T maxLabel = r.maxRegionLabel();
+    centers.resize(maxLabel+1);
+
+    for (T i=0; i <= maxLabel; ++i)
+    {
+        if(get<Count>(r, i) == 0)
+            continue;
+        centers[i] = eccentricityCentersOneRegionImpl(pathFinder, weights, maxWeight, 
+                                             get<RegionAnchor>(r, i), 
+                                             get<Coord<Minimum> >(r, i),
+                                             get<Coord<Maximum> >(r, i) + Shape(1));
+    }
+}
+
+/** \addtogroup MultiArrayDistanceTransform
+*/
+//@{
+
+    /** \brief Find the (approximate) eccentricity center in each region of a labeled image.
+        
+        <b> Declarations:</b>
+
+        pass arbitrary-dimensional array views:
+        \code
+        namespace vigra {
+            template <unsigned int N, class T, class S, class Array>
+            void 
+            eccentricityCenters(MultiArrayView<N, T, S> const & src,
+                                Array & centers);
+        }
+        \endcode
+        
+        \param[in] src : labeled array
+        \param[out] centers : list of eccentricity centers (required interface: 
+                               <tt>centers[k] = TinyVector<int, N>()</tt> must be supported)    
+                               
+        <b> Usage:</b>
+
+        <b>\#include</b> \<vigra/eccentricitytransform.hxx\><br/>
+        Namespace: vigra
+
+        \code
+        Shape3 shape(width, height, depth);
+        MultiArray<3, UInt32> labels(shape);
+        ArrayVector<TinyVector<Int32, N> > centers;
+        ...
+
+        eccentricityCenters(labels, centers);
+        \endcode
+    */
+template <unsigned int N, class T, class S, class Array>
+void 
+eccentricityCenters(const MultiArrayView<N, T, S> & src,
+                    Array & centers)
+{
+    using namespace acc;
+    typedef GridGraph<N> Graph;
+    typedef float WeightType;
+    
+    Graph g(src.shape(), IndirectNeighborhood);
+    ShortestPathDijkstra<Graph, WeightType> pathFinder(g);
+
+    AccumulatorChainArray<CoupledArrays<N, T>,
+                          Select< DataArg<1>, LabelArg<1>,
+                                  Count, BoundingBox, RegionAnchor> > a;
+    extractFeatures(src, a);
+    
+    eccentricityCentersImpl(src, g, a, pathFinder, centers);
+}
+
+    /** \brief Computes the (approximate) eccentricity transform on each region of a labeled image.
+        
+        <b> Declarations:</b>
+
+        pass arbitrary-dimensional array views:
+        \code
+        namespace vigra {
+            // compute only the accentricity transform
+            template <unsigned int N, class T, class S>
+            void 
+            eccentricityTransformOnLabels(MultiArrayView<N, T> const & src,
+                                          MultiArrayView<N, S> dest);
+            
+            // also return the eccentricity center of each region
+            template <unsigned int N, class T, class S, class Array>
+            void 
+            eccentricityTransformOnLabels(MultiArrayView<N, T> const & src,
+                                          MultiArrayView<N, S> dest,
+                                          Array & centers);
+        }
+        \endcode
+        
+        \param[in] src : labeled array
+        \param[out] dest : eccentricity transform of src
+        \param[out] centers : (optional) list of eccentricity centers (required interface: 
+                               <tt>centers[k] = TinyVector<int, N>()</tt> must be supported)    
+                               
+        <b> Usage:</b>
+
+        <b>\#include</b> \<vigra/eccentricitytransform.hxx\><br/>
+        Namespace: vigra
+
+        \code
+        Shape3 shape(width, height, depth);
+        MultiArray<3, UInt32> labels(shape);
+        MultiArray<3, float> dest(shape);
+        ArrayVector<TinyVector<Int32, N> > centers;
+        ...
+
+        eccentricityTransformOnLabels(labels, dest, centers);
+        \endcode
+    */
+template <unsigned int N, class T, class S, class Array>
+void 
+eccentricityTransformOnLabels(MultiArrayView<N, T> const & src,
+                              MultiArrayView<N, S> dest,
+                              Array & centers)
+{
+    using namespace acc;
+    typedef typename MultiArrayShape<N>::type Shape;
+    typedef GridGraph<N> Graph;
+    typedef typename Graph::Node Node;
+    typedef typename Graph::EdgeIt EdgeIt;
+    typedef float WeightType;
+    
+    vigra_precondition(src.shape() == dest.shape(), 
+        "eccentricityTransformOnLabels(): Shape mismatch between src and dest.");
+        
+    Graph g(src.shape(), IndirectNeighborhood);
+    ShortestPathDijkstra<Graph, WeightType> pathFinder(g);
+
+    using namespace acc;        
+    AccumulatorChainArray<CoupledArrays<N, T>,
+                          Select< DataArg<1>, LabelArg<1>,
+                                  Count, BoundingBox, RegionAnchor> > a;
+    extractFeatures(src, a);
+    
+    eccentricityCentersImpl(src, g, a, pathFinder, centers);
+
+    typename Graph::template EdgeMap<WeightType> weights(g);
+    for (EdgeIt edge(g); edge != lemon::INVALID; ++edge)
+    {
+        const Node u(g.u(*edge)), v(g.v(*edge));
+        const T label = src[u];
+        if(label != src[v])
+            weights[*edge] = NumericTraits<WeightType>::max();
+        else
+            weights[*edge] = norm(u - v);
+    }
+    ArrayVector<Shape> filtered_centers;
+    for (T i=0; i <= a.maxRegionLabel(); ++i)
+        if(get<Count>(a, i) > 0)
+            filtered_centers.push_back(centers[i]);
+    pathFinder.runMultiSource(weights, filtered_centers.begin(), filtered_centers.end());
+    dest = pathFinder.distances();
+}
+
+template <unsigned int N, class T, class S>
+inline void 
+eccentricityTransformOnLabels(MultiArrayView<N, T> const & src,
+                              MultiArrayView<N, S> dest)
+{
+    ArrayVector<TinyVector<MultiArrayIndex, N> > centers;
+    eccentricityTransformOnLabels(src, dest, centers);
+}
+
+//@}
+
+} // namespace vigra
+
+
+#endif // VIGRA_ECCENTRICITYTRANSFORM_HXX
diff --git a/include/vigra/edgedetection.hxx b/include/vigra/edgedetection.hxx
index 0a84185..cd88858 100644
--- a/include/vigra/edgedetection.hxx
+++ b/include/vigra/edgedetection.hxx
@@ -626,19 +626,21 @@ void differenceOfExponentialCrackEdgeImage(
         }
     }
 
-    typename TMPIMG::Iterator ix = iy;
-    typename TMPIMG::Iterator tx = ty;
-    DestIterator              dx = dy;
-
-    for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, dx.x+=2)
     {
-        TMPTYPE diff = *tx - *ix;
-        TMPTYPE gx = tx[right] - *tx;
+        typename TMPIMG::Iterator ix = iy;
+        typename TMPIMG::Iterator tx = ty;
+        DestIterator              dx = dy;
 
-        if((gx * gx > thresh) &&
-           (diff * (tx[right] - ix[right]) < zero))
+        for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, dx.x+=2)
         {
-            da.set(edge_marker, dx, right);
+            TMPTYPE diff = *tx - *ix;
+            TMPTYPE gx = tx[right] - *tx;
+
+            if((gx * gx > thresh) &&
+               (diff * (tx[right] - ix[right]) < zero))
+            {
+                da.set(edge_marker, dx, right);
+            }
         }
     }
 
@@ -2236,6 +2238,9 @@ void cannyEdgeImageFromGradWithThinning(
            GradValue gradient_threshold,
            DestValue edge_marker, bool addBorder = true)
 {
+    vigra_precondition(gradient_threshold >= NumericTraits<GradValue>::zero(),
+         "cannyEdgeImageFromGradWithThinning(): gradient threshold must not be negative.");
+    
     int w = slr.x - sul.x;
     int h = slr.y - sul.y;
 
@@ -2312,7 +2317,7 @@ void cannyEdgeImageFromGradWithThinning(
             BImage::traverser eneu = eul + pneu;
             if(*eneu == 1) // point is boundary and not yet in the queue
             {
-                int v = detail::neighborhoodConfiguration(eneu);
+                v = detail::neighborhoodConfiguration(eneu);
                 if(isSimplePoint[v])
                 {
                     pqueue.push(SP(pneu, norm(sa(sul+pneu))));
diff --git a/include/vigra/eigensystem.hxx b/include/vigra/eigensystem.hxx
index 96fa1e5..6d5ee5d 100644
--- a/include/vigra/eigensystem.hxx
+++ b/include/vigra/eigensystem.hxx
@@ -994,7 +994,7 @@ bool hessenbergQrDecomposition(MultiArrayView<2, T, C1> & H, MultiArrayView<2, T
         \a a is a real symmetric matrix, \a ew is a single-column matrix
         holding the eigenvalues, and \a ev is a matrix of the same size as
         \a a whose columns are the corresponding eigenvectors. Eigenvalues
-        will be sorted from largest to smallest magnitude.
+        will be sorted from largest to smallest.
         The algorithm returns <tt>false</tt> when it doesn't
         converge. It can be applied in-place, i.e. <tt>&a == &ev</tt> is allowed.
         The code of this function was adapted from JAMA.
@@ -1026,66 +1026,153 @@ symmetricEigensystem(MultiArrayView<2, T, C1> const & a,
 }
 
 namespace detail{
-template <class T, class C1, class C2, class C3>
+
+template <class T, class C2, class C3>
 bool
-symmetricEigensystem2x2(MultiArrayView<2, T, C1> const & a,
+symmetricEigensystem2x2(T a00, T a01, T a11,
             MultiArrayView<2, T, C2> & ew, MultiArrayView<2, T, C3> & ev)
 {
-    vigra_precondition(isSymmetric(a),
-        "symmetricEigensystem(): symmetric input matrix required.");
- 
     double evec[2]={0,0};
-      
-      /* Eigenvectors*/ 
-      if (a(0,1)==0){
-        if (fabs(a(1,1))>fabs(a(0,0))){
-          evec[0]=0.;
-          evec[1]=1.;
-          ew(0,0)=a(1,1);
-          ew(1,0)=a(0,0);
-         }
-        else if(fabs(a(0,0))>fabs(a(1,1))) {
-          evec[0]=1.;
-          evec[1]=0.;
-          ew(0,0)=a(0,0);
-          ew(1,0)=a(1,1);
+
+    /* Eigenvectors*/
+    if (a01==0){
+        if (fabs(a11)>fabs(a00)){
+            evec[0]=0.;
+            evec[1]=1.;
+            ew(0,0)=a11;
+            ew(1,0)=a00;
+        }
+        else if(fabs(a00)>fabs(a11)) {
+            evec[0]=1.;
+            evec[1]=0.;
+            ew(0,0)=a00;
+            ew(1,0)=a11;
         }
         else {
-          evec[0]=.5* M_SQRT2;
-          evec[1]=.5* M_SQRT2;
-          ew(0,0)=a(0,0);
-          ew(1,0)=a(1,1);
+            evec[0]=.5* M_SQRT2;
+            evec[1]=.5* M_SQRT2;
+            ew(0,0)=a00;
+            ew(1,0)=a11;
         }
-      }
-      else{ 
-        double temp=a(1,1)-a(0,0);
-        
-        double coherence=sqrt(temp*temp+4*a(0,1)*a(0,1));
-        evec[0]=2*a(0,1);
+    }
+    else{
+        double temp=a11-a00;
+
+        double coherence=sqrt(temp*temp+4*a01*a01);
+        evec[0]=2*a01;
         evec[1]=temp+coherence;
         temp=std::sqrt(evec[0]*evec[0]+evec[1]*evec[1]);
         if (temp==0){
-          evec[0]=.5* M_SQRT2;
-          evec[1]=.5* M_SQRT2;
-          ew(0,0)=1.;
-          ew(1,0)=1.;
+            evec[0]=.5* M_SQRT2;
+            evec[1]=.5* M_SQRT2;
+            ew(0,0)=1.;
+            ew(1,0)=1.;
         }
         else{
-          evec[0]/=temp;
-          evec[1]/=temp;
-          
-          /* Eigenvalues */
-          ew(0,0)=.5*(a(0,0)+a(1,1)+coherence);
-          ew(1,0)=.5*(a(0,0)+a(1,1)-coherence);
+            evec[0]/=temp;
+            evec[1]/=temp;
+
+            /* Eigenvalues */
+            ew(0,0)=.5*(a00+a11+coherence);
+            ew(1,0)=.5*(a00+a11-coherence);
         }
-      }
-      ev(0,0)= evec[0];
-      ev(1,0)= evec[1];
-      ev(0,1)=-evec[1];
-      ev(1,1)= evec[0];
-      return true;
+    }
+    ev(0,0)= evec[0];
+    ev(1,0)= evec[1];
+    ev(0,1)=-evec[1];
+    ev(1,1)= evec[0];
+    return true;
+}
+
+template <class T, class C2, class C3>
+bool
+symmetricEigensystem3x3(T a00, T a01, T a02, T a11, T a12, T a22,
+            MultiArrayView<2, T, C2> & ew, MultiArrayView<2, T, C3> & ev)
+{
+    symmetric3x3Eigenvalues(a00, a01, a02, a11, a12, a22,
+                            &ew(0,0), &ew(1,0), &ew(2,0));
+
+    /* Calculate eigen vectors */
+    double a1=a01*a12,
+           a2=a01*a02,
+           a3=sq(a01);
+
+    double b1=a00-ew(0,0),
+           b2=a11-ew(0,0);
+    ev(0,0)=a1-a02*b2;
+    ev(1,0)=a2-a12*b1;
+    ev(2,0)=b1*b2-a3;
+
+    b1=a00-ew(1,0);
+    b2=a11-ew(1,0);
+    ev(0,1)=a1-a02*b2;
+    ev(1,1)=a2-a12*b1;
+    ev(2,1)=b1*b2-a3;
+
+    b1=a00-ew(2,0);
+    b2=a11-ew(2,0);
+    ev(0,2)=a1-a02*b2;
+    ev(1,2)=a2-a12*b1;
+    ev(2,2)=b1*b2-a3;
+
+    /* Eigen vector normalization */
+    double l0=norm(columnVector(ev, 0));
+    double l1=norm(columnVector(ev, 1));
+    double l2=norm(columnVector(ev, 2));
+
+    /* Detect fail : eigenvectors with only zeros */
+    double M = std::max(std::max(abs(ew(0,0)), abs(ew(1,0))), abs(ew(2,0)));
+    double epsilon = 1e-12*M;
+    if(l0<epsilon) { return false; }
+    if(l1<epsilon) { return false; }
+    if(l2<epsilon) { return false; }
+
+    columnVector(ev, 0) /= l0;
+    columnVector(ev, 1) /= l1;
+    columnVector(ev, 2) /= l2;
+
+    /* Succes    */
+    return true;
+}
+
+} // closing namespace detail
+
+
+    /** Fast computation of the eigensystem of a 2x2 or 3x3 symmetric matrix.
+
+        The function works like \ref symmetricEigensystem(), but uses fast analytic
+        formula to avoid iterative computations.
+
+        <b>\#include</b> \<vigra/eigensystem.hxx\> or<br>
+        <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
+        Namespaces: vigra and vigra::linalg
+     */
+template <class T, class C1, class C2, class C3>
+bool
+symmetricEigensystemNoniterative(MultiArrayView<2, T, C1> const & a,
+                                 MultiArrayView<2, T, C2> & ew, MultiArrayView<2, T, C3> & ev)
+{
+    vigra_precondition(isSymmetric(a),
+        "symmetricEigensystemNoniterative(): symmetric input matrix required.");
+    const MultiArrayIndex acols = columnCount(a);
+    if(acols == 2)
+    {
+        detail::symmetricEigensystem2x2(a(0,0), a(0,1), a(1,1), ew, ev);
+        return true;
+    }
+    if(acols == 3)
+    {
+        // try the fast algorithm
+        if(detail::symmetricEigensystem3x3(a(0,0), a(0,1), a(0,2), a(1,1), a(1,2), a(2,2),
+                                           ew, ev))
+            return true;
+        // fast algorithm failed => fall-back to iterative algorithm
+        return symmetricEigensystem(a, ew, ev);
+    }
+    vigra_precondition(false,
+        "symmetricEigensystemNoniterative(): can only handle 2x2 and 3x3 matrices.");
+    return false;
 }
-} // closing namespace detail 
 
     /** Compute the eigensystem of a square, but
         not necessarily symmetric matrix.
@@ -1187,9 +1274,9 @@ bool polynomialRootsEigenvalueMethod(POLYNOMIAL const & poly, VECTOR & roots)
         with a <tt>value_type</tt> compatible to the type <tt>POLYNOMIAL::Real</tt>) to which
         the roots are appended. The function calls \ref polynomialRootsEigenvalueMethod() and
         throws away all complex roots. It returns <tt>false</tt> if it fails to converge.
-        The parameter <tt>polishRoots</tt> is ignored (it is only here for syntax compatibility 
+        The parameter <tt>polishRoots</tt> is ignored (it is only here for syntax compatibility
         with polynomialRealRoots()).
-        
+
 
         <b>\#include</b> \<vigra/eigensystem.hxx\> or<br>
         <b>\#include</b> \<vigra/linear_algebra.hxx\><br>
@@ -1222,6 +1309,7 @@ bool polynomialRealRootsEigenvalueMethod(POLYNOMIAL const & p, VECTOR & roots)
 } // namespace linalg
 
 using linalg::symmetricEigensystem;
+using linalg::symmetricEigensystemNoniterative;
 using linalg::nonsymmetricEigensystem;
 using linalg::polynomialRootsEigenvalueMethod;
 using linalg::polynomialRealRootsEigenvalueMethod;
diff --git a/include/vigra/fftw.hxx b/include/vigra/fftw.hxx
index b65fdef..f109f7a 100644
--- a/include/vigra/fftw.hxx
+++ b/include/vigra/fftw.hxx
@@ -604,6 +604,27 @@ class FFTWMagnitudeAccessor
 
 /* documentation: see fftw3.hxx
 */
+class FFTWLogMagnitudeAccessor
+{
+  public:
+        /// The accessor's value type.
+    typedef fftw_real value_type;
+
+        /// Read natural log of magnitude at iterator position.
+    template <class ITERATOR>
+    value_type operator()(ITERATOR const & i) const {
+        return std::log((*i).magnitude() + 1);
+    }
+
+        /// Read natural log of magnitude at offset from iterator position.
+    template <class ITERATOR, class DIFFERENCE>
+    value_type operator()(ITERATOR const & i, DIFFERENCE d) const {
+        return std::log((i[d]).magnitude() + 1);
+    }
+};
+
+/* documentation: see fftw3.hxx
+*/
 class FFTWPhaseAccessor
 {
   public:
diff --git a/include/vigra/fftw3.hxx b/include/vigra/fftw3.hxx
index 112723d..4749ae9 100644
--- a/include/vigra/fftw3.hxx
+++ b/include/vigra/fftw3.hxx
@@ -1004,7 +1004,7 @@ inline typename FFTWComplex<R>::NormType abs(const FFTWComplex<R> &a)
     return a.magnitude();
 }
 
-    /// pahse
+    /// phase
 template <class R>
 inline R arg(const FFTWComplex<R> &a)
 {
@@ -1393,6 +1393,32 @@ class FFTWMagnitudeAccessor
     }
 };
 
+    /** Calculate natural logarithm of magnitude of complex number on the fly.
+
+    <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
+    <b>\#include</b> \<vigra/fftw.hxx\> (for deprecated FFTW 2)<br>
+    Namespace: vigra
+    */
+template <class Real = double>
+class FFTWLogMagnitudeAccessor
+{
+  public:
+        /// The accessor's value type.
+    typedef Real value_type;
+
+        /// Read natural log of magnitude at iterator position.
+    template <class ITERATOR>
+    value_type operator()(ITERATOR const & i) const {
+        return std::log((*i).magnitude() + 1);
+    }
+
+        /// Read natural log of magnitude at offset from iterator position.
+    template <class ITERATOR, class DIFFERENCE>
+    value_type operator()(ITERATOR const & i, DIFFERENCE d) const {
+        return std::log((i[d]).magnitude() + 1);
+    }
+};
+
     /** Calculate phase of complex number on the fly.
 
     <b>\#include</b> \<vigra/fftw3.hxx\> (for FFTW 3) or<br>
diff --git a/include/vigra/fixedpoint.hxx b/include/vigra/fixedpoint.hxx
index 6da55e8..d499128 100644
--- a/include/vigra/fixedpoint.hxx
+++ b/include/vigra/fixedpoint.hxx
@@ -1216,7 +1216,7 @@ public:
             to the target type's <tt>OverflowHandling</tt>.
         */
     explicit FixedPoint16(double rhs)
-    : value(detail::FP16OverflowHandling<OverflowHandling>::exec(roundi(rhs * ONE)))
+    : value(detail::FP16OverflowHandling<OverflowHandling>::exec((Int32)roundi(rhs * ONE)))
     {
         VIGRA_STATIC_ASSERT((FixedPoint_error__Right_shift_operator_has_unsupported_semantics<((-1 >> 8) == -1)>));
     }
diff --git a/include/vigra/graph_algorithms.hxx b/include/vigra/graph_algorithms.hxx
new file mode 100644
index 0000000..b09f27b
--- /dev/null
+++ b/include/vigra/graph_algorithms.hxx
@@ -0,0 +1,1566 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2014 by Thorsten Beier and Ullrich Koethe              */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+/**
+ * This header provides definitions of graph-related algorithms
+ */
+
+#ifndef VIGRA_GRAPH_ALGORITHMS_HXX
+#define VIGRA_GRAPH_ALGORITHMS_HXX
+
+/*std*/
+#include <algorithm>
+#include <vector>
+#include <functional>
+#include <set>
+#include <iomanip>
+
+/*vigra*/
+#include "graphs.hxx"
+#include "graph_generalization.hxx"
+#include "multi_gridgraph.hxx"
+#include "priority_queue.hxx"
+#include "union_find.hxx"
+#include "adjacency_list_graph.hxx"
+#include "graph_maps.hxx"
+
+#include "timing.hxx"
+//#include "openmp_helper.hxx"
+
+
+#include "functorexpression.hxx"
+#include "array_vector.hxx"
+
+namespace vigra{
+
+/** \addtogroup GraphDataStructures
+*/
+//@{
+
+    namespace detail_graph_algorithms{
+        template <class GRAPH_MAP,class COMPERATOR>
+        struct GraphItemCompare
+        {
+            
+            GraphItemCompare(const GRAPH_MAP & map,const COMPERATOR & comperator)
+            : map_(map),
+              comperator_(comperator){
+
+            }
+
+            template<class KEY>
+            bool operator()(const KEY & a, const KEY & b) const{
+                return comperator_(map_[a],map_[b]);
+            }
+
+            const GRAPH_MAP & map_;
+            const COMPERATOR & comperator_;
+        };
+    } // namespace detail_graph_algorithms
+
+    /// \brief get a vector of Edge descriptors
+    ///
+    /// Sort the Edge descriptors given weights 
+    /// and a comperator
+    template<class GRAPH,class WEIGHTS,class COMPERATOR>
+    void edgeSort(
+        const GRAPH   & g,
+        const WEIGHTS & weights,
+        const COMPERATOR  & comperator,
+        std::vector<typename GRAPH::Edge> & sortedEdges
+    ){
+        sortedEdges.resize(g.edgeNum());
+        size_t c=0;
+        for(typename GRAPH::EdgeIt e(g);e!=lemon::INVALID;++e){
+            sortedEdges[c]=*e;
+            ++c;
+        }
+        detail_graph_algorithms::GraphItemCompare<WEIGHTS,COMPERATOR> edgeComperator(weights,comperator);
+        std::sort(sortedEdges.begin(),sortedEdges.end(),edgeComperator);
+    }
+
+
+    /// \brief copy a lemon node map
+    template<class G,class A,class B>
+    void copyNodeMap(const G & g,const A & a ,B & b){
+        typename  G::NodeIt iter(g);
+        while(iter!=lemon::INVALID){
+            b[*iter]=a[*iter];
+            ++iter;
+        }
+
+    }
+    /// \brief copy a lemon edge map
+    template<class G,class A,class B>
+    void copyEdgeMap(const G & g,const A & a ,B & b){
+        typename  G::EdgeIt iter(g);
+        while(iter!=lemon::INVALID){
+            b[*iter]=a[*iter];
+            ++iter;
+        }
+    }
+    /// \brief fill a lemon node map 
+    template<class G,class A,class T>
+    void fillNodeMap(const G & g, A & a, const T & value){
+        typename  G::NodeIt iter(g);
+        while(iter!=lemon::INVALID){
+            a[*iter]=value;
+            ++iter;
+        }
+    }
+    /// \brief fill a lemon edge map
+    template<class G,class A,class T>
+    void fillEdgeMap(const G & g,A & a ,const T & value){
+        typename  G::EdgeIt iter(g);
+        while(iter!=lemon::INVALID){
+            a[*iter]=value;
+            ++iter;
+        }
+    }
+
+    /// \brief make a region adjacency graph from a graph and labels w.r.t. that graph
+    ///
+    /// \param graphIn  : input graph
+    /// \param labels   : labels w.r.t. graphIn
+    /// \param[out] rag  : region adjacency graph 
+    /// \param[out] affiliatedEdges : a vector of edges of graphIn for each edge in rag
+    /// \param      ignoreLabel : optional label to ignore (default: -1 means no label will be ignored)
+    ///
+    template<
+        class GRAPH_IN,
+        class GRAPH_IN_NODE_LABEL_MAP
+    >
+    void makeRegionAdjacencyGraph(
+        GRAPH_IN                   graphIn,
+        GRAPH_IN_NODE_LABEL_MAP    labels,
+        AdjacencyListGraph & rag,
+        typename AdjacencyListGraph:: template EdgeMap< std::vector<typename GRAPH_IN::Edge> > & affiliatedEdges,
+        const Int64   ignoreLabel=-1
+    ){
+        rag=AdjacencyListGraph();
+        typedef typename GraphMapTypeTraits<GRAPH_IN_NODE_LABEL_MAP>::Value LabelType;
+        typedef GRAPH_IN GraphIn;
+        typedef AdjacencyListGraph GraphOut;
+
+        typedef typename GraphIn::Edge   EdgeGraphIn;
+        typedef typename GraphIn::NodeIt NodeItGraphIn;
+        typedef typename GraphIn::EdgeIt EdgeItGraphIn;
+        typedef typename GraphOut::Edge   EdgeGraphOut; 
+
+
+        for(NodeItGraphIn iter(graphIn);iter!=lemon::INVALID;++iter){
+            const LabelType l=labels[*iter];
+            if(ignoreLabel==-1 || static_cast<Int64>(l)!=ignoreLabel)
+                rag.addNode(l);
+        }
+    
+        for(EdgeItGraphIn e(graphIn);e!=lemon::INVALID;++e){
+            const EdgeGraphIn edge(*e);
+            const LabelType lu = labels[graphIn.u(edge)];
+            const LabelType lv = labels[graphIn.v(edge)];
+            if(  lu!=lv && ( ignoreLabel==-1 || (static_cast<Int64>(lu)!=ignoreLabel  && static_cast<Int64>(lv)!=ignoreLabel) )  ){
+                // if there is an edge between lu and lv no new edge will be added
+                rag.addEdge( rag.nodeFromId(lu),rag.nodeFromId(lv));
+            }
+        }
+        
+        //SET UP HYPEREDGES
+        affiliatedEdges.assign(rag);
+        for(EdgeItGraphIn e(graphIn);e!=lemon::INVALID;++e){
+            const EdgeGraphIn edge(*e);
+            const LabelType lu = labels[graphIn.u(edge)];
+            const LabelType lv = labels[graphIn.v(edge)];
+            //std::cout<<"edge between ?? "<<lu<<" "<<lv<<"\n";
+            if(  lu!=lv && ( ignoreLabel==-1 || (static_cast<Int64>(lu)!=ignoreLabel  && static_cast<Int64>(lv)!=ignoreLabel) )  ){
+                //std::cout<<"find edge between "<<lu<<" "<<lv<<"\n";
+                EdgeGraphOut ragEdge= rag.findEdge(rag.nodeFromId(lu),rag.nodeFromId(lv));
+                //std::cout<<"invalid?"<<bool(ragEdge==lemon::INVALID)<<" id "<<rag.id(ragEdge)<<"\n";
+                affiliatedEdges[ragEdge].push_back(edge);
+                //std::cout<<"write done\n";
+            }
+        }
+    }
+
+    template<unsigned int DIM, class DTAG, class AFF_EDGES>
+    size_t affiliatedEdgesSerializationSize(
+        const GridGraph<DIM,DTAG> & gridGraph,
+        const AdjacencyListGraph & rag,
+        const AFF_EDGES & affEdges
+    ){
+        size_t size = 0;
+
+        typedef typename  AdjacencyListGraph::EdgeIt EdgeIt;
+        typedef typename  AdjacencyListGraph::Edge Edge;
+
+        for(EdgeIt iter(rag); iter!=lemon::INVALID; ++iter){
+            const Edge e(*iter);
+            size+=1;
+            size+=affEdges[e].size()*(DIM+1);
+        }
+        return size;
+    }
+
+    template<class OUT_ITER, unsigned int DIM, class DTAG, class AFF_EDGES>
+    void serializeAffiliatedEdges(
+        const GridGraph<DIM,DTAG> & gridGraph,
+        const AdjacencyListGraph & rag,
+        const AFF_EDGES & affEdges,
+        OUT_ITER outIter
+    ){
+      
+        typedef typename  AdjacencyListGraph::EdgeIt EdgeIt;
+        typedef typename  AdjacencyListGraph::Edge Edge;
+        typedef typename  GridGraph<DIM,DTAG>::Edge GEdge;
+
+        for(EdgeIt iter(rag); iter!=lemon::INVALID; ++iter){
+
+            const Edge edge = *iter;
+            const size_t numAffEdge = affEdges[edge].size();
+            *outIter = numAffEdge; ++outIter;
+
+            for(size_t i=0; i<numAffEdge; ++i){
+                const GEdge gEdge = affEdges[edge][i];
+                for(size_t d=0; d<DIM+1; ++d){
+                    *outIter = gEdge[d]; ++outIter;
+                }
+            }
+        }
+    }
+
+    template<class IN_ITER, unsigned int DIM, class DTAG, class AFF_EDGES>
+    void deserializeAffiliatedEdges(
+        const GridGraph<DIM,DTAG> & gridGraph,
+        const AdjacencyListGraph & rag,
+        AFF_EDGES & affEdges,
+        IN_ITER begin,
+        IN_ITER end
+    ){
+      
+        typedef typename  AdjacencyListGraph::EdgeIt EdgeIt;
+        typedef typename  AdjacencyListGraph::Edge Edge;
+        typedef typename  GridGraph<DIM,DTAG>::Edge GEdge;
+
+        affEdges.assign(rag);
+
+        for(EdgeIt iter(rag); iter!=lemon::INVALID; ++iter){
+
+            const Edge edge = *iter;
+            const size_t numAffEdge = *begin; ++begin;
+
+            for(size_t i=0; i<numAffEdge; ++i){
+                GEdge gEdge;
+                for(size_t d=0; d<DIM+1; ++d){
+                    gEdge[d]=*begin; ++begin;
+                }
+                affEdges[edge].push_back(gEdge);
+            }
+        }
+    }
+
+
+
+
+    /// \brief shortest path computer
+    template<class GRAPH,class WEIGHT_TYPE>
+    class ShortestPathDijkstra{
+    public:
+        typedef GRAPH Graph;
+
+        typedef typename Graph::Node Node;
+        typedef typename Graph::NodeIt NodeIt;
+        typedef typename Graph::Edge Edge;
+        typedef typename Graph::OutArcIt OutArcIt;
+
+        typedef WEIGHT_TYPE WeightType;
+        typedef ChangeablePriorityQueue<WeightType>           PqType;
+        typedef typename Graph:: template NodeMap<Node>       PredecessorsMap;
+        typedef typename Graph:: template NodeMap<WeightType> DistanceMap;
+        typedef ArrayVector<Node>                             DiscoveryOrder;
+            
+        /// \ brief constructor from graph
+        ShortestPathDijkstra(const Graph & g)
+        :   graph_(g),
+            pq_(g.maxNodeId()+1),
+            predMap_(g),
+            distMap_(g)
+        {
+        }
+
+        /// \brief run shortest path given edge weights
+        ///
+        /// \param weights : edge weights encoding the distance between adjacent nodes (must be non-negative) 
+        /// \param source  : source node where shortest path should start
+        /// \param target  : target node where shortest path should stop. If target is not given
+        ///                  or <tt>INVALID</tt>, the shortest path from source to all reachable nodes is computed
+        /// \param maxDistance  : path search is terminated when the path length exceeds <tt>maxDistance</tt>
+        ///
+        /// When a valid \a target is unreachable from \a source (either because the graph is disconnected 
+        /// or \a maxDistance is exceeded), it is set to <tt>lemon::INVALID</tt>. In contrast, if \a target
+        /// was <tt>lemon::INVALID</tt> at the beginning, it will always be set to the last node 
+        /// visited in the search.
+        template<class WEIGHTS>
+        void run(const WEIGHTS & weights, const Node & source,
+                 const Node & target = lemon::INVALID, 
+                 WeightType maxDistance=NumericTraits<WeightType>::max())
+        {
+            this->initializeMaps(source);
+            runImpl(weights, target, maxDistance);
+        }
+
+        /// \brief run shortest path in a region of interest of a \ref GridGraph.
+        ///
+        /// \param start : first point in the desired ROI.
+        /// \param stop  : beyond the last point in the desired ROI (i.e. exclusive)
+        /// \param weights : edge weights encoding the distance between adjacent nodes (must be non-negative) 
+        /// \param source  : source node where shortest path should start
+        /// \param target  : target node where shortest path should stop. If target is not given
+        ///                  or <tt>INVALID</tt>, the shortest path from source to all reachable nodes is computed
+        /// \param maxDistance  : path search is terminated when the path length exceeds <tt>maxDistance</tt>
+        ///
+        /// This version of <tt>run()</tt> restricts the path search to the ROI <tt>[start, stop)</tt> and only
+        /// works for instances of \ref GridGraph. Otherwise, it is identical to the standard <tt>run()</tt> 
+        /// function.
+        template<class WEIGHTS>
+        void run(Node const & start, Node const & stop,
+                 const WEIGHTS & weights, const Node & source,
+                 const Node & target = lemon::INVALID, 
+                 WeightType maxDistance=NumericTraits<WeightType>::max())
+        {
+            vigra_precondition(allLessEqual(start, source) && allLess(source, stop),
+                "ShortestPathDijkstra::run(): source is not within ROI");
+            vigra_precondition(target == lemon::INVALID ||
+                               (allLessEqual(start, target) && allLess(target, stop)),
+                "ShortestPathDijkstra::run(): target is not within ROI");
+            this->initializeMaps(source, start, stop);
+            runImpl(weights, target, maxDistance);
+        }
+
+        /// \brief run shortest path again with given edge weights
+        ///
+        /// This only differs from standard <tt>run()</tt> by initialization: Instead of resetting 
+        /// the entire graph, this only resets the nodes that have been visited in the 
+        /// previous run, i.e. the contents of the array <tt>discoveryOrder()</tt>.
+        /// This will be much faster if only a small fraction of the nodes has to be reset.
+        template<class WEIGHTS>
+        void reRun(const WEIGHTS & weights, const Node & source,
+                   const Node & target = lemon::INVALID, 
+                   WeightType maxDistance=NumericTraits<WeightType>::max())
+        {
+            this->reInitializeMaps(source);
+            runImpl(weights, target, maxDistance);
+        }
+
+        /// \brief run shortest path with given edge weights from multiple sources.
+        ///
+        /// This is otherwise identical to standard <tt>run()</tt>, except that 
+        /// <tt>source()</tt> returns <tt>lemon::INVALID</tt> after path search finishes.
+        template<class WEIGHTS, class ITER>
+        void 
+        runMultiSource(const WEIGHTS & weights, ITER source_begin, ITER source_end,
+                 const Node & target = lemon::INVALID, 
+                 WeightType maxDistance=NumericTraits<WeightType>::max())
+        {
+            this->initializeMapsMultiSource(source_begin, source_end);
+            runImpl(weights, target, maxDistance);
+        }
+
+
+        /// \brief run shortest path with given edge weights from multiple sources.
+        ///
+        /// This is otherwise identical to standard <tt>run()</tt>, except that 
+        /// <tt>source()</tt> returns <tt>lemon::INVALID</tt> after path search finishes.
+        template<class EFGE_WEIGHTS,class NODE_WEIGHTS, class ITER>
+        void 
+        runMultiSource(
+            const EFGE_WEIGHTS & edgeWeights, 
+            const NODE_WEIGHTS & nodeWeights,
+            ITER source_begin, 
+            ITER source_end,
+            const Node & target = lemon::INVALID, 
+            WeightType maxDistance = NumericTraits<WeightType>::max())
+        {
+            this->initializeMapsMultiSource(source_begin, source_end);
+            runImplWithNodeWeights(edgeWeights, nodeWeights, target, maxDistance);
+        }
+
+        /// \brief get the graph
+        const Graph & graph()const{
+            return graph_;
+        }
+        /// \brief get the source node
+        const Node & source()const{
+            return source_;
+        }
+        /// \brief get the target node
+        const Node & target()const{
+            return target_;
+        }
+
+        /// \brief check if explicit target is given
+        bool hasTarget()const{
+            return target_!=lemon::INVALID;
+        }
+
+        /// \brief get an array with all visited nodes, sorted by distance from source
+        const DiscoveryOrder & discoveryOrder() const{
+            return discoveryOrder_;
+        }
+
+        /// \brief get the predecessors node map (after a call of run)
+        const PredecessorsMap & predecessors()const{
+            return predMap_;
+        }
+        
+        /// \brief get the distances node map (after a call of run)
+        const DistanceMap & distances()const{
+            return distMap_;
+        }
+        
+        /// \brief get the distance to a rarget node (after a call of run)
+        WeightType distance(const Node & target)const{
+            return distMap_[target];
+        }
+
+
+    private:
+
+        template<class WEIGHTS>
+        void runImpl(const WEIGHTS & weights,
+                     const Node & target = lemon::INVALID, 
+                     WeightType maxDistance=NumericTraits<WeightType>::max())
+        {
+            ZeroNodeMap<Graph, WEIGHT_TYPE> zeroNodeMap;
+            this->runImplWithNodeWeights(weights,zeroNodeMap, target, maxDistance);
+        }
+
+
+        template<class EDGE_WEIGHTS, class NODE_WEIGHTS>
+        void runImplWithNodeWeights(
+            const EDGE_WEIGHTS & edgeWeights,
+            const NODE_WEIGHTS & nodeWeights,
+            const Node & target = lemon::INVALID, 
+            WeightType maxDistance=NumericTraits<WeightType>::max())
+        {
+            target_ = lemon::INVALID;
+            while(!pq_.empty() ){ //&& !finished){
+                const Node topNode(graph_.nodeFromId(pq_.top()));
+                if(distMap_[topNode] > maxDistance)
+                    break; // distance threshold exceeded
+                pq_.pop();
+                discoveryOrder_.push_back(topNode);
+                if(topNode == target)
+                    break;
+                // loop over all neigbours
+                for(OutArcIt outArcIt(graph_,topNode);outArcIt!=lemon::INVALID;++outArcIt){
+                    const Node otherNode = graph_.target(*outArcIt);
+                    const size_t otherNodeId = graph_.id(otherNode);
+                    const WeightType otherNodeWeight = nodeWeights[otherNode];
+                    if(pq_.contains(otherNodeId)){
+                        const Edge edge(*outArcIt);
+                        const WeightType currentDist     = distMap_[otherNode];
+                        const WeightType alternativeDist = distMap_[topNode]+edgeWeights[edge]+otherNodeWeight;
+                        if(alternativeDist<currentDist){
+                            pq_.push(otherNodeId,alternativeDist);
+                            distMap_[otherNode]=alternativeDist;
+                            predMap_[otherNode]=topNode;
+                        }
+                    }
+                    else if(predMap_[otherNode]==lemon::INVALID){
+                        const Edge edge(*outArcIt);
+                        const WeightType initialDist = distMap_[topNode]+edgeWeights[edge]+otherNodeWeight;
+                        if(initialDist<=maxDistance)
+                        {
+                            pq_.push(otherNodeId,initialDist);
+                            distMap_[otherNode]=initialDist;
+                            predMap_[otherNode]=topNode;
+                        }
+                    }
+                }
+            }
+            while(!pq_.empty() ){
+                const Node topNode(graph_.nodeFromId(pq_.top()));
+                predMap_[topNode]=lemon::INVALID;
+                pq_.pop();
+            }
+            if(target == lemon::INVALID || discoveryOrder_.back() == target)
+                target_ = discoveryOrder_.back(); // Means that target was reached. If, to the contrary, target 
+                                                  // was unreachable within maxDistance, target_ remains INVALID.
+        }
+
+        void initializeMaps(Node const & source){
+            for(NodeIt n(graph_); n!=lemon::INVALID; ++n){
+                const Node node(*n);
+                predMap_[node]=lemon::INVALID;
+            }
+            distMap_[source]=static_cast<WeightType>(0.0);
+            predMap_[source]=source;
+            discoveryOrder_.clear();
+            pq_.push(graph_.id(source),0.0);
+            source_=source;
+        }
+
+        void initializeMaps(Node const & source,
+                            Node const & start, Node const & stop)
+        {
+            Node left_border  = min(start, Node(1)),
+                 right_border = min(predMap_.shape()-stop, Node(1)),
+                 DONT_TOUCH   = Node(lemon::INVALID) - Node(1);
+            
+            initMultiArrayBorder(predMap_.subarray(start-left_border, stop+right_border),
+                                 left_border, right_border, DONT_TOUCH);
+            predMap_.subarray(start, stop) = lemon::INVALID;
+            predMap_[source]=source;
+            
+            distMap_[source]=static_cast<WeightType>(0.0);
+            discoveryOrder_.clear();
+            pq_.push(graph_.id(source),0.0);
+            source_=source;
+        }
+
+        template <class ITER>
+        void initializeMapsMultiSource(ITER source, ITER source_end){
+            for(NodeIt n(graph_); n!=lemon::INVALID; ++n){
+                const Node node(*n);
+                predMap_[node]=lemon::INVALID;
+            }
+            discoveryOrder_.clear();
+            for( ; source != source_end; ++source)
+            {
+                distMap_[*source]=static_cast<WeightType>(0.0);
+                predMap_[*source]=*source;
+                pq_.push(graph_.id(*source),0.0);
+            }
+            source_=lemon::INVALID;
+        }
+
+        void reInitializeMaps(Node const & source){
+            for(unsigned int n=0; n<discoveryOrder_.size(); ++n){
+                predMap_[discoveryOrder_[n]]=lemon::INVALID;
+            }
+            distMap_[source]=static_cast<WeightType>(0.0);
+            predMap_[source]=source;
+            discoveryOrder_.clear();
+            pq_.push(graph_.id(source),0.0);
+            source_=source;
+        }
+
+        const Graph  & graph_;
+        PqType  pq_;
+        PredecessorsMap predMap_;
+        DistanceMap     distMap_;
+        DiscoveryOrder  discoveryOrder_;
+
+        Node source_;
+        Node target_;
+    };
+
+    /// \brief get the length in node units of a path
+    template<class NODE,class PREDECESSORS>
+    size_t pathLength(
+        const NODE source,
+        const NODE target,
+        const PREDECESSORS & predecessors
+    ){
+        if(predecessors[target]==lemon::INVALID)
+            return 0;
+        else{
+            NODE currentNode = target;
+            size_t length=1;
+            while(currentNode!=source){
+                currentNode=predecessors[currentNode];
+                length+=1;
+            }
+            return length;
+        }
+    }
+
+    /// \brief Astar Shortest path search
+    template<class GRAPH,class WEIGHTS,class PREDECESSORS,class DISTANCE,class HEURSTIC>
+    void shortestPathAStar(
+        const GRAPH         &           graph,
+        const typename GRAPH::Node &    source,
+        const typename GRAPH::Node &    target,
+        const WEIGHTS       &           weights,
+        PREDECESSORS        &           predecessors,
+        DISTANCE            &           distance,
+        const HEURSTIC      &           heuristic
+    ){
+
+        typedef GRAPH                       Graph;
+        typedef typename Graph::Edge Edge;
+        typedef typename Graph::Node Node;
+        typedef typename Graph::NodeIt NodeIt;
+        typedef typename Graph::OutArcIt OutArcIt;
+        typedef typename DISTANCE::value_type    DistanceType;
+
+        typename  GRAPH:: template NodeMap<bool> closedSet(graph);
+        vigra::ChangeablePriorityQueue<typename WEIGHTS::value_type> estimatedDistanceOpenSet(graph.maxNodeId()+1);
+        // initialize
+        for(NodeIt n(graph);n!=lemon::INVALID;++n){
+            const Node node(*n);
+            closedSet[node]=false;
+            distance[node]=std::numeric_limits<DistanceType>::infinity();
+            predecessors[node]=lemon::INVALID;
+        }
+        // distance and estimated distance for start node
+        distance[source]=static_cast<DistanceType>(0.0);
+        estimatedDistanceOpenSet.push(graph.id(source),heuristic(source,target));
+
+        // while any nodes left in openSet
+        while(!estimatedDistanceOpenSet.empty()){
+
+            // get the node with the lpwest estimated distance in the open set
+            const Node current = graph.nodeFromId(estimatedDistanceOpenSet.top());
+
+            // reached target?
+            if(current==target)
+                break;
+
+            // remove current from openSet
+            // add current to closedSet
+            estimatedDistanceOpenSet.pop();
+            closedSet[current]=true;
+
+            // iterate over neigbours of current
+            for(OutArcIt outArcIt(graph,current);outArcIt!=lemon::INVALID;++outArcIt){
+
+                // get neigbour node and id
+                const Node neighbour = graph.target(*outArcIt);
+                const size_t neighbourId = graph.id(neighbour);
+
+                // if neighbour is not yet in closedSet
+                if(!closedSet[neighbour]){
+
+                    // get edge between current and neigbour
+                    const Edge edge(*outArcIt);
+
+                    // get tentative score
+                    const DistanceType tenativeScore = distance[current] + weights[edge];
+
+                    // neighbour NOT in openSet OR tentative score better than the current distance
+                    if(!estimatedDistanceOpenSet.contains(neighbourId) || tenativeScore < distance[neighbour] ){
+                        // set predecessors and distance
+                        predecessors[neighbour]=current;
+                        distance[neighbour]=tenativeScore;
+
+                        // update the estimated cost from neighbour to target
+                        // ( and neigbour will be (re)-added to openSet)
+                        estimatedDistanceOpenSet.push(neighbourId,distance[neighbour]+heuristic(neighbour,target));
+                    }
+                }
+            }
+        }
+    }
+    
+
+    template<
+    class GRAPH, 
+    class EDGE_WEIGHTS, 
+    class NODE_WEIGHTS,
+    class SEED_NODE_MAP,
+    class WEIGHT_TYPE
+    >
+    void shortestPathSegmentation(
+        const GRAPH & graph,
+        const EDGE_WEIGHTS & edgeWeights,
+        const NODE_WEIGHTS & nodeWeights,
+        SEED_NODE_MAP & seeds
+    ){
+
+        typedef GRAPH Graph;
+        typedef typename Graph::Node Node;
+        typedef typename Graph::NodeIt NodeIt;
+        typedef WEIGHT_TYPE WeightType;
+
+        // find seeds
+        std::vector<Node> seededNodes;
+        for(NodeIt n(graph);n!=lemon::INVALID;++n){
+            const Node node(*n);
+            // not a seed
+            if(seeds[node]!=0){
+                seededNodes.push_back(node);
+            }
+        }
+
+        // do shortest path
+        typedef ShortestPathDijkstra<Graph, WeightType> Sp;
+        typedef typename Sp::PredecessorsMap PredecessorsMap;
+        Sp sp(graph);
+        sp.runMultiSource(edgeWeights, nodeWeights, seededNodes.begin(), seededNodes.end());
+        const PredecessorsMap & predMap = sp.predecessors();
+        // do the labeling
+        for(NodeIt n(graph);n!=lemon::INVALID;++n){
+            Node node(*n);
+            if(seeds[node]==0){
+                int label = 0 ;
+                Node pred=predMap[node];
+                while(seeds[pred]==0){
+                    pred=predMap[pred];
+                }
+                seeds[node]=seeds[pred];
+            }
+        }
+    }
+
+    namespace detail_watersheds_segmentation{
+
+    struct RawPriorityFunctor{
+        template<class L, class T>
+        T operator()(const L label,const T  priority)const{
+            return priority;
+        }
+    };
+
+
+
+    template<class PRIORITY_TYPE,class LABEL_TYPE>
+    struct CarvingFunctor{
+        CarvingFunctor(const LABEL_TYPE backgroundLabel,
+                       const PRIORITY_TYPE & factor,
+                       const PRIORITY_TYPE & noPriorBelow
+        )
+        :   backgroundLabel_(backgroundLabel),
+            factor_(factor),
+            noPriorBelow_(noPriorBelow){
+        }
+        PRIORITY_TYPE operator()(const LABEL_TYPE label,const PRIORITY_TYPE  priority)const{
+            if(priority>=noPriorBelow_)
+                return (label==backgroundLabel_ ? priority*factor_ : priority);
+            else{
+                return priority;
+            }
+        }
+        LABEL_TYPE     backgroundLabel_;
+        PRIORITY_TYPE  factor_;
+        PRIORITY_TYPE  noPriorBelow_;
+    };
+
+
+    template<
+        class GRAPH,
+        class EDGE_WEIGHTS,
+        class SEEDS,
+        class PRIORITY_MANIP_FUNCTOR,
+        class LABELS
+    >
+    void edgeWeightedWatershedsSegmentationImpl(
+        const GRAPH & g,
+        const EDGE_WEIGHTS      & edgeWeights,
+        const SEEDS             & seeds,
+        PRIORITY_MANIP_FUNCTOR  & priorManipFunctor,
+        LABELS                  & labels
+    ){  
+        typedef GRAPH Graph;
+        typedef typename Graph::Edge Edge;
+        typedef typename Graph::Node Node;
+        typedef typename Graph::NodeIt NodeIt;
+        typedef typename Graph::OutArcIt OutArcIt;
+
+        typedef typename EDGE_WEIGHTS::Value WeightType;
+        typedef typename LABELS::Value  LabelType;
+        //typedef typename Graph:: template EdgeMap<bool>    EdgeBoolMap;
+        typedef PriorityQueue<Edge,WeightType,true> PQ;
+
+        PQ pq;
+        //EdgeBoolMap inPQ(g);
+        copyNodeMap(g,seeds,labels);
+        //fillEdgeMap(g,inPQ,false);
+
+
+        // put edges from nodes with seed on pq
+        for(NodeIt n(g);n!=lemon::INVALID;++n){
+            const Node node(*n);
+            if(labels[node]!=static_cast<LabelType>(0)){
+                for(OutArcIt a(g,node);a!=lemon::INVALID;++a){
+                    const Edge edge(*a);
+                    const Node neigbour=g.target(*a);
+                    //std::cout<<"n- node "<<g.id(neigbour)<<"\n";
+                    if(labels[neigbour]==static_cast<LabelType>(0)){
+                        const WeightType priority = priorManipFunctor(labels[node],edgeWeights[edge]);
+                        pq.push(edge,priority);
+                        //inPQ[edge]=true;
+                    }
+                }
+            }
+        }
+
+
+        while(!pq.empty()){
+
+            const Edge edge = pq.top();
+            pq.pop();
+
+            const Node u = g.u(edge);
+            const Node v = g.v(edge);
+            const LabelType lU = labels[u];
+            const LabelType lV = labels[v];
+
+
+            if(lU==0 && lV==0){
+                throw std::runtime_error("both have no labels");
+            }
+            else if(lU!=0 && lV!=0){
+                // nothing to do
+            }
+            else{
+
+                const Node unlabeledNode = lU==0 ? u : v;
+                const LabelType label = lU==0 ? lV : lU;
+
+                // assign label to unlabeled node
+                labels[unlabeledNode] = label;
+
+                // iterate over the nodes edges
+                for(OutArcIt a(g,unlabeledNode);a!=lemon::INVALID;++a){
+                    const Edge otherEdge(*a);
+                    const Node targetNode=g.target(*a);
+                    if(labels[targetNode] == 0){
+                    //if(inPQ[otherEdge] == false && labels[targetNode] == 0){
+                        const WeightType priority = priorManipFunctor(label,edgeWeights[otherEdge]);
+                        pq.push(otherEdge,priority);
+                       // inPQ[otherEdge]=true;
+                    }
+                }
+            }
+
+        }
+
+    }
+
+    } // end namespace detail_watersheds_segmentation
+
+
+    /// \brief edge weighted watersheds Segmentataion
+    /// 
+    /// \param g: input graph
+    /// \param edgeWeights : edge weights / edge indicator
+    /// \param seeds : seed must be non empty!
+    /// \param[out] labels : resulting  nodeLabeling (not necessarily dense)
+    template<class GRAPH,class EDGE_WEIGHTS,class SEEDS,class LABELS>
+    void edgeWeightedWatershedsSegmentation(
+        const GRAPH & g,
+        const EDGE_WEIGHTS & edgeWeights,
+        const SEEDS        & seeds,
+        LABELS             & labels
+    ){  
+        detail_watersheds_segmentation::RawPriorityFunctor fPriority;
+        detail_watersheds_segmentation::edgeWeightedWatershedsSegmentationImpl(g,edgeWeights,seeds,fPriority,labels);
+    }   
+    
+
+    /// \brief edge weighted watersheds Segmentataion
+    /// 
+    /// \param g: input graph
+    /// \param edgeWeights : edge weights / edge indicator
+    /// \param seeds : seed must be non empty!
+    /// \param backgroundLabel : which label is background
+    /// \param backgroundBias  : bias for background
+    /// \param noPriorBelow  : don't bias the background if edge indicator is below this value
+    /// \param[out] labels : resulting  nodeLabeling (not necessarily dense)
+    template<class GRAPH,class EDGE_WEIGHTS,class SEEDS,class LABELS>
+    void carvingSegmentation(
+        const GRAPH                         & g,
+        const EDGE_WEIGHTS                  & edgeWeights,
+        const SEEDS                         & seeds,
+        const typename LABELS::Value        backgroundLabel,
+        const typename EDGE_WEIGHTS::Value  backgroundBias,
+        const typename EDGE_WEIGHTS::Value  noPriorBelow,
+        LABELS                      & labels
+    ){
+        typedef typename EDGE_WEIGHTS::Value WeightType;
+        typedef typename LABELS::Value       LabelType;
+        detail_watersheds_segmentation::CarvingFunctor<WeightType,LabelType> fPriority(backgroundLabel,backgroundBias, noPriorBelow);
+        detail_watersheds_segmentation::edgeWeightedWatershedsSegmentationImpl(g,edgeWeights,seeds,fPriority,labels);
+    }
+
+    /// \brief edge weighted watersheds Segmentataion
+    /// 
+    /// \param graph: input graph
+    /// \param edgeWeights : edge weights / edge indicator
+    /// \param nodeSizes : size of each node
+    /// \param k : free parameter of felzenszwalb algorithm
+    /// \param[out] nodeLabeling :  nodeLabeling (not necessarily dense)
+    /// \param nodeNumStopCond      : optional stopping condition
+    template< class GRAPH , class EDGE_WEIGHTS, class NODE_SIZE,class NODE_LABEL_MAP>
+    void felzenszwalbSegmentation(
+        const GRAPH &         graph,
+        const EDGE_WEIGHTS &  edgeWeights,
+        const NODE_SIZE    &  nodeSizes,
+        float           k,
+        NODE_LABEL_MAP     &  nodeLabeling,
+        const int             nodeNumStopCond = -1
+    ){
+        typedef GRAPH Graph;
+        typedef typename Graph::Edge Edge;
+        typedef typename Graph::Node Node;
+
+        typedef typename EDGE_WEIGHTS::Value WeightType;
+        typedef typename EDGE_WEIGHTS::Value NodeSizeType;
+        typedef typename Graph:: template NodeMap<WeightType>   NodeIntDiffMap;
+        typedef typename Graph:: template NodeMap<NodeSizeType> NodeSizeAccMap;
+
+        // initalize node size map  and internal diff map
+        NodeIntDiffMap internalDiff(graph);
+        NodeSizeAccMap nodeSizeAcc(graph);  
+        copyNodeMap(graph,nodeSizes,nodeSizeAcc);
+        fillNodeMap(graph,internalDiff,static_cast<WeightType>(0.0));
+
+
+
+        // initlaize internal node diff map
+
+        // sort the edges by their weights
+        std::vector<Edge> sortedEdges;
+        std::less<WeightType> comperator;
+        edgeSort(graph,edgeWeights,comperator,sortedEdges);
+
+        // make the ufd
+        UnionFindArray<UInt64> ufdArray(graph.maxNodeId()+1);
+
+
+        size_t nodeNum = graph.nodeNum();   
+
+
+        while(true){
+            // iterate over edges is the sorted order
+            for(size_t i=0;i<sortedEdges.size();++i){
+                const Edge e  = sortedEdges[i];
+                const size_t rui = ufdArray.findIndex(graph.id(graph.u(e)));
+                const size_t rvi = ufdArray.findIndex(graph.id(graph.v(e)));
+                const Node   ru  = graph.nodeFromId(rui);
+                const Node   rv  = graph.nodeFromId(rvi);
+                if(rui!=rvi){
+
+                    //check if to merge or not ?
+                    const WeightType   w         = edgeWeights[e];
+                    const NodeSizeType sizeRu    = nodeSizeAcc[ru];
+                    const NodeSizeType sizeRv    = nodeSizeAcc[rv];
+                    const WeightType tauRu       = static_cast<WeightType>(k)/static_cast<WeightType>(sizeRu);
+                    const WeightType tauRv       = static_cast<WeightType>(k)/static_cast<WeightType>(sizeRv);
+                    const WeightType minIntDiff  = std::min(internalDiff[ru]+tauRu,internalDiff[rv]+tauRv);
+                    if(w<=minIntDiff){
+                        // do merge
+                        ufdArray.makeUnion(rui,rvi);
+                        --nodeNum;
+                        // update size and internal difference
+                        const size_t newRepId = ufdArray.findIndex(rui);
+                        const Node newRepNode = graph.nodeFromId(newRepId);
+                        internalDiff[newRepNode]=w;
+                        nodeSizeAcc[newRepNode] = sizeRu+sizeRv;
+                    }
+                }
+                if(nodeNum==nodeNumStopCond){
+                    break;
+                }
+            }
+            if(nodeNumStopCond==-1){
+                break;
+            }
+            else{
+                if(nodeNum>nodeNumStopCond){
+                    k *= 1.2f;
+                }
+                else{
+                    break;
+                }
+            }
+        }
+        ufdArray.makeContiguous();
+        for(typename  GRAPH::NodeIt n(graph);n!=lemon::INVALID;++n){
+            const Node node(*n);
+            nodeLabeling[node]=ufdArray.findLabel(graph.id(node));
+        }
+    } 
+
+
+
+
+    namespace detail_graph_smoothing{
+
+    template<
+        class GRAPH, 
+        class NODE_FEATURES_IN,
+        class EDGE_WEIGHTS,
+        class WEIGHTS_TO_SMOOTH_FACTOR,
+        class NODE_FEATURES_OUT
+    >
+    void graphSmoothingImpl(
+        const GRAPH & g,
+        const NODE_FEATURES_IN   & nodeFeaturesIn,
+        const EDGE_WEIGHTS       & edgeWeights,
+        WEIGHTS_TO_SMOOTH_FACTOR & weightsToSmoothFactor,
+        NODE_FEATURES_OUT        & nodeFeaturesOut
+
+    ){
+        typedef GRAPH Graph;
+        typedef typename Graph::Edge Edge;
+        typedef typename Graph::Node Node;
+        typedef typename Graph::NodeIt NodeIt;
+        typedef typename Graph::OutArcIt OutArcIt;
+
+        typedef typename NODE_FEATURES_IN::Value          NodeFeatureInValue;
+        typedef typename NODE_FEATURES_OUT::Reference     NodeFeatureOutRef;
+        typedef typename EDGE_WEIGHTS::ConstReference SmoothFactorType;
+
+
+        //fillNodeMap(g, nodeFeaturesOut, typename NODE_FEATURES_OUT::value_type(0.0));
+
+        for(NodeIt n(g);n!=lemon::INVALID;++n){
+
+            const Node node(*n);
+
+            NodeFeatureInValue    featIn  = nodeFeaturesIn[node];
+            NodeFeatureOutRef     featOut = nodeFeaturesOut[node];
+
+            featOut=0;
+            float weightSum = 0.0;
+            size_t degree    = 0;
+            for(OutArcIt a(g,node);a!=lemon::INVALID;++a){
+                const Edge edge(*a);
+                const Node neigbour(g.target(*a));
+                SmoothFactorType smoothFactor= weightsToSmoothFactor(edgeWeights[edge]);
+
+                NodeFeatureInValue neighbourFeat = nodeFeaturesIn[neigbour];
+                neighbourFeat*=smoothFactor;
+                if(degree==0)
+                    featOut = neighbourFeat;
+                else
+                    featOut += neighbourFeat;
+                weightSum+=smoothFactor;
+                ++degree;
+            }
+            // fixme..set me to right type 
+            featIn*=static_cast<float>(degree);
+            weightSum+=static_cast<float>(degree);
+            featOut+=featIn;
+            featOut/=weightSum;
+        }
+    }
+
+    template<class T>
+    struct ExpSmoothFactor{
+        ExpSmoothFactor(const T lambda,const T edgeThreshold,const T scale)
+        :   lambda_(lambda),
+            edgeThreshold_(edgeThreshold),
+            scale_(scale){
+        }
+        T operator()(const T weight){
+            return weight> edgeThreshold_ ? 0 :  std::exp(-1.0*lambda_*weight)*scale_;
+        }
+        T lambda_;
+        T edgeThreshold_;
+        T scale_;
+    };
+
+    } // namespace detail_graph_smoothing
+
+
+    /// \brief smooth node features of a graph
+    ///
+    /// \param g               : input graph
+    /// \param nodeFeaturesIn  : input node features which should be smoothed       
+    /// \param edgeIndicator   : edge indicator to indicate over which edges one should smooth        
+    /// \param lambda          : scale edge indicator by lambda before taking negative exponent
+    /// \param edgeThreshold   : edge threshold
+    /// \param scale           : how much smoothing should be applied
+    /// \param[out] nodeFeaturesOut : smoothed node features
+    template<class GRAPH, class NODE_FEATURES_IN,class EDGE_INDICATOR,class NODE_FEATURES_OUT>
+    void graphSmoothing(
+        const GRAPH & g,
+        const NODE_FEATURES_IN  & nodeFeaturesIn,
+        const EDGE_INDICATOR    & edgeIndicator,
+        const float lambda,
+        const float edgeThreshold,
+        const float scale,
+        NODE_FEATURES_OUT       & nodeFeaturesOut
+    ){
+        detail_graph_smoothing::ExpSmoothFactor<float> functor(lambda,edgeThreshold,scale);
+        detail_graph_smoothing::graphSmoothingImpl(g,nodeFeaturesIn,edgeIndicator,functor,nodeFeaturesOut);
+    }
+
+    /// \brief smooth node features of a graph
+    ///
+    /// \param g               : input graph
+    /// \param nodeFeaturesIn  : input node features which should be smoothed       
+    /// \param edgeIndicator   : edge indicator to indicate over which edges one should smooth        
+    /// \param lambda          : scale edge indicator by lambda before taking negative exponent
+    /// \param edgeThreshold   : edge threshold
+    /// \param scale           : how much smoothing should be applied
+    /// \param iterations      : how often should this algorithm be called recursively
+    /// \param[out] nodeFeaturesBuffer : preallocated(!) buffer to store node features temp.
+    /// \param[out] nodeFeaturesOut : smoothed node features
+    template<class GRAPH, class NODE_FEATURES_IN,class EDGE_INDICATOR,class NODE_FEATURES_OUT>
+    void recursiveGraphSmoothing(
+        const GRAPH & g,
+        const NODE_FEATURES_IN   & nodeFeaturesIn,
+        const EDGE_INDICATOR     & edgeIndicator,
+        const float lambda,
+        const float edgeThreshold,
+        const float scale,
+        size_t                    iterations,
+        NODE_FEATURES_OUT       & nodeFeaturesBuffer,
+        NODE_FEATURES_OUT       & nodeFeaturesOut
+    ){
+
+        iterations = std::max(size_t(1),iterations);
+        // initial run
+        graphSmoothing(g,nodeFeaturesIn,edgeIndicator,lambda,edgeThreshold,scale,nodeFeaturesOut);
+        iterations -=1;
+
+        bool outAsIn=true;
+        for(size_t i=0;i<iterations;++i){
+            if(outAsIn){
+                graphSmoothing(g,nodeFeaturesOut,edgeIndicator,lambda,edgeThreshold,scale,nodeFeaturesBuffer);
+                outAsIn=false;
+            }
+            else{
+                graphSmoothing(g,nodeFeaturesBuffer,edgeIndicator,lambda,edgeThreshold,scale,nodeFeaturesOut);
+                outAsIn=true;
+            }
+        }
+        if(!outAsIn){
+            copyNodeMap(g,nodeFeaturesBuffer,nodeFeaturesOut);
+        }
+    }
+
+
+    template<class GRAPH, class NODE_MAP, class EDGE_MAP>
+    void nodeGtToEdgeGt(
+        const GRAPH & g,
+        const NODE_MAP & nodeGt,
+        const Int64 ignoreLabel,
+        EDGE_MAP & edgeGt
+    ){
+        typedef typename  GRAPH::Node Node;
+        typedef typename  GRAPH::EdgeIt EdgeIt;
+        typedef typename  GRAPH::Edge Edge;
+
+        for(EdgeIt edgeIt(g); edgeIt!=lemon::INVALID; ++edgeIt){
+            const Edge edge(*edgeIt);
+            const Node u = g.u(edge);
+            const Node v = g.v(edge);
+
+            const Int64 lU = static_cast<Int64>(nodeGt[u]);
+            const Int64 lV = static_cast<Int64>(nodeGt[v]);
+
+            if(ignoreLabel==-1 || (lU!=ignoreLabel || lV!=ignoreLabel)){
+                edgeGt[edge] = lU == lV ? 0 : 1;
+            }
+            else{
+                edgeGt[edge] = 2;
+            }
+        }
+    }
+
+
+
+
+
+
+    /// project ground truth from a base graph, to a region adjacency graph.
+    ///     
+    ///
+    ///
+    ///
+    template<class RAG, class BASE_GRAPH, class BASE_GRAPH_RAG_LABELS,  
+             class BASE_GRAPH_GT,  class RAG_GT, class RAG_GT_QT>
+    void projectGroundTruth(
+        const RAG                   & rag,
+        const BASE_GRAPH            & baseGraph,
+        const BASE_GRAPH_RAG_LABELS & baseGraphRagLabels,
+        const BASE_GRAPH_GT         & baseGraphGt,
+        RAG_GT                      & ragGt,
+        RAG_GT_QT                   & ragGtQt
+    ){
+        typedef typename BASE_GRAPH::Node BaseGraphNode;
+        typedef typename BASE_GRAPH::NodeIt BaseGraphNodeIt;
+        typedef typename RAG::NodeIt RagNodeIt;
+        typedef typename RAG::Node RagNode;
+        typedef typename BASE_GRAPH_RAG_LABELS::Value BaseRagLabelType;
+        typedef typename BASE_GRAPH_GT::Value GtLabelType;
+        typedef typename RAG_GT::Value RagGtLabelType;
+
+        // overlap map
+        typedef std::map<GtLabelType,UInt32> MapType;
+        typedef typename MapType::const_iterator MapIter;
+        typedef typename  RAG:: template NodeMap<MapType> Overlap;
+        Overlap overlap(rag);
+        
+        size_t i=0;
+        //::cout<<"\n"; 
+        for(BaseGraphNodeIt baseNodeIter(baseGraph); baseNodeIter!=lemon::INVALID; ++baseNodeIter , ++i ){
+
+            //if (i%2000 == 0){
+            //    std::cout<<"\r"<<std::setw(10)<< float(i)/float(baseGraph.nodeNum())<<std::flush;
+            //}
+
+            const BaseGraphNode baseNode = *baseNodeIter;
+
+            // get gt label
+            const GtLabelType gtLabel = baseGraphGt[baseNode];
+
+            // get the label which generated rag 
+            // (node mapping from  bg-node to rag-node-id)
+            const BaseRagLabelType bgRagLabel = baseGraphRagLabels[baseNode];
+            const RagNode  ragNode = rag.nodeFromId(bgRagLabel);
+
+            // fill overlap 
+            overlap[ragNode][gtLabel]+=1;
+        }
+        //std::cout<<"\n"; 
+        // select label with max overlap
+        for(RagNodeIt ragNodeIter(rag); ragNodeIter!=lemon::INVALID; ++ragNodeIter ){
+            const RagNode  ragNode = *ragNodeIter;
+            const MapType olMap = overlap[ragNode];
+            UInt32 olSize=0;
+            RagGtLabelType bestLabel = 0;
+            for(MapIter  olIter = olMap.begin(); olIter!=olMap.end(); ++olIter ){
+                if(olIter->second > olSize){
+                    olSize = olIter->second;
+                    bestLabel = olIter->first;
+                }
+            }
+            ragGt[ragNode]=bestLabel;
+        }
+    }
+
+
+
+    /// \brief Find indices of points on the edges
+    ///
+    /// \param rag : Region adjacency graph of the labels array
+    /// \param graph : Graph of labels array
+    /// \param affiliatedEdges : The affiliated edges of the region adjacency graph
+    /// \param labelsArray : The label image
+    /// \param node : The node (of the region adjacency graph), whose edges shall be found
+    template<class RAGGRAPH, class GRAPH, class RAGEDGES, unsigned int N, class T>
+    MultiArray<2, MultiArrayIndex> ragFindEdges(
+            const RAGGRAPH & rag,
+            const GRAPH & graph,
+            const RAGEDGES & affiliatedEdges,
+            MultiArrayView<N, T> labelsArray,
+            const typename RAGGRAPH::Node & node
+    ){
+        typedef typename GRAPH::Node Node;
+        typedef typename GRAPH::Edge Edge;
+        typedef typename RAGGRAPH::OutArcIt RagOutArcIt;
+        typedef typename RAGGRAPH::Edge RagEdge;
+        typedef typename GraphDescriptorToMultiArrayIndex<GRAPH>::IntrinsicNodeMapShape NodeCoordinate;
+
+        T nodeLabel = rag.id(node);
+
+        // Find edges and write them into a set.
+        std::set< NodeCoordinate > edgeCoordinates;
+        for (RagOutArcIt iter(rag, node); iter != lemon::INVALID; ++iter)
+        {
+            const RagEdge ragEdge(*iter);
+            const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+            for (int i=0; i<affEdges.size(); ++i)
+            {
+                Node u = graph.u(affEdges[i]);
+                Node v = graph.v(affEdges[i]);
+                T uLabel = labelsArray[u];
+                T vLabel = labelsArray[v];
+
+                NodeCoordinate coords;
+                if (uLabel == nodeLabel)
+                {
+                    coords = GraphDescriptorToMultiArrayIndex<GRAPH>::intrinsicNodeCoordinate(graph, u);
+                }
+                else if (vLabel == nodeLabel)
+                {
+                    coords = GraphDescriptorToMultiArrayIndex<GRAPH>::intrinsicNodeCoordinate(graph, v);
+                }
+                else
+                {
+                    vigra_precondition(false, "You should not come to this part of the code.");
+                }
+                edgeCoordinates.insert(coords);
+            }
+        }
+
+        // Fill the return array.
+        MultiArray<2, MultiArrayIndex> edgePoints(Shape2(edgeCoordinates.size(), N));
+        edgePoints.init(0);
+        int next = 0;
+        typedef typename std::set< NodeCoordinate >::iterator setIter;
+        for (setIter iter = edgeCoordinates.begin(); iter!=edgeCoordinates.end(); ++iter)
+        {
+            NodeCoordinate coords = *iter;
+            for (int k=0; k<coords.size(); ++k)
+            {
+                edgePoints(next, k) = coords[k];
+            }
+            next++;
+        }
+        return edgePoints;
+    }
+    /// \brief create edge weights from node weights
+    ///
+    /// \param g : input graph
+    /// \param nodeWeights : node property map holding node weights
+    /// \param[out] edgeWeights : resulting edge weights
+    /// \param euclidean : if 'true', multiply the computed weights with the Euclidean
+    ///                    distance between the edge's end nodes (default: 'false')
+    /// \param func : binary function that computes the edge weight from the 
+    ///               weights of the edge's end nodes (default: take the average)
+    template<unsigned int N, class DirectedTag,
+             class NODEMAP, class EDGEMAP, class FUNCTOR>
+    void 
+    edgeWeightsFromNodeWeights(
+            const GridGraph<N, DirectedTag> & g,
+            const NODEMAP  & nodeWeights,
+            EDGEMAP & edgeWeights,
+            bool euclidean,
+            FUNCTOR const & func)
+    {
+        typedef GridGraph<N, DirectedTag> Graph;
+        typedef typename Graph::Edge Edge;
+        typedef typename Graph::EdgeIt EdgeIt;
+        typedef typename MultiArrayShape<N>::type CoordType;
+
+        vigra_precondition(nodeWeights.shape() == g.shape(), 
+             "edgeWeightsFromNodeWeights(): shape mismatch between graph and nodeWeights.");
+        
+        for (EdgeIt iter(g); iter!=lemon::INVALID; ++iter)
+        {
+            const Edge edge(*iter);
+            const CoordType uCoord(g.u(edge));
+            const CoordType vCoord(g.v(edge));
+            if (euclidean)
+            {
+                edgeWeights[edge] = norm(uCoord-vCoord) * func(nodeWeights[uCoord], nodeWeights[vCoord]);
+            }
+            else
+            {
+                edgeWeights[edge] = func(nodeWeights[uCoord], nodeWeights[vCoord]);
+            }
+        }
+    }
+
+    template<unsigned int N, class DirectedTag,
+             class NODEMAP, class EDGEMAP>
+    inline void 
+    edgeWeightsFromNodeWeights(
+            const GridGraph<N, DirectedTag> & g,
+            const NODEMAP  & nodeWeights,
+            EDGEMAP & edgeWeights,
+            bool euclidean=false)
+    {
+        using namespace vigra::functor;
+        edgeWeightsFromNodeWeights(g, nodeWeights, edgeWeights, euclidean, Param(0.5)*(Arg1()+Arg2()));
+    }
+    
+    
+    /// \brief create edge weights from an interpolated image
+    ///
+    /// \param g : input graph
+    /// \param interpolatedImage : interpolated image
+    /// \param[out] edgeWeights : edge weights
+    /// \param euclidean : if 'true', multiply the weights with the Euclidean
+    ///                    distance between the edge's end nodes (default: 'false')
+    /// 
+    /// For each edge, the function reads the weight from <tt>interpolatedImage[u+v]</tt>,
+    /// where <tt>u</tt> and <tt>v</tt> are the coordinates of the edge's end points.
+    template<unsigned int N, class DirectedTag,
+            class T, class EDGEMAP>
+    void 
+    edgeWeightsFromInterpolatedImage(
+            const GridGraph<N, DirectedTag> & g,
+            const MultiArrayView<N, T>  & interpolatedImage,
+            EDGEMAP & edgeWeights,
+            bool euclidean = false)
+    {
+        typedef GridGraph<N, DirectedTag> Graph;
+        typedef typename Graph::Edge Edge;
+        typedef typename Graph::EdgeIt EdgeIt;
+        typedef typename MultiArrayShape<N>::type CoordType;
+
+        vigra_precondition(interpolatedImage.shape() == 2*g.shape()-CoordType(1), 
+             "edgeWeightsFromInterpolatedImage(): interpolated shape must be shape*2-1");
+        
+        for (EdgeIt iter(g); iter!=lemon::INVALID; ++iter)
+        {
+            const Edge edge(*iter);
+            const CoordType uCoord(g.u(edge));
+            const CoordType vCoord(g.v(edge));
+            if (euclidean)
+            {
+                edgeWeights[edge] = norm(uCoord-vCoord) * interpolatedImage[uCoord+vCoord];
+            }
+            else
+            {
+                edgeWeights[edge] = interpolatedImage[uCoord+vCoord];
+            }
+        }
+    }
+
+    template<class GRAPH>
+    struct ThreeCycle{
+
+        typedef typename GRAPH::Node Node;
+
+        ThreeCycle(const Node & a, const Node & b, const Node c){
+            nodes_[0] = a;
+            nodes_[1] = b;
+            nodes_[2] = c;
+            std::sort(nodes_, nodes_+3);
+        }
+        bool operator < (const ThreeCycle & other)const{
+            if(nodes_[0] < other.nodes_[0]){
+                return true;
+            }
+            else if(nodes_[0] == other.nodes_[0]){
+                if(nodes_[1] < other.nodes_[1]){
+                    return true;
+                }
+                else if(nodes_[1] == other.nodes_[1]){
+                    if(nodes_[2] < other.nodes_[2]){
+                        return true;
+                    }
+                    else{
+                        return false;
+                    }
+                }
+                else{
+                    return false;
+                }
+            }
+            else{
+                return false;
+            }
+        }
+
+        Node nodes_[3];
+
+
+    };
+
+
+    template<class GRAPH>
+    void find3Cycles(
+        const GRAPH & g, 
+        MultiArray<1, TinyVector<Int32, 3> > & cyclesArray 
+    ){
+        typedef typename GRAPH::Node Node;
+        typedef typename GRAPH::Edge Edge;
+        typedef typename GRAPH::EdgeIt EdgeIt;
+        typedef typename GRAPH::OutArcIt OutArcIt;
+
+        typedef ThreeCycle<GRAPH> Cycle;
+
+        std::set< Cycle > cycles;
+        typedef typename std::set<Cycle>::const_iterator SetIter;
+        for (EdgeIt iter(g); iter!=lemon::INVALID; ++iter){
+            const Edge edge(*iter);
+            const Node u = g.u(edge);
+            const Node v = g.v(edge);
+
+            // find a node n which is connected to u and v
+            for(OutArcIt outArcIt(g,u); outArcIt!=lemon::INVALID;++outArcIt){
+                const Node w = g.target(*outArcIt);
+                if(w != v){
+                    const Edge e = g.findEdge(w,v);
+                    if(e != lemon::INVALID){
+                        // found cycle
+                        cycles.insert(Cycle(u, v, w));
+                    }
+                }
+            }
+        }
+        cyclesArray.reshape(TinyVector<UInt32,1>(cycles.size()));
+        UInt32 i=0;
+        for(SetIter iter=cycles.begin(); iter!=cycles.end(); ++iter){
+
+            const Cycle & c = *iter;
+            for(size_t j=0;j<3; ++j){
+                cyclesArray(i)[j] = g.id(c.nodes_[j]);
+            }
+            ++i;
+        }
+    }
+
+    template<class GRAPH>
+    void find3CyclesEdges(
+        const GRAPH & g, 
+        MultiArray<1, TinyVector<Int32, 3> > & cyclesArray 
+    ){
+        typedef typename GRAPH::Node Node;
+        typedef typename GRAPH::Edge Edge;
+        typedef typename GRAPH::EdgeIt EdgeIt;
+        typedef typename GRAPH::OutArcIt OutArcIt;
+
+        typedef ThreeCycle<GRAPH> Cycle;
+
+        std::set< Cycle > cycles;
+        typedef typename std::set<Cycle>::const_iterator SetIter;
+        for (EdgeIt iter(g); iter!=lemon::INVALID; ++iter){
+            const Edge edge(*iter);
+            const Node u = g.u(edge);
+            const Node v = g.v(edge);
+
+            // find a node n which is connected to u and v
+            for(OutArcIt outArcIt(g,u); outArcIt!=lemon::INVALID;++outArcIt){
+                const Node w = g.target(*outArcIt);
+                if(w != v){
+                    const Edge e = g.findEdge(w,v);
+                    if(e != lemon::INVALID){
+                        // found cycle
+                        cycles.insert(Cycle(u, v, w));
+                    }
+                }
+            }
+        }
+        cyclesArray.reshape(TinyVector<UInt32,1>(cycles.size()));
+        UInt32 i=0;
+        for(SetIter iter=cycles.begin(); iter!=cycles.end(); ++iter){
+
+            const Cycle & c = *iter;
+            const Node u = c.nodes_[0];
+            const Node v = c.nodes_[1];
+            const Node w = c.nodes_[2];
+
+            cyclesArray(i)[0] = g.id(g.findEdge(u, v));
+            cyclesArray(i)[1] = g.id(g.findEdge(u, w));
+            cyclesArray(i)[2] = g.id(g.findEdge(v, w));
+            ++i;
+        }
+    }
+
+//@}
+
+} // namespace vigra
+
+#endif // VIGRA_GRAPH_ALGORITHMS_HXX
diff --git a/include/vigra/graph_generalization.hxx b/include/vigra/graph_generalization.hxx
new file mode 100644
index 0000000..a2c4a84
--- /dev/null
+++ b/include/vigra/graph_generalization.hxx
@@ -0,0 +1,252 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2011-2012 Stefan Schmidt and Ullrich Koethe            */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+/**
+ * This header provides definitions of graph-related types
+ * and optionally provides a gateway to popular graph libraries
+ * (for now, BGL is supported).
+ */
+
+#ifndef VIGRA_GRAPH_GENERALIZATION_HXX
+#define VIGRA_GRAPH_GENERALIZATION_HXX
+
+
+#include "graphs.hxx"
+#include "multi_gridgraph.hxx"
+namespace vigra{
+
+
+
+    template<class MAP>
+    struct GraphMapTypeTraits{
+        typedef typename MAP::Value          Value;
+        typedef typename MAP::Reference      Reference;
+        typedef typename MAP::ConstReference ConstReference;
+    };
+
+    // generalizes the iterator begin end accessed
+    // since grid graph has no constructor
+    // for INVALID
+    template<class GRAPH>
+    struct GraphIteratorAccessor{
+        typedef GRAPH Graph;
+        typedef typename Graph::Node        Node;
+        typedef typename Graph::NodeIt      NodeIt;
+        typedef typename Graph::EdgeIt      EdgeIt;
+        typedef typename Graph::ArcIt       ArcIt;
+        typedef typename Graph::OutArcIt    OutArcIt;
+        typedef typename Graph::IncEdgeIt   IncEdgeIt;
+
+        static NodeIt nodesBegin(const Graph & g){ return NodeIt(g);}
+        static EdgeIt edgesBegin(const Graph & g){ return EdgeIt(g);}
+        static ArcIt  arcsBegin( const Graph & g){ return ArcIt( g);}
+        static OutArcIt outArcBegin(const Graph & g,const Node & node){
+            return OutArcIt(g,node);
+        }
+        static IncEdgeIt incEdgeBegin(const Graph & g,const Node & node){
+            return IncEdgeIt(g,node);
+        }
+
+
+        static NodeIt nodesEnd(const Graph & g){ return NodeIt(lemon::INVALID);}
+        static EdgeIt edgesEnd(const Graph & g){ return EdgeIt(lemon::INVALID);}
+        static ArcIt  arcsEnd( const Graph & g){ return ArcIt( lemon::INVALID);}
+        static OutArcIt outArcEnd(const Graph & g,const Node & node){
+            return OutArcIt(lemon::INVALID);
+        }
+        static IncEdgeIt incEdgeEnd(const Graph & g,const Node & node){
+            return IncEdgeIt(lemon::INVALID);
+        }
+    };
+
+    // generalizes the iterator begin end accessed
+    // since grid graph has no constructor
+    // for INVALID
+    template<unsigned int DIM,class DIRECTED_TAG>
+    struct GraphIteratorAccessor<GridGraph<DIM,DIRECTED_TAG> >{
+        typedef GridGraph<DIM,DIRECTED_TAG> Graph;
+        typedef typename Graph::Node Node;
+        typedef typename Graph::NodeIt NodeIt;
+        typedef typename Graph::EdgeIt EdgeIt;
+        typedef typename Graph::ArcIt  ArcIt;
+        typedef typename Graph::OutArcIt OutArcIt;
+        typedef typename Graph::IncEdgeIt   IncEdgeIt;
+
+        static NodeIt   nodesBegin(const Graph & g){ return NodeIt(g);}
+        static EdgeIt   edgesBegin(const Graph & g){ return g.get_edge_iterator();}
+        static ArcIt    arcsBegin( const Graph & g){ return ArcIt( g);}
+        static OutArcIt outArcBegin(const Graph & g,const Node & node){
+            return g.get_out_edge_iterator(node);
+        }
+         static IncEdgeIt incEdgeBegin(const Graph & g,const Node & node){
+            return IncEdgeIt(g,node);
+        }
+
+        static NodeIt   nodesEnd(const Graph & g){ return g.get_vertex_end_iterator();}
+        static EdgeIt   edgesEnd(const Graph & g){ return g.get_edge_end_iterator();}
+        static ArcIt    arcsEnd( const Graph & g){ return g.get_arc_end_iterator(); }
+        static OutArcIt outArcEnd(const Graph & g,const Node & node){
+            return g.get_out_edge_end_iterator(node);
+        }
+        static IncEdgeIt incEdgeEnd(const Graph & g,const Node & node){
+            return IncEdgeIt(lemon::INVALID);
+        }
+    };
+
+
+    // shape of graphs node,edge,arc-maps
+    template<class GRAPH>
+    class IntrinsicGraphShape{
+    private:
+        typedef GRAPH Graph;
+        typedef typename vigra::MultiArray<1,int>::difference_type DiffType1d;
+        typedef typename Graph::index_type  index_type;
+    public:
+        typedef typename Graph::Node Node ;
+        typedef typename Graph::Edge Edge ;
+        typedef typename  Graph::Arc  Arc ;
+
+        typedef DiffType1d IntrinsicNodeMapShape;
+        typedef DiffType1d IntrinsicEdgeMapShape;
+        typedef DiffType1d  IntrinsicArcMapShape;
+
+        static IntrinsicNodeMapShape intrinsicNodeMapShape(const Graph & g){
+            return IntrinsicNodeMapShape(g.maxNodeId()+1);
+        }
+        static IntrinsicEdgeMapShape intrinsicEdgeMapShape(const Graph & g){
+            return IntrinsicEdgeMapShape(g.maxEdgeId()+1);
+        }
+        static IntrinsicArcMapShape intrinsicArcMapShape(const Graph & g){
+            return  IntrinsicArcMapShape(g.maxArcId()+1);
+        }
+
+
+        static const unsigned int IntrinsicNodeMapDimension=1;
+        static const unsigned int IntrinsicEdgeMapDimension=1;
+        static const unsigned int IntrinsicArcMapDimension=1;
+    };
+    // shape of graphs node,edge,arc-maps
+    template<unsigned int DIM,class DIRECTED_TAG>
+    class IntrinsicGraphShape<GridGraph<DIM,DIRECTED_TAG> >{
+    private:
+        typedef GridGraph<DIM,DIRECTED_TAG> Graph;
+    typedef typename Graph::index_type  index_type;
+    public:
+        typedef typename Graph::Node Node ;
+        typedef typename Graph::Edge Edge ;
+        typedef typename  Graph::Arc  Arc ;
+
+        typedef typename Graph::shape_type              IntrinsicNodeMapShape;
+        typedef typename Graph::edge_propmap_shape_type IntrinsicEdgeMapShape;
+        typedef typename Graph::edge_propmap_shape_type IntrinsicArcMapShape;
+
+        static IntrinsicNodeMapShape intrinsicNodeMapShape(const Graph & g){
+            return  g.shape();
+        }
+        static IntrinsicEdgeMapShape intrinsicEdgeMapShape(const Graph & g){
+            return  g.edge_propmap_shape();
+        }
+        static IntrinsicArcMapShape intrinsicArcMapShape(const Graph & g){
+            return  g.arc_propmap_shape();
+        }
+        static const unsigned int IntrinsicNodeMapDimension=DIM;
+        static const unsigned int IntrinsicEdgeMapDimension=DIM+1;
+        static const unsigned int IntrinsicArcMapDimension=DIM+1;
+    };
+
+    // convert a descriptor to an multi_array index w.r.t. 
+    // an node/edge/arc map
+    template<class GRAPH>
+    class GraphDescriptorToMultiArrayIndex{
+    private:
+        typedef GRAPH Graph;
+    typedef typename Graph::index_type  index_type;
+    public:
+        typedef typename Graph::Node Node ;
+        typedef typename Graph::Edge Edge ;
+        typedef typename  Graph::Arc  Arc ;
+
+        typedef typename IntrinsicGraphShape<Graph>::IntrinsicNodeMapShape IntrinsicNodeMapShape;
+        typedef typename IntrinsicGraphShape<Graph>::IntrinsicEdgeMapShape IntrinsicEdgeMapShape;
+        typedef typename IntrinsicGraphShape<Graph>::IntrinsicArcMapShape  IntrinsicArcMapShape;
+
+        static IntrinsicNodeMapShape intrinsicNodeCoordinate(const Graph & g,const Node & node){
+            return IntrinsicNodeMapShape(g.id(node));
+        }
+        static IntrinsicEdgeMapShape intrinsicEdgeCoordinate(const Graph & g,const Edge & edge){
+            return IntrinsicEdgeMapShape(g.id(edge));
+        }
+        static IntrinsicArcMapShape intrinsicArcCoordinate(const Graph & g,const Arc & arc){
+            return  IntrinsicArcMapShape(g.id(arc));
+        }
+
+    };
+
+    // convert a descriptor to an multi_array index w.r.t. 
+    // an node/edge/arc map
+    template<unsigned int DIM,class DIRECTED_TAG>
+    class GraphDescriptorToMultiArrayIndex<GridGraph<DIM,DIRECTED_TAG> >{
+    private:
+        typedef GridGraph<DIM,DIRECTED_TAG> Graph;
+        typedef typename Graph::index_type  index_type;
+    public:
+        typedef typename Graph::Node Node ;
+        typedef typename Graph::Edge Edge ;
+        typedef typename  Graph::Arc  Arc ;
+
+        typedef typename IntrinsicGraphShape<Graph>::IntrinsicNodeMapShape IntrinsicNodeMapShape;
+        typedef typename IntrinsicGraphShape<Graph>::IntrinsicEdgeMapShape IntrinsicEdgeMapShape;
+        typedef typename IntrinsicGraphShape<Graph>::IntrinsicArcMapShape  IntrinsicArcMapShape;
+
+
+        static Node intrinsicNodeCoordinate(const Graph & g,const Node & node){
+            return node;
+        }
+        static Edge intrinsicEdgeCoordinate(const Graph & g,const Edge & edge){
+            return edge;
+        }
+        static Arc  intrinsicArcCoordinate (const Graph & g,const Arc & arc){
+            return arc;
+        }
+
+    };
+
+
+
+
+
+} // namespace vigra
+
+#endif // VIGRA_GRAPH_GENERALIZATION_HXX
diff --git a/include/vigra/graph_item_impl.hxx b/include/vigra/graph_item_impl.hxx
new file mode 100644
index 0000000..7c5f0c3
--- /dev/null
+++ b/include/vigra/graph_item_impl.hxx
@@ -0,0 +1,575 @@
+#ifndef VIGRA_NODE_IMPL_HXX
+#define VIGRA_NODE_IMPL_HXX
+
+
+
+/*vigra*/
+#include "algorithm.hxx"
+#include "tinyvector.hxx"
+#include "random_access_set.hxx"
+#include "iteratorfacade.hxx"
+
+
+
+
+
+namespace vigra{
+
+    /*
+        within this namespace we implement 
+        filter to provide generic lemon iterators
+        for a single incEdgeIterator like iterator
+        
+        These Iterators are used by:
+        - AdjacencyListGraph
+        - MergeGraphAdaptor
+    */
+    namespace detail{
+
+        /*
+            a filter is a functor 
+            which makes an lemon iterator 
+            from a std::set<Adjacency<...> >::const_iterator like
+            iterator.
+            Using these filters will reduce the code 
+            needed to implement lemon compatible iterators
+        */
+
+        // filter to iterate over neighbor nodes for
+        // for a given node
+        template<class GRAPH>
+        struct NeighborNodeFilter{
+            typedef typename GRAPH::Node ResultType;
+            typedef typename GRAPH::NodeStorage::AdjacencyElement AdjacencyElement;
+
+            static bool valid(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return true;
+            }
+
+
+             static ResultType transform(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return g.nodeFromId(adj.nodeId());    
+            }
+
+            static const bool IsFilter = false ; 
+        };
+
+        template<class GRAPH>
+        struct IncEdgeFilter{
+            typedef typename GRAPH::Edge ResultType;
+            typedef typename GRAPH::NodeStorage::AdjacencyElement AdjacencyElement;
+
+            static bool valid(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return true;
+            }
+
+            static ResultType transform(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return g.edgeFromId(adj.edgeId());    
+            }
+
+            static const bool IsFilter = false ; 
+        };
+
+        template<class GRAPH>
+        struct BackEdgeFilter{
+            typedef typename GRAPH::Edge ResultType;
+            typedef typename GRAPH::NodeStorage::AdjacencyElement AdjacencyElement;
+            
+            static bool valid(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return adj.nodeId() < ownNodeId;
+            } 
+
+            static ResultType transform(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return g.edgeFromId(adj.edgeId());
+            }
+
+            static const bool IsFilter = true ; 
+        };
+        template<class GRAPH>
+        struct IsBackOutFilter{
+            typedef typename GRAPH::Arc ResultType;
+            typedef typename GRAPH::NodeStorage::AdjacencyElement AdjacencyElement;
+            
+            static bool valid(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return adj.nodeId() < ownNodeId;
+            } 
+            static ResultType transform(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return g.direct(g.edgeFromId(adj.edgeId()) ,g.nodeFromId(ownNodeId));
+            }
+
+            static const bool IsFilter = true ; 
+        };
+        template<class GRAPH>
+        struct IsOutFilter{
+            typedef typename GRAPH::Arc ResultType;
+            typedef typename GRAPH::NodeStorage::AdjacencyElement AdjacencyElement;
+            
+            static bool valid(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return  true;
+            } 
+            static ResultType transform(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return g.direct(g.edgeFromId(adj.edgeId()) ,g.nodeFromId(ownNodeId));
+            }
+
+            static const bool IsFilter = false ; 
+        };
+
+
+
+        template<class GRAPH>
+        struct IsInFilter{
+            typedef typename GRAPH::Arc ResultType;
+            typedef typename GRAPH::NodeStorage::AdjacencyElement AdjacencyElement;
+            
+            static bool valid(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return  true;
+            } 
+            ResultType static transform(
+                const GRAPH & g,
+                const AdjacencyElement & adj,
+                const typename GRAPH::index_type ownNodeId
+            ){
+                return g.direct(g.edgeFromId(adj.edgeId()) ,g.nodeFromId(adj.nodeId()));
+            }
+            static const bool IsFilter = false ; 
+        };
+
+        template<class GRAPH,class NODE_IMPL,class FILTER>    
+        class GenericIncEdgeIt
+        : public ForwardIteratorFacade<
+            GenericIncEdgeIt<GRAPH,NODE_IMPL,FILTER>,
+            typename FILTER::ResultType,true
+        >
+        {
+        public:
+
+            typedef GRAPH Graph;
+            typedef typename Graph::index_type index_type;
+            typedef typename Graph::NodeIt NodeIt;
+            typedef typename Graph::Edge Edge;
+            typedef typename Graph::Node Node;
+            typedef typename FILTER::ResultType ResultItem;
+            //typedef typename GraphItemHelper<GRAPH,typename FILTER::ResultType>  ResultItem
+
+            // default constructor
+            GenericIncEdgeIt(const lemon::Invalid & invalid = lemon::INVALID)
+            :   nodeImpl_(NULL),
+                graph_(NULL),
+                ownNodeId_(-1),
+                adjIter_(),
+                resultItem_(lemon::INVALID){
+            }   
+            // from a given node iterator
+            GenericIncEdgeIt(const Graph & g , const NodeIt & nodeIt)
+            :   nodeImpl_(&g.nodeImpl(*nodeIt)),
+                graph_(&g),
+                ownNodeId_(g.id(*nodeIt)),
+                adjIter_(g.nodeImpl(*nodeIt).adjacencyBegin()),
+                resultItem_(lemon::INVALID){
+
+                if(FILTER::IsFilter){
+                    while(adjIter_!=nodeImpl_->adjacencyEnd() && !FILTER::valid(*graph_,*adjIter_,ownNodeId_) ) {
+                        ++adjIter_;
+                    }
+                }
+            }
+
+            // from a given node
+            GenericIncEdgeIt(const Graph & g , const Node & node)
+            :   nodeImpl_(&g.nodeImpl(node)),
+                graph_(&g),
+                ownNodeId_(g.id(node)),
+                adjIter_(g.nodeImpl(node).adjacencyBegin()),
+                resultItem_(lemon::INVALID){
+
+                if(FILTER::IsFilter){
+                    while(adjIter_!=nodeImpl_->adjacencyEnd() && !FILTER::valid(*graph_,*adjIter_,ownNodeId_) ) {
+                        ++adjIter_;
+                    }
+                }
+            }
+
+        private:
+            friend class vigra::IteratorFacadeCoreAccess;
+
+            typedef NODE_IMPL NodeImpl;
+            typedef typename NodeImpl::AdjIt AdjIt;
+
+            bool isEnd()const{
+                return  (nodeImpl_==NULL  || adjIter_==nodeImpl_->adjacencyEnd());      
+            }
+            bool isBegin()const{
+                return (nodeImpl_!=NULL &&  adjIter_==nodeImpl_->adjacencyBegin());
+            }
+            bool equal(const GenericIncEdgeIt<GRAPH,NODE_IMPL,FILTER> & other)const{
+                if(isEnd() && other.isEnd()){
+                    return true;
+                }
+                else if (isEnd() != other.isEnd()){
+                    return false;
+                }
+                else{
+                    return adjIter_==other.adjIter_;
+                }
+            }
+
+            void increment(){
+                ++adjIter_;
+                if(FILTER::IsFilter){
+                    while(adjIter_!=nodeImpl_->adjacencyEnd() && !FILTER::valid(*graph_,*adjIter_,ownNodeId_)){
+                        ++adjIter_;
+                    }
+                }
+            }
+
+            // might no need to make this constant
+            // therefore we would lose the "mutabe"
+            const ResultItem & dereference()const{
+                resultItem_ =  FILTER::transform(*graph_,*adjIter_,ownNodeId_);
+                return resultItem_;
+            }
+
+
+            const NODE_IMPL * nodeImpl_;
+            const GRAPH     * graph_;
+            const index_type  ownNodeId_;
+            AdjIt adjIter_;
+            mutable ResultItem resultItem_;
+        };
+
+        // an element in the implementation
+        // of adjacency list
+        // End users will not notice this class
+        // => implementation detail
+        template<class T>
+        class Adjacency {
+        public:
+            typedef T Value;
+
+            Adjacency(const Value nodeId, const Value edgeId)
+            :   nodeId_(nodeId),
+                edgeId_(edgeId){
+
+            }
+            Value  nodeId() const{
+                return nodeId_;
+            }
+            Value& nodeId(){
+                return nodeId_;
+            }
+            Value  edgeId() const{
+                return edgeId_;
+            }
+            Value& edgeId(){
+                return edgeId_;
+            }
+            bool operator<(const Adjacency<Value> & other) const{
+                return  nodeId_ < other.nodeId_;
+            }
+        private:
+            Value nodeId_;
+            Value edgeId_;
+        };
+
+
+        // an element in the implementation
+        // of adjacency list
+        // End users will not notice this class
+        // => implementation detail
+        template<class INDEX_TYPE,bool USE_STL_SET>
+        class GenericNodeImpl{
+
+            public:
+                typedef INDEX_TYPE index_type;
+                typedef Adjacency<index_type>    AdjacencyElement;
+                typedef std::set<AdjacencyElement >        StdSetType;
+                typedef RandomAccessSet<AdjacencyElement > RandAccessSet;
+                typedef typename IfBool<USE_STL_SET,StdSetType,RandAccessSet>::type SetType;
+
+                typedef typename SetType::const_iterator AdjIt;
+            public:
+
+                GenericNodeImpl(const lemon::Invalid iv=lemon::INVALID)
+                :  id_(-1){
+                }
+
+                GenericNodeImpl(const index_type id)
+                :   id_(id){
+                 }
+                // query
+                size_t numberOfEdges()const{return adjacency_.size();}
+                size_t edgeNum()const{return adjacency_.size();}
+                size_t num_edges()const{return adjacency_.size();}
+
+                //bool hasEdgeId(const index_type edge)const{return edges_.find(edge)!=edges_.end();}
+
+                // modification
+                void  merge(const GenericNodeImpl & other){
+                    adjacency_.insert(other.adjacency_.begin(),other.adjacency_.end());
+                }
+
+                void setId(const index_type id){
+                    id_=id;
+                }
+                
+                std::pair<index_type,bool> findEdge(const index_type nodeId)const{
+                    AdjIt iter = adjacency_.find(AdjacencyElement(nodeId,0));
+                    if(iter==adjacency_.end()){
+                        return std::pair<index_type,bool>(-1,false);
+                    }
+                    else{
+                        return std::pair<index_type,bool>(iter->edgeId(),true);
+                    }
+                }
+
+
+
+                void insert(const index_type nodeId,const index_type edgeId){
+                    adjacency_.insert(AdjacencyElement(nodeId,edgeId));
+                }
+
+                AdjIt adjacencyBegin()const{
+                    return adjacency_.begin();
+                }
+                AdjIt adjacencyEnd()const{
+                    return adjacency_.end();
+                }
+
+
+                index_type id()const{
+                    return id_;
+                }
+
+
+                void eraseFromAdjacency(const index_type nodeId){
+                    // edge id does not matter?
+                    adjacency_.erase(AdjacencyElement(nodeId,0));
+                }
+
+                void clear(){
+                    adjacency_.clear();
+                    id_=-1;
+                }
+
+                SetType adjacency_;
+                index_type id_;
+        };
+
+        template<class INDEX_TYPE>
+        class GenericEdgeImpl
+        :  public vigra::TinyVector<INDEX_TYPE,3> {
+                // public typedefs
+            public:
+                typedef INDEX_TYPE index_type;
+
+                GenericEdgeImpl(const lemon::Invalid iv=lemon::INVALID)
+                :    vigra::TinyVector<INDEX_TYPE,3>(-1){
+                }
+
+                GenericEdgeImpl(const index_type u,const index_type v, const index_type id)   
+                :    vigra::TinyVector<INDEX_TYPE,3>(u,v,id){
+                }
+            // public methods
+            public:
+                index_type u()const{return this->operator[](0);}
+                index_type v()const{return this->operator[](1);}
+                index_type id()const{return this->operator[](2);}
+            private:
+        };
+
+
+        template<class INDEX_TYPE>
+        class GenericEdge;
+
+        template<class INDEX_TYPE>
+        class GenericArc{
+        public:
+            typedef INDEX_TYPE index_type;
+
+            GenericArc(const lemon::Invalid & iv = lemon::INVALID)
+            :   id_(-1),
+                edgeId_(-1){
+
+            }
+
+
+
+            GenericArc(
+                const index_type id,
+                const index_type edgeId = static_cast<index_type>(-1) 
+            )
+            :   id_(id),
+                edgeId_(edgeId){
+
+            }
+            index_type id()const{return id_;}
+            index_type edgeId()const{return edgeId_;}
+
+            operator GenericEdge<INDEX_TYPE> () const{
+                return GenericEdge<INDEX_TYPE>(edgeId());
+            }
+
+            bool operator == (const GenericArc<INDEX_TYPE> & other )const{
+                return id_ == other.id_;
+            }
+            bool operator != (const GenericArc<INDEX_TYPE> & other )const{
+                return id_ != other.id_;
+            }
+            bool operator < (const GenericArc<INDEX_TYPE> & other )const{
+                return id_ < other.id_;
+            }
+            bool operator > (const GenericArc<INDEX_TYPE> & other )const{
+                return id_ > other.id_;
+            }
+
+
+
+        private:
+            index_type id_;
+            index_type edgeId_;
+        };
+
+        template<class INDEX_TYPE>
+        class GenericEdge{
+        public:
+            typedef INDEX_TYPE index_type;
+
+            GenericEdge(const lemon::Invalid & iv = lemon::INVALID)
+            : id_(-1){
+
+            }
+
+            GenericEdge(const index_type id )
+            : id_(id){
+
+            }
+
+            GenericEdge(const GenericArc<INDEX_TYPE> & arc)
+            :   id_(arc.edgeId())
+            {
+            }
+
+            bool operator == (const GenericEdge<INDEX_TYPE> & other )const{
+                return id_ == other.id_;
+            }
+            bool operator != (const GenericEdge<INDEX_TYPE> & other )const{
+                return id_ != other.id_;
+            }
+            bool operator < (const GenericEdge<INDEX_TYPE> & other )const{
+                return id_ < other.id_;
+            }
+            bool operator > (const GenericEdge<INDEX_TYPE> & other )const{
+                return id_ > other.id_;
+            }
+            bool operator <= (const GenericEdge<INDEX_TYPE> & other )const{
+                return id_ <= other.id_;
+            }
+            bool operator >= (const GenericEdge<INDEX_TYPE> & other )const{
+                return id_ >= other.id_;
+            }
+
+
+            index_type id()const{return id_;}
+        private:
+            index_type id_;
+        };
+
+
+        template<class INDEX_TYPE>
+        class GenericNode{
+        public:
+            typedef INDEX_TYPE index_type;
+
+            GenericNode(const lemon::Invalid & iv = lemon::INVALID)
+            : id_(-1){
+
+            }
+
+            GenericNode(const index_type id  )
+            : id_(id){
+                
+            }
+            bool operator == (const GenericNode<INDEX_TYPE> & other )const{
+                return id_ == other.id_;
+            }
+            bool operator != (const GenericNode<INDEX_TYPE> & other )const{
+                return id_ != other.id_;
+            }
+            bool operator < (const GenericNode<INDEX_TYPE> & other )const{
+                return id_ < other.id_;
+            }
+            bool operator > (const GenericNode<INDEX_TYPE> & other )const{
+                return id_ > other.id_;
+            }
+
+            index_type id()const{return id_;}
+        private:
+            index_type id_;
+        };
+
+    } // namespace detail
+} // end namespace vigra
+
+namespace std {
+
+template<class INDEX_TYPE>
+ostream & operator<<(ostream & o, vigra::detail::GenericNode<INDEX_TYPE> const & n)
+{
+    o << "Node(" << n.id() << ")";
+    return o;
+}
+
+template<class INDEX_TYPE>
+ostream & operator<<(ostream & o, vigra::detail::GenericEdge<INDEX_TYPE> const & e)
+{
+    o << "Edge(" << e.id() << ")";
+    return o;
+}
+
+}
+
+#endif // VIGRA_NODE_IMPL_HXX
diff --git a/include/vigra/graph_maps.hxx b/include/vigra/graph_maps.hxx
new file mode 100644
index 0000000..95992a6
--- /dev/null
+++ b/include/vigra/graph_maps.hxx
@@ -0,0 +1,399 @@
+/************************************************************************/
+/*                                                                      */
+/*   Copyright 2014 by Ullrich Koethe  and Thorsten Beier               */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+
+#ifndef VIGRA_GRAPH_MAPS
+#define VIGRA_GRAPH_MAPS
+
+/*vigra*/
+#include "multi_array.hxx"
+#include "graph_generalization.hxx"
+#include "graphs.hxx"
+
+
+namespace vigra{
+
+// base class for basic implementation
+// of a class for node,edge and arc maps.
+template<class T,class KEY,class REF,class CREF>
+class DenseReferenceMap
+: public MultiArray<1,T>
+{
+public:
+    typedef KEY  Key;
+    typedef T    Value;
+    typedef REF  Reference;
+    typedef CREF ConstReference;
+
+    typedef Key             key_type;
+    typedef Value           value_type;
+    typedef Reference       reference;
+    typedef ConstReference  const_reference;
+    typedef boost_graph::read_write_property_map_tag category;
+
+
+    typedef typename MultiArray<1,T>::difference_type Shape1Type;
+
+    DenseReferenceMap()
+    : MultiArray<1,T>(){
+    }
+    DenseReferenceMap(const size_t maxKey)
+    : MultiArray<1,T>(Shape1Type(maxKey+1)){
+    }
+    DenseReferenceMap(const size_t maxKey,ConstReference  value)
+    : MultiArray<1,T>(Shape1Type(maxKey+1),value){
+    }
+
+
+
+
+    ConstReference operator[](const KEY & key)const{
+        //return this->operator[](key.id());
+        return MultiArray<1,T>::operator()(key.id());
+    }
+    Reference operator[](const KEY & key){
+        return MultiArray<1,T>::operator()(key.id());
+    }
+
+    size_t size()const{
+        return this->shape(0);
+    }
+protected:
+    void assign(const size_t maxKey){
+        this->reshape(Shape1Type(maxKey+1));
+    }
+private:
+    // NONE
+};
+
+
+// basic implementation
+// of a class for node,edge and arc maps.
+template<class GRAPH,class ITEM,class T,class REF,class CREF>
+class DenseGraphItemReferenceMap
+: public DenseReferenceMap<T,ITEM,REF,CREF>
+{
+    typedef GRAPH Graph;
+    typedef ITEM  Item;
+    typedef DenseReferenceMap<T,ITEM,REF,CREF> DenseReferenceMapType;
+    typedef GraphItemHelper<Graph,ITEM> ItemHelper;
+    typedef typename ItemHelper::ItemIt ItemIt;
+
+public:
+    DenseGraphItemReferenceMap()
+    :   DenseReferenceMapType(){
+
+    }
+    DenseGraphItemReferenceMap(const Graph & g)
+    :   DenseReferenceMapType(ItemHelper::itemNum(g)==0 ? 0: ItemHelper::maxItemId(g) ){
+
+    }
+    DenseGraphItemReferenceMap(const Graph & g,typename DenseReferenceMapType::ConstReference value)
+    :   DenseReferenceMapType(ItemHelper::itemNum(g)==0 ? 0: ItemHelper::maxItemId(g)){
+
+    }
+    void assign(const Graph & g){
+        DenseReferenceMapType::assign(ItemHelper::itemNum(g)==0 ? 0: ItemHelper::maxItemId(g));
+    }
+};
+
+// basic class for node-maps
+template<class GRAPH,class T,class REF= T & ,class CREF = const T & >
+class DenseNodeReferenceMap
+: public DenseGraphItemReferenceMap<GRAPH,typename GRAPH::Node,T,REF,CREF>
+{
+    typedef typename GRAPH::Node Node;
+    typedef DenseGraphItemReferenceMap<GRAPH,Node,T,REF,CREF> DenseGraphItemReferenceMapType;
+    public:
+        DenseNodeReferenceMap()
+        : DenseGraphItemReferenceMapType(){
+        }
+        DenseNodeReferenceMap(const GRAPH & g)
+        : DenseGraphItemReferenceMapType(g){
+        }
+        DenseNodeReferenceMap(const GRAPH & g,typename DenseGraphItemReferenceMapType::ConstReference value)
+        : DenseGraphItemReferenceMapType(g,value){
+        }
+};
+
+// basic class for edge-maps
+template<class GRAPH,class T,class REF= T & ,class CREF = const T & >
+class DenseEdgeReferenceMap
+: public DenseGraphItemReferenceMap<GRAPH,typename GRAPH::Edge,T,REF,CREF>
+{
+    typedef typename GRAPH::Edge Edge;
+    typedef DenseGraphItemReferenceMap<GRAPH,Edge,T,REF,CREF> DenseGraphItemReferenceMapType;
+    public:
+        DenseEdgeReferenceMap()
+        : DenseGraphItemReferenceMapType(){
+        }
+        DenseEdgeReferenceMap(const GRAPH & g)
+        : DenseGraphItemReferenceMapType(g){
+        }
+        DenseEdgeReferenceMap(const GRAPH & g,typename DenseGraphItemReferenceMapType::ConstReference value)
+        : DenseGraphItemReferenceMapType(g,value){
+        }
+};
+
+// basic class for arc-maps
+template<class GRAPH,class T,class REF= T & ,class CREF = const T & >
+class DenseArcReferenceMap
+: public DenseGraphItemReferenceMap<GRAPH,typename GRAPH::Arc,T,REF,CREF>
+{
+    typedef typename GRAPH::Arc Arc;
+    typedef DenseGraphItemReferenceMap<GRAPH,Arc,T,REF,CREF> DenseGraphItemReferenceMapType;
+    public:
+        DenseArcReferenceMap()
+        : DenseGraphItemReferenceMapType(){
+        }
+        DenseArcReferenceMap(const GRAPH & g)
+        : DenseGraphItemReferenceMapType(g){
+        }
+        DenseArcReferenceMap(const GRAPH & g,typename DenseGraphItemReferenceMapType::ConstReference value)
+        : DenseGraphItemReferenceMapType(g,value){
+        }
+};
+
+// implicit edge map:
+// the values of a node map are converted
+// to an edge map.
+// FUNCTOR is used to convert the two
+// node map values corresponding to an edge to
+// an edge map value
+template<class G,class NODE_MAP,class FUNCTOR,class RESULT>
+class OnTheFlyEdgeMap{
+
+public:
+    typedef G  Graph;
+    typedef typename Graph::Node Node;
+    typedef NODE_MAP  NodeMap;
+    typedef typename  Graph::Edge      Key;
+    typedef RESULT   Value;
+    typedef RESULT   ConstReference;
+
+    typedef Key             key_type;
+    typedef Value           value_type;
+    typedef ConstReference  const_reference;
+
+    typedef boost_graph::readable_property_map_tag category;
+
+    OnTheFlyEdgeMap(const Graph & graph,const NodeMap & nodeMap,FUNCTOR & f)
+    :   graph_(graph),
+        nodeMap_(nodeMap),
+        f_(f){
+    }
+
+    ConstReference operator[](const Key & key){
+        const Node u(graph_.u(key));
+        const Node v(graph_.v(key));
+        return f_(nodeMap_[u],nodeMap_[v]);
+    }
+
+    ConstReference operator[](const Key & key)const{
+        const Node u(graph_.u(key));
+        const Node v(graph_.v(key));
+        return f_(nodeMap_[u],nodeMap_[v]);
+    }
+private:
+
+    const Graph & graph_;
+    const NodeMap & nodeMap_;
+    FUNCTOR & f_;
+};
+
+
+// node map that returns zero (specifically, <tt>RESULT()</tt>) for all keys
+template<class G, class RESULT>
+class ZeroNodeMap
+{
+  public:
+    typedef G  Graph;
+    typedef typename Graph::Node Key;
+    typedef RESULT   Value;
+    typedef RESULT   ConstReference;
+
+    typedef Key             key_type;
+    typedef Value           value_type;
+    typedef ConstReference  const_reference;
+    typedef boost_graph::readable_property_map_tag category;
+
+    ZeroNodeMap()
+    {}
+
+    value_type operator[](const Key & key) const
+    {
+        return value_type();
+    }
+};
+
+
+
+template<class T_OUT>
+struct MeanFunctor{
+    template<class T>
+    T_OUT operator()(const T & a, const T & b)const{
+        return static_cast<T_OUT>(a+b)/static_cast<T_OUT>(2.0);
+    }
+
+};
+
+
+// implicit edge map:
+// the values of a node map are converted
+// to an edge map.
+// FUNCTOR is used to convert the two
+// node map values corresponding to an edge to
+// an edge map value
+template<class G,class NODE_MAP,class FUNCTOR,class RESULT>
+class OnTheFlyEdgeMap2{
+
+public:
+    typedef G  Graph;
+    typedef typename Graph::Node Node;
+    typedef NODE_MAP  NodeMap;
+    typedef typename  Graph::Edge      Key;
+    typedef RESULT   Value;
+    typedef RESULT   ConstReference;
+
+    typedef Key             key_type;
+    typedef Value           value_type;
+    typedef ConstReference  const_reference;
+
+    typedef boost_graph::readable_property_map_tag category;
+
+    OnTheFlyEdgeMap2(const Graph & graph,const NodeMap & nodeMap,FUNCTOR  f)
+    :   graph_(graph),
+        nodeMap_(nodeMap),
+        f_(f){
+    }
+
+    ConstReference operator[](const Key & key){
+        const Node u(graph_.u(key));
+        const Node v(graph_.v(key));
+        return f_(nodeMap_[u],nodeMap_[v]);
+    }
+
+    ConstReference operator[](const Key & key)const{
+        const Node u(graph_.u(key));
+        const Node v(graph_.v(key));
+        return f_(nodeMap_[u],nodeMap_[v]);
+    }
+private:
+
+    const Graph & graph_;
+    const NodeMap nodeMap_;
+    FUNCTOR  f_;
+};
+
+
+// convert 2 edge maps with a functor into a single edge map
+template<class G,class EDGE_MAP_A,class EDGE_MAP_B,class FUNCTOR,class RESULT>
+class BinaryOpEdgeMap{
+public:
+    typedef G  Graph;
+    typedef typename Graph::Edge Key;
+    typedef RESULT   Value;
+    typedef RESULT   ConstReference;
+
+    typedef Key             key_type;
+    typedef Value           value_type;
+    typedef ConstReference  const_reference;
+
+    typedef boost_graph::readable_property_map_tag category;
+
+    BinaryOpEdgeMap(const Graph & graph,const EDGE_MAP_A & edgeMapA,const EDGE_MAP_B & edgeMapB,FUNCTOR & f)
+    :   graph_(graph),
+        edgeMapA_(edgeMapA),
+        edgeMapB_(edgeMapB),
+        f_(f){
+    }
+    ConstReference operator[](const Key & key){
+        return f_(edgeMapA_[key],edgeMapB_[key]);
+    }
+    ConstReference operator[](const Key & key)const{
+        return f_(edgeMapA_[key],edgeMapB_[key]);
+    }
+private:
+
+    const Graph & graph_;
+    const EDGE_MAP_A & edgeMapA_;
+    const EDGE_MAP_B & edgeMapB_;
+    FUNCTOR & f_;
+};
+
+
+
+// encapsulate a MultiArrayView indexed by node/edge ID
+template<class T,class GRAPH, class KEY>
+struct ArrayMap{
+
+    typedef MultiArrayView<1, T>  View;
+    typedef KEY    Key;
+    typedef typename View::value_type  Value;
+    typedef typename View::const_reference  ConstReference;
+    typedef typename View::reference  Reference;
+
+    ArrayMap(const GRAPH & graph)
+    :   graph_(graph),
+        view_(){
+    }
+
+    ArrayMap(const GRAPH & graph, const View & view)
+    :   graph_(graph),
+        view_(view){
+    }
+
+    void setArray(const MultiArrayView<1, T> & view){
+        view_ = view;
+    }
+
+    Reference operator[](const Key & key){
+       return view_(graph_.id(key));
+    }
+
+    ConstReference operator[](const Key & key)const{
+        return view_(graph_.id(key));
+    }
+    const GRAPH & graph_;
+    MultiArrayView<1, T> view_;
+
+};
+
+
+
+
+} // end namespace vigra
+
+#endif // VIGRA_GRAPH_MAPS
diff --git a/include/vigra/graph_rag_project_back.hxx b/include/vigra/graph_rag_project_back.hxx
new file mode 100644
index 0000000..0338ddd
--- /dev/null
+++ b/include/vigra/graph_rag_project_back.hxx
@@ -0,0 +1,193 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2014 by Thorsten Beier and Ullrich Koethe              */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+/**
+ * This header provides definitions of graph-related algorithms
+ */
+
+#ifndef VIGRA_GRAPH_RAG_PROJECT_BACK_HXX
+#define VIGRA_GRAPH_RAG_PROJECT_BACK_HXX
+
+/*std*/
+#include <algorithm>
+#include <vector>
+#include <functional>
+#include <set>
+
+
+/*vigra*/
+#include "graphs.hxx"
+#include "graph_generalization.hxx"
+#include "multi_gridgraph.hxx"
+#include "priority_queue.hxx"
+#include "union_find.hxx"
+#include "adjacency_list_graph.hxx"
+#include "graph_maps.hxx"
+
+
+
+namespace vigra{
+
+    /// \cond
+    namespace detail_rag_project_back{
+
+    template<
+        class BASE_GRAPH,
+        class BASE_GRAPH_LABELS,
+        class RAG_FEATURES,
+        class BASE_GRAPH_FEATURES
+    >
+    struct RagProjectBack{
+
+
+        static void projectBack(
+            const AdjacencyListGraph & rag,
+            const BASE_GRAPH & bg,
+            const Int64 ignoreLabel,
+            const BASE_GRAPH_LABELS bgLabels,
+            const RAG_FEATURES & ragFeatures,
+            BASE_GRAPH_FEATURES & bgFeatures
+        ){
+            typedef BASE_GRAPH Bg;
+            typedef typename Bg::NodeIt BgNodeIt;
+            typedef typename Bg::Node BgNode;
+
+            if(ignoreLabel==-1){
+                for(BgNodeIt iter(bg); iter!=lemon::INVALID; ++iter){
+                    const BgNode bgNode(*iter);
+                    bgFeatures[bgNode] = ragFeatures[rag.nodeFromId(bgLabels[bgNode])];
+                }
+            }
+            else{
+                for(BgNodeIt iter(bg); iter!=lemon::INVALID; ++iter){
+                    const BgNode bgNode(*iter);
+                    if(static_cast<Int64>(bgLabels[bgNode])!=ignoreLabel)
+                        bgFeatures[bgNode] = ragFeatures[rag.nodeFromId(bgLabels[bgNode])];
+                }
+            }
+        }
+    };
+
+
+    template<
+        class BASE_GRAPH_LABELS,
+        class RAG_FEATURES,
+        class BASE_GRAPH_FEATURES
+    >
+    struct RagProjectBack<
+        vigra::GridGraph<3, undirected_tag>,
+        BASE_GRAPH_LABELS,
+        RAG_FEATURES,
+        BASE_GRAPH_FEATURES
+    >{
+        typedef vigra::GridGraph<3, undirected_tag> BASE_GRAPH;
+
+        static void projectBack(
+            const AdjacencyListGraph & rag,
+            const BASE_GRAPH & bg,
+            const Int64 ignoreLabel,
+            const BASE_GRAPH_LABELS bgLabels,
+            const RAG_FEATURES & ragFeatures,
+            BASE_GRAPH_FEATURES & bgFeatures
+        ){
+            typedef BASE_GRAPH Bg;
+            typedef typename Bg::Node BgNode;
+
+
+            vigra::TinyVector<Int64, 3> shape = bg.shape();
+
+
+            if(ignoreLabel==-1){
+                
+// FIXME: replace with threadpool                #pragma omp parallel for
+                for(Int64 z=0; z<shape[2]; ++z){    
+                    BgNode node;
+                    node[2]=z;
+                    for(node[1]=0; node[1]<shape[1]; ++node[1])  
+                    for(node[0]=0; node[0]<shape[0]; ++node[0]){
+                        bgFeatures[node] = ragFeatures[rag.nodeFromId(bgLabels[node])];
+                    }  
+                }
+
+            }
+            else{
+// FIXME: replace with threadpool                #pragma omp parallel for
+                for(Int64 z=0; z<shape[2]; ++z){    
+                    BgNode node;
+                    node[2]=z;
+                    for(node[1]=0; node[1]<shape[1]; ++node[1])  
+                    for(node[0]=0; node[0]<shape[0]; ++node[0]){
+                        if(static_cast<Int64>(bgLabels[node])!=ignoreLabel)
+                            bgFeatures[node] = ragFeatures[rag.nodeFromId(bgLabels[node])];
+                    }  
+                }
+            }
+        }
+    };
+
+
+
+    }
+    /// \endcond
+
+    /// project node features of a region adjacency
+    /// graph back to the base graph.
+    ///
+    /// This function can be used to show a segmentation
+    /// or node features of RAG on pixel / voxel level
+    template< class BASE_GRAPH,
+                class BASE_GRAPH_LABELS,
+                class RAG_FEATURES,
+                class BASE_GRAPH_FEATURES 
+    >
+    inline void projectBack(
+            const AdjacencyListGraph & rag,
+            const BASE_GRAPH & bg,
+            const Int64 ignoreLabel,
+            const BASE_GRAPH_LABELS bgLabels,
+            const RAG_FEATURES & ragFeatures,
+            BASE_GRAPH_FEATURES & bgFeatures
+    ){
+        using namespace detail_rag_project_back;
+        detail_rag_project_back::RagProjectBack< BASE_GRAPH,BASE_GRAPH_LABELS,RAG_FEATURES,BASE_GRAPH_FEATURES>::projectBack(rag,
+            bg,ignoreLabel,bgLabels,ragFeatures,bgFeatures);
+    }
+
+
+
+}
+
+#endif /* VIGRA_GRAPH_RAG_PROJECT_BACK_HXX */
+
diff --git a/include/vigra/graphs.hxx b/include/vigra/graphs.hxx
index 348bca5..411ca50 100644
--- a/include/vigra/graphs.hxx
+++ b/include/vigra/graphs.hxx
@@ -51,10 +51,19 @@
 #  include <boost/graph/graph_traits.hpp>
 #  include <boost/graph/properties.hpp>
 
+namespace vigra {
+namespace boost_graph {
+
+// vigra::boost_graph contains algorithms that are compatible to the Boost Graph Library
+using namespace boost;
+
+}} // namespace vigra::boost_graph
+
 #else // not WITH_BOOST_GRAPH
 
 // emulate the BGL-style interface
-namespace boost {
+namespace vigra {
+namespace boost_graph {
 
 struct no_property {};
 
@@ -80,24 +89,22 @@ struct disallow_parallel_edge_tag { };
 struct readable_property_map_tag { };
 struct writable_property_map_tag { };
 struct read_write_property_map_tag
-    : public readable_property_map_tag, 
+    : public readable_property_map_tag,
       public writable_property_map_tag {};
 struct lvalue_property_map_tag
     : public read_write_property_map_tag {};
 
-struct vertex_index_t {}; 
+struct vertex_index_t {};
 
 struct edge_property_tag {};
 
-#ifndef BOOST_TUPLE_HPP
-
 // tie() support for std::pair, similar to Boost's one:
 // (necessary because std::pair doesn't define a suitable assignment operator)
 template<class T1, class T2>
-class tie_adapter 
+class tie_adapter
 {
   public:
-    tie_adapter(T1 &x, T2 &y) 
+    tie_adapter(T1 &x, T2 &y)
         : x_(x), y_(y)
     {}
 
@@ -108,7 +115,7 @@ class tie_adapter
         y_ = pair.second;
         return *this;
     }
-    
+
   protected:
     T1 &x_;
     T2 &y_;
@@ -117,11 +124,10 @@ class tie_adapter
 template<class T1, class T2>
 inline
 tie_adapter<T1, T2>
-tie(T1& t1, T2& t2) 
+tie(T1& t1, T2& t2)
 {
     return tie_adapter<T1, T2>(t1, t2);
 }
-#endif
 
 // graph_traits class template
 template <typename G>
@@ -150,73 +156,17 @@ struct graph_traits {
 
 // property_traits class template
 template <typename PropMap>
-struct property_traits 
+struct property_traits
 {
     typedef typename PropMap::key_type    key_type;
-    typedef typename PropMap::value_type  value_type; 
+    typedef typename PropMap::value_type  value_type;
     typedef typename PropMap::reference   reference;
     typedef typename PropMap::category    category;
 };
 
-namespace {
-
-vertex_index_t vertex_index;
-
-} // anonymous namespace
-
-} // namespace boost
-
-#endif // WITH_BOOST_GRAPH
-
-namespace vigra {
-namespace boost_graph { 
-
-// vigra::boost_graph contains algorithms that are compatible to the Boost Graph Library
-using namespace boost;
-
 }} // namespace vigra::boost_graph
 
-
-
-
-#if 0
-namespace vigragraph {
-
-// custom get_helper for read-only property maps (by-value)
-
-template <class ValueType, class ReadablePropertyMap>
-struct get_helper { };
-
-template <class PropertyMap, class ValueType, class K>
-inline ValueType
-get(const get_helper<ValueType, PropertyMap>& pa, const K& k)
-{
-    const ValueType v = static_cast<const PropertyMap&>(pa)[k];
-    return v;
-}
-
-
-// ! A fallback template for adjacent_vertices() called with
-// a vertex_iterator 
-// (which may be specialized to be implemented more efficiently;
-//  the reason is that the iterator may have more information than
-//  the plain vertex_descriptor, e.g. it knows the neighborhood
-//  already which otherwise needs to be reconstructed.)
-template<class GRAPH>
-inline
-std::pair<typename graph_traits<GRAPH>::adjacency_iterator, 
-          typename graph_traits<GRAPH>::adjacency_iterator >
-adjacent_vertices_at_iterator(typename graph_traits<GRAPH>::vertex_iterator const &v,
-                              GRAPH const &g) 
-{    
-    // the default implementation just derefences the iterator
-    // to yield a vertex_descriptor and forwards the call
-    std::cout << "FB" << std::endl;
-    return adjacent_vertices(*v, g);
-}
-
-} // namespace vigragraph
-#endif
+#endif // WITH_BOOST_GRAPH
 
 #ifdef WITH_LEMON
 #  include <lemon/core.h>
@@ -276,7 +226,72 @@ inline bool operator!=(Invalid, T const & t)
 } // namespace lemon
 
 namespace vigra {
-namespace lemon_graph { 
+
+
+template<class GRAPH,class ITEM>
+struct GraphItemHelper;
+
+template<class GRAPH>
+struct GraphItemHelper<GRAPH,typename GRAPH::Edge>{
+    typedef typename GRAPH::index_type index_type ;
+    typedef typename GRAPH::Edge Item;
+    typedef typename GRAPH::EdgeIt ItemIt;
+
+
+    static index_type maxItemId(const GRAPH & g){
+        return g.maxEdgeId();
+    }
+    static index_type itemNum(const GRAPH & g){
+        return g.edgeNum();
+    }
+    static Item itemFromId(const GRAPH & g,const index_type id){
+        return g.edgeFromId(id);
+    }
+
+};
+
+template<class GRAPH>
+struct GraphItemHelper<GRAPH,typename GRAPH::Node>{
+    typedef typename GRAPH::index_type index_type ;
+    typedef typename GRAPH::Node Item;
+    typedef typename GRAPH::NodeIt ItemIt;
+
+
+    static index_type maxItemId(const GRAPH & g){
+        return g.maxNodeId();
+    }
+    static index_type itemNum(const GRAPH & g){
+        return g.nodeNum();
+    }
+    static Item itemFromId(const GRAPH & g,const index_type id){
+        return g.nodeFromId(id);
+    }
+};
+
+
+template<class GRAPH>
+struct GraphItemHelper<GRAPH,typename GRAPH::Arc>{
+    typedef typename GRAPH::index_type index_type ;
+    typedef typename GRAPH::Arc Item;
+    typedef typename GRAPH::ArcIt ItemIt;
+
+
+    static index_type maxItemId(const GRAPH & g){
+        return g.maxArcId();
+    }
+    static index_type itemNum(const GRAPH & g){
+        return g.arcNum();
+    }
+    static Item itemFromId(const GRAPH & g,const index_type id){
+        return g.arcFromId(id);
+    }
+};
+
+
+
+
+
+namespace lemon_graph {
 
 // vigra::lemon_graph contains algorithms that are compatible to the LEMON graph library
 using namespace lemon;
diff --git a/include/vigra/hdf5impex.hxx b/include/vigra/hdf5impex.hxx
index ea3fd98..6a0e8d0 100644
--- a/include/vigra/hdf5impex.hxx
+++ b/include/vigra/hdf5impex.hxx
@@ -37,6 +37,8 @@
 #define VIGRA_HDF5IMPEX_HXX
 
 #include <string>
+#include <algorithm>
+#include <utility>
 
 #define H5Gcreate_vers 2
 #define H5Gopen_vers 2
@@ -77,8 +79,6 @@
 #include "utilities.hxx"
 #include "error.hxx"
 
-#include <algorithm>
-
 #if defined(_MSC_VER)
 #  include <io.h>
 #else
@@ -106,26 +106,81 @@ inline bool isHDF5(char const * filename)
 #endif
 }
 
-    /** \brief Wrapper for hid_t objects.
+    /** \brief Temporarily disable HDF5's native error output.
+    
+        This should be used when you want to call an HDF5 function
+        that is known to fail (e.g. during testing), or when you want
+        to use an alternative error reporting mechanism (e.g. exceptions).
+        
+        <b>Usage:</b>
+        
+        <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
+        Namespace: vigra
+        \code
+        {
+            HDF5DisableErrorOutput hdf5DisableErrorOutput;
+        
+            ... // call some HDF5 function
+            
+        } // restore the original error reporting in the destructor of HDF5DisableErrorOutput
+        \endcode
+    */
+class HDF5DisableErrorOutput
+{
+    H5E_auto2_t old_func_;
+    void *old_client_data_;
+    
+    HDF5DisableErrorOutput(HDF5DisableErrorOutput const &);
+    HDF5DisableErrorOutput & operator=(HDF5DisableErrorOutput const &);
+
+  public:    
+    HDF5DisableErrorOutput()
+    : old_func_(0)
+    , old_client_data_(0)
+    {
+        H5Eget_auto2(H5E_DEFAULT, &old_func_, &old_client_data_);
+        H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
+    }
 
-    Newly created or opened HDF5 handles are usually stored as objects of type 'hid_t'. When the handle
+    ~HDF5DisableErrorOutput()
+    {
+        H5Eset_auto2(H5E_DEFAULT, old_func_, old_client_data_);
+    }
+};
+
+    /** \brief Wrapper for unique hid_t objects.
+
+    This class offers the functionality of <tt>std::unique_ptr</tt> for HDF5 handles 
+    (type <tt>hid_t</tt>). Unfortunately, <tt>std::unique_ptr</tt> cannot be used directly 
+    for this purpose because it only works with pointers, whereas <tt>hid_t</tt> is an integer type.
+    
+    Newly created or opened HDF5 handles are stored as objects of type <tt>hid_t</tt>. When the handle
     is no longer needed, the appropriate close function must be called. However, if a function is 
     aborted by an exception, this is difficult to ensure. Class HDF5Handle is a smart pointer that 
     solves this problem by calling the close function in the destructor (This is analogous to how 
-    VIGRA_UNIQUE_PTR calls 'delete' on the contained pointer). A pointer to the close function must be 
-    passed to the constructor, along with an error message that is raised when creation/opening fails. 
+    <tt>std::unique_ptr</tt> calls 'delete' on the contained pointer). A pointer to the close function 
+    must be passed to the constructor, along with an error message that is raised when 
+    creation/opening fails. 
+    
+    When a <tt>HDF5Handle</tt> is created or assigned from another one, ownership passes on to the  
+    left-hand-side handle object, and the right-hand-side objects is resest to a NULL handle.
     
-    Since HDF5Handle objects are convertible to hid_t, they can be used in the code in place 
-    of the latter.
+    Since <tt>HDF5Handle</tt> objects are convertible to <tt>hid_t</tt>, they can be used in the code 
+    in place of the latter.
 
     <b>Usage:</b>
 
     \code
     HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT), 
                        &H5Fclose, 
-                       "Error message.");
+                       "Error message when H5Fopen() fails.");
                        
     ... // use file_id in the same way as a plain hid_t object
+    
+    // pass ownership to a new handle object
+    HDF5Handle new_handle(file_id);
+    
+    assert(file_id.get() == 0);
     \endcode
 
     <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
@@ -156,7 +211,7 @@ public:
         It will be closed with the given close function \a destructor as soon as this 
         HDF5Handle is destructed, except when \a destructor is a NULL pointer (in which
         case nothing happens at destruction time). If \a h has a value that indicates
-        failed opening or creation (by HDF5 convention, this means if it is a negative number),
+        failed opening or creation (by HDF5 convention, this means that \a h is negative),
         an exception is raised by calling <tt>vigra_fail(error_message)</tt>.
 
         <b>Usage:</b>
@@ -178,7 +233,8 @@ public:
     }
 
         /** \brief Copy constructor.
-            Hands over ownership of the RHS handle (analogous to VIGRA_UNIQUE_PTR).
+        
+            Hands over ownership of the RHS handle (analogous to <tt>std::unique_pt</tt>).
         */
     HDF5Handle(HDF5Handle const & h)
     : handle_( h.handle_ ),
@@ -189,7 +245,7 @@ public:
     
         /** \brief Assignment.
             Calls close() for the LHS handle and hands over ownership of the 
-            RHS handle (analogous to VIGRA_UNIQUE_PTR).
+            RHS handle (analogous to <tt>std::unique_pt</tt>).
         */
     HDF5Handle & operator=(HDF5Handle const & h)
     {
@@ -211,8 +267,10 @@ public:
         close();
     }
     
-        /** \brief Explicitly call the stored function (if one has been stored within
-             this object) for the contained handle and set the handle to NULL.
+        /** \brief Explicitly call the stored destructor (if one has been registered in the
+             constructor) for the contained handle and set the wrapper to NULL. Returns
+             a negative value when the destructor call for the handle fails, and
+             a non-negative value otherwise.
         */
     herr_t close()
     {
@@ -220,8 +278,46 @@ public:
         if(handle_ && destructor_)
             res = (*destructor_)(handle_);
         handle_ = 0;
+        destructor_ = 0;
+        return res;
+    }
+    
+        /** \brief Return the contained handle and set the wrapper to NULL
+            without calling <tt>close()</tt>.
+        */
+    hid_t release()
+    {
+        hid_t res = handle_;
+        handle_ = 0;
+        destructor_ = 0;
         return res;
     }
+    
+        /** \brief Reset the wrapper to a new handle.
+        
+             Equivalent to <tt>handle = HDF5Handle(h, destructor, error_message)</tt>.
+        */
+    void reset(hid_t h, Destructor destructor, const char * error_message)
+    {
+        if(h < 0)
+            vigra_fail(error_message);
+        if(h != handle_)
+        {
+            close();
+            handle_ = h;
+            destructor_ = destructor;
+        }
+    }
+    
+        /** \brief Swap the contents of two handle wrappers.
+        
+            Also available as <tt>std::swap(handle1, handle2)</tt>.
+        */    
+    void swap(HDF5Handle & h)
+    {
+        std::swap(handle_, h.handle_);
+        std::swap(destructor_, h.destructor_);
+    }
 
         /** \brief Get a temporary hid_t object for the contained handle.
             Do not call a close function on the return value - a crash will be likely
@@ -272,6 +368,281 @@ public:
     }
 };
 
+
+    /** \brief Wrapper for shared hid_t objects.
+
+    This class offers the functionality of <tt>std::shared_ptr</tt> for HDF5 handles 
+    (type <tt>hid_t</tt>). Unfortunately, <tt>std::shared_ptr</tt> cannot be used directly 
+    for this purpose because it only works with pointers, whereas <tt>hid_t</tt> is an integer type.
+    
+    Newly created or opened HDF5 handles are stored as objects of type <tt>hid_t</tt>. When the handle
+    is no longer needed, the appropriate close function must be called. However, if a function is 
+    aborted by an exception, this is difficult to ensure. Class HDF5HandleShared is a smart pointer 
+    that solves this problem by calling the close function in the destructor of the handle's last 
+    owner (This is analogous to how <tt>std::shared_ptr</tt> calls 'delete' on the contained
+    pointer). A pointer to the close function must be passed to the constructor, along with an error 
+    message that is raised when creation/opening fails. 
+    
+    When a <tt>HDF5HandleShared</tt> is created or assigned from another one, ownership is shared
+    between the two handles, and the value returned by <tt>use_count()</tt> increases by one.
+    
+    Since <tt>HDF5HandleShared</tt> objects are convertible to <tt>hid_t</tt>, they can be used in the code 
+    in place of the latter.
+
+    <b>Usage:</b>
+
+    \code
+    HDF5HandleShared file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT), 
+                             &H5Fclose, 
+                             "Error message when H5Fopen() fails.");
+                       
+    ... // use file_id in the same way as a plain hid_t object
+    
+    // share ownership between same_id and file_id
+    HDF5HandleShared same_id(file_id);
+    assert(same_id.use_count() == 2);
+    assert(same_id.get() == file_id.get());
+    \endcode
+
+    <b>\#include</b> \<vigra/hdf5impex.hxx\><br>
+    Namespace: vigra
+    */
+class HDF5HandleShared
+{
+public:
+    typedef herr_t (*Destructor)(hid_t);
+    
+private:
+    hid_t handle_;
+    Destructor destructor_;
+    size_t * refcount_;
+    
+public:
+
+        /** \brief Default constructor.
+            Creates a NULL handle.
+        **/
+    HDF5HandleShared()
+    : handle_( 0 ),
+      destructor_(0),
+      refcount_(0)
+    {}
+
+        /** \brief Create a shared wrapper for a plain hid_t object.
+
+        The hid_t object \a h is assumed to be the return value of an open or create function.
+        It will be closed with the given close function \a destructor as soon as this 
+        HDF5HandleShared is destructed, except when \a destructor is a NULL pointer (in which
+        case nothing happens at destruction time). If \a h has a value that indicates
+        failed opening or creation (by HDF5 convention, this means that \a h is negative),
+        an exception is raised by calling <tt>vigra_fail(error_message)</tt>.
+
+        <b>Usage:</b>
+
+        \code
+        HDF5HandleShared file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT), 
+                                 &H5Fclose, 
+                                 "Error message.");
+                           
+        ... // use file_id in the same way
+        \endcode
+        */
+    HDF5HandleShared(hid_t h, Destructor destructor, const char * error_message)
+    : handle_( h ),
+      destructor_(destructor),
+      refcount_(0)
+    {
+        if(handle_ < 0)
+            vigra_fail(error_message);
+        if(handle_ > 0)
+            refcount_ = new size_t(1);
+    }
+
+        /** \brief Copy constructor.
+            Shares ownership with the RHS handle (analogous to <tt>std::shared_ptr</tt>).
+        */
+    HDF5HandleShared(HDF5HandleShared const & h)
+    : handle_( h.handle_ ),
+      destructor_(h.destructor_),
+      refcount_(h.refcount_)
+    {
+        if(refcount_)
+            ++(*refcount_);
+    }
+    
+        /** \brief Assignment.
+            Call close() for the present LHS handle and share ownership with the 
+            RHS handle (analogous to <tt>std::shared_ptr</tt>).
+        */
+    HDF5HandleShared & operator=(HDF5HandleShared const & h)
+    {
+        if(h.handle_ != handle_)
+        {
+            close();
+            handle_ = h.handle_;
+            destructor_ = h.destructor_;
+            refcount_ = h.refcount_;
+            if(refcount_)
+                ++(*refcount_);
+        }
+        return *this;
+    }
+
+        /** \brief Destructor (calls close())
+        */
+    ~HDF5HandleShared()
+    {
+        close();
+    }
+    
+        /** \brief Close the handle if this is the unique (i.e. last) owner. 
+        
+             Decrements the reference counter and calls the destructor function of 
+             the handle (if one has been registered in the constructor) when the counter
+             reaches zero. Sets this wrapper to NULL in any case. Returns
+             a negative value when the destructor call for the handle fails, and
+             a non-negative value otherwise.
+        */
+    herr_t close()
+    {
+        herr_t res = 1;
+        if(refcount_)
+        {
+            --(*refcount_);
+            if(*refcount_ == 0) 
+            {
+                if(destructor_)
+                    res = (*destructor_)(handle_);
+                delete refcount_;
+            }
+        }
+        handle_ = 0;
+        destructor_ = 0;
+        refcount_ = 0;
+        return res;
+    }
+    
+        /** \brief Reset the handle to a new value. 
+        
+             Equivalent to <tt>handle = HDF5HandleShared(h, destructor, error_message)</tt>.
+        */
+    void reset(hid_t h, Destructor destructor, const char * error_message)
+    {
+        if(h < 0)
+            vigra_fail(error_message);
+        if(h != handle_)
+        {
+            close();
+            handle_ = h;
+            destructor_ = destructor;
+            if(handle_ > 0)
+                refcount_ = new size_t(1);
+        }
+    }
+    
+        /** \brief Get the number of owners of the contained handle.
+        */
+    size_t use_count() const
+    {
+        return refcount_
+                 ? *refcount_
+                 : 0;
+    }
+    
+        /** \brief Check if this is the unique owner of the conatined handle.
+        
+            Equivalent to <tt>handle.use_count() == 1</tt>.
+        */
+    bool unique() const
+    {
+        return use_count() == 1;
+    }
+    
+        /** \brief Swap the contents of two handle wrappers.
+        
+            Also available as <tt>std::swap(handle1, handle2)</tt>.
+        */    
+    void swap(HDF5HandleShared & h)
+    {
+        std::swap(handle_, h.handle_);
+        std::swap(destructor_, h.destructor_);
+        std::swap(refcount_, h.refcount_);
+    }
+
+        /** \brief Get a temporary hid_t object for the contained handle.
+            Do not call a close function on the return value - a crash will be likely
+            otherwise.
+        */
+    hid_t get() const
+    {
+        return handle_;
+    }
+
+        /** \brief Convert to a plain hid_t object.
+
+        This function ensures that hid_t objects can be transparently replaced with 
+        HDF5HandleShared objects in user code. Do not call a close function on the return 
+        value - a crash will be likely otherwise.
+        */
+    operator hid_t() const
+    {
+        return handle_;
+    }
+
+        /** \brief Equality comparison of the contained handle.
+        */
+    bool operator==(HDF5HandleShared const & h) const
+    {
+        return handle_ == h.handle_;
+    }
+
+        /** \brief Equality comparison of the contained handle.
+        */
+    bool operator==(hid_t h) const
+    {
+        return handle_ == h;
+    }
+
+        /** \brief Inequality comparison of the contained handle.
+        */
+    bool operator!=(HDF5HandleShared const & h) const
+    {
+        return handle_ != h.handle_;
+    }
+
+        /** \brief Inequality comparison of the contained handle.
+        */
+    bool operator!=(hid_t h) const
+    {
+        return handle_ != h;
+    }
+};
+
+//@}
+
+} // namespace vigra
+
+namespace std {
+
+inline void swap(vigra::HDF5Handle & l, vigra::HDF5Handle & r)
+{
+    l.swap(r);
+}
+
+inline void swap(vigra::HDF5HandleShared & l, vigra::HDF5HandleShared & r)
+{
+    l.swap(r);
+}
+
+} // namespace std
+
+namespace vigra {
+
+/** \addtogroup VigraHDF5Impex
+*/
+//@{
+
+
 /********************************************************/
 /*                                                      */
 /*                   HDF5ImportInfo                     */
@@ -389,7 +760,7 @@ class HDF5ImportInfo
     VIGRA_EXPORT PixelType pixelType() const;
 
   private:
-    HDF5Handle m_file_handle, m_dataset_handle;
+    HDF5HandleShared m_file_handle, m_dataset_handle;
     std::string m_filename, m_path, m_pixeltype;
     hssize_t m_dimensions;
     ArrayVector<hsize_t> m_dims;
@@ -398,96 +769,118 @@ class HDF5ImportInfo
 
 namespace detail {
 
-template<class type>
+template <class T>
+struct HDF5TypeTraits
+{
+    static hid_t getH5DataType()
+    {
+        std::runtime_error("getH5DataType(): invalid type");
+        return 0;
+    }
+    
+    static int numberOfBands()
+    {
+        std::runtime_error("numberOfBands(): invalid type");
+        return 0;
+    }
+};
+
+template<class T>
 inline hid_t getH5DataType()
 {
-    std::runtime_error("getH5DataType(): invalid type");
-    return 0;
+    return HDF5TypeTraits<T>::getH5DataType();
 }
 
 #define VIGRA_H5_DATATYPE(type, h5type) \
-template<> \
-inline hid_t getH5DataType<type>() \
-{ return h5type;}
+template <> \
+struct HDF5TypeTraits<type> \
+{ \
+    static hid_t getH5DataType() \
+    { \
+        return h5type; \
+    } \
+    static int numberOfBands() \
+    { \
+        return 1; \
+    } \
+    typedef type value_type; \
+}; \
+template <int M> \
+struct HDF5TypeTraits<TinyVector<type, M> > \
+{ \
+    static hid_t getH5DataType() \
+    { \
+        return h5type; \
+    } \
+    static int numberOfBands() \
+    { \
+        return M; \
+    } \
+    typedef type value_type; \
+}; \
+template <> \
+struct HDF5TypeTraits<RGBValue<type> > \
+{ \
+    static hid_t getH5DataType() \
+    { \
+        return h5type; \
+    } \
+    static int numberOfBands() \
+    { \
+        return 3; \
+    } \
+    typedef type value_type; \
+}; \
 
 VIGRA_H5_DATATYPE(char, H5T_NATIVE_CHAR)
+VIGRA_H5_DATATYPE(signed char, H5T_NATIVE_SCHAR)
+VIGRA_H5_DATATYPE(unsigned char, H5T_NATIVE_UCHAR)
+VIGRA_H5_DATATYPE(signed short, H5T_NATIVE_SHORT)
+VIGRA_H5_DATATYPE(unsigned short, H5T_NATIVE_USHORT)
+VIGRA_H5_DATATYPE(signed int, H5T_NATIVE_INT)
+VIGRA_H5_DATATYPE(unsigned int, H5T_NATIVE_UINT)
+VIGRA_H5_DATATYPE(signed long, H5T_NATIVE_LONG)
+VIGRA_H5_DATATYPE(unsigned long, H5T_NATIVE_ULONG)
+VIGRA_H5_DATATYPE(signed long long, H5T_NATIVE_LLONG)
+VIGRA_H5_DATATYPE(unsigned long long, H5T_NATIVE_ULLONG)
 VIGRA_H5_DATATYPE(float, H5T_NATIVE_FLOAT)
 VIGRA_H5_DATATYPE(double, H5T_NATIVE_DOUBLE)
 VIGRA_H5_DATATYPE(long double, H5T_NATIVE_LDOUBLE)
 
 // char arrays with flexible length require 'handcrafted' H5 datatype
-template<>
-inline hid_t getH5DataType<char*>()
-{
-    hid_t stringtype = H5Tcopy (H5T_C_S1);
-    H5Tset_size(stringtype, H5T_VARIABLE);
-    return stringtype;
-}
-template<>
-inline hid_t getH5DataType<const char*>()
-{
-    hid_t stringtype = H5Tcopy (H5T_C_S1);
-    H5Tset_size(stringtype, H5T_VARIABLE);
-    return stringtype;
-}
-#undef VIGRA_H5_DATATYPE
-
-template <unsigned int SIZE>
-struct HDF5TypeBySize;
-
-template <>
-struct HDF5TypeBySize<1>
-{
-    static hid_t signed_type() { return H5T_NATIVE_INT8; }
-    static hid_t unsigned_type() { return H5T_NATIVE_UINT8; }
-};
-
-template <>
-struct HDF5TypeBySize<2>
-{
-    static hid_t signed_type() { return H5T_NATIVE_INT16; }
-    static hid_t unsigned_type() { return H5T_NATIVE_UINT16; }
-};
-
 template <>
-struct HDF5TypeBySize<4>
+struct HDF5TypeTraits<char*>
 {
-    static hid_t signed_type() { return H5T_NATIVE_INT32; }
-    static hid_t unsigned_type() { return H5T_NATIVE_UINT32; }
+    static hid_t getH5DataType()
+    {
+        hid_t stringtype = H5Tcopy (H5T_C_S1);
+        H5Tset_size(stringtype, H5T_VARIABLE);
+        return stringtype;
+    }
+    
+    static int numberOfBands()
+    {
+        return 1;
+    }
 };
 
 template <>
-struct HDF5TypeBySize<8>
+struct HDF5TypeTraits<const char*>
 {
-    static hid_t signed_type() { return H5T_NATIVE_INT64; }
-    static hid_t unsigned_type() { return H5T_NATIVE_UINT64; }
+    static hid_t getH5DataType()
+    {
+        hid_t stringtype = H5Tcopy (H5T_C_S1);
+        H5Tset_size(stringtype, H5T_VARIABLE);
+        return stringtype;
+    }
+    
+    static int numberOfBands()
+    {
+        return 1;
+    }
 };
 
-#define VIGRA_H5_SIGNED_DATATYPE(type) \
-template<> \
-inline hid_t getH5DataType<type>() \
-{ return HDF5TypeBySize<sizeof(type)>::signed_type(); }
-
-VIGRA_H5_SIGNED_DATATYPE(signed char)
-VIGRA_H5_SIGNED_DATATYPE(signed short)
-VIGRA_H5_SIGNED_DATATYPE(signed int)
-VIGRA_H5_SIGNED_DATATYPE(signed long)
-VIGRA_H5_SIGNED_DATATYPE(signed long long)
-
-#undef VIGRA_H5_SIGNED_DATATYPE
-
-#define VIGRA_H5_UNSIGNED_DATATYPE(type) \
-template<> \
-inline hid_t getH5DataType<type>() \
-{ return HDF5TypeBySize<sizeof(type)>::unsigned_type(); }
-
-VIGRA_H5_UNSIGNED_DATATYPE(unsigned char)
-VIGRA_H5_UNSIGNED_DATATYPE(unsigned short)
-VIGRA_H5_UNSIGNED_DATATYPE(unsigned int)
-VIGRA_H5_UNSIGNED_DATATYPE(unsigned long)
-VIGRA_H5_UNSIGNED_DATATYPE(unsigned long long)
-
-#undef VIGRA_H5_UNSIGNED_DATATYPE
+#undef VIGRA_H5_DATATYPE
 
 #if 0
 template<>
@@ -520,6 +913,7 @@ void HDF5_ls_insert(void*, const std::string &);
 
 VIGRA_EXPORT H5O_type_t HDF5_get_type(hid_t, const char*);
 extern "C" VIGRA_EXPORT herr_t HDF5_ls_inserter_callback(hid_t, const char*, const H5L_info_t*, void*);
+extern "C" VIGRA_EXPORT herr_t HDF5_listAttributes_inserter_callback(hid_t, const char*, const H5A_info_t*, void*);
 
 /********************************************************/
 /*                                                      */
@@ -562,7 +956,7 @@ Namespace: vigra
 class HDF5File
 {
   protected:
-    HDF5Handle fileHandle_;
+    HDF5HandleShared fileHandle_;
 
     // current group handle
     HDF5Handle cGroupHandle_;
@@ -570,14 +964,17 @@ class HDF5File
   private:
     // time tagging of datasets, turned off (= 0) by default.
     int track_time;
+    
+    bool read_only_;
 
-    // helper class for ls()
+    // helper classes for ls() and listAttributes()
     struct ls_closure
     {
         virtual void insert(const std::string &) = 0;
         virtual ~ls_closure() {}
     };
-    // datastructure to hold a list of dataset and group names
+    
+    // datastructure to hold a std::vector<std::string>
     struct lsOpData : public ls_closure
     {
         std::vector<std::string> & objects;
@@ -587,7 +984,8 @@ class HDF5File
             objects.push_back(x);
         }
     };
-    // (associative-)container closure
+    
+    // datastructure to hold an associative container
     template<class Container>
     struct ls_container_data : public ls_closure
     {
@@ -606,26 +1004,39 @@ class HDF5File
 
         /** \brief Set how a file is opened.
 
-            OpenMode::New creates a new file. If the file already exists, overwrite it.
+            OpenMode::New creates a new file. If the file already exists, it is overwritten.
 
-            OpenMode::Open opens a file for reading/writing. The file will be created,
-                           if necessary.
+            OpenMode::ReadWrite opens a file for reading/writing. The file will be created if it doesn't exist.
+            
+            OpenMode::ReadOnly opens a file for reading. The file as well as any dataset to be accessed must already exist.
         */
     enum OpenMode {
-        New,           // Create new empty file (existing file will be deleted).
-        Open,          // Open file. Create if not existing.
-        OpenReadOnly   // Open file in read-only mode.
+        New,              // Create new empty file (existing file will be deleted).
+        Open,             // Open file. Create if not existing.
+        ReadWrite = Open, // Alias for Open.
+        OpenReadOnly,     // Open file in read-only mode.
+        ReadOnly = OpenReadOnly, // Alias for OpenReadOnly
+        Replace,          // for ChunkedArrayHDF5: replace dataset if it exists, create otherwise
+        Default           // for ChunkedArrayHDF5: use New if file doesn't exist, 
+                          //                           ReadOnly if file and dataset exist
+                          //                           Open otherwise
     };
 
         /** \brief Default constructor.
 
-        A file can later be opened via the open() function.
-        
-        If \a track_creation_times is non-zero, time tagging of datasets will be enabled (it is disabled
-        by default).
+        A file can later be opened via the open() function. Time tagging of datasets is disabled.
+        */
+    HDF5File()
+    : track_time(0)
+    {}
+
+        /** \brief Construct with time tagging of datasets enabled.
+
+        If \a track_creation_times is 'true', time tagging of datasets will be enabled.
         */
-    HDF5File(int track_creation_times = 0)
-    : track_time(track_creation_times)
+    explicit HDF5File(bool track_creation_times)
+    : track_time(track_creation_times ? 1 : 0),
+      read_only_(true)
     {}
 
         /** \brief Open or create an HDF5File object.
@@ -636,10 +1047,64 @@ class HDF5File
         Note that the HDF5File class is not copyable (the copy constructor is 
         private to enforce this).
         */
-    HDF5File(std::string filename, OpenMode mode, int track_creation_times = 0)
-        : track_time(track_creation_times)
+    HDF5File(std::string filePath, OpenMode mode, bool track_creation_times = false)
+        : track_time(track_creation_times ? 1 : 0)
     {
-        open(filename, mode);
+        open(filePath, mode);
+    }
+
+        /** \brief Initialize an HDF5File object from HDF5 file handle
+
+        Initializes an HDF5File object corresponding to the HDF5 file
+        opened elsewhere. If \a fileHandle is constructed with a 
+        <tt>NULL</tt> destructor, ownership is not transferred
+        to the new HDF5File object, and you must ensure that the file is
+        not closed while the new HDF5File object is in use. Otherwise,
+        ownership will be shared.
+        
+        The current group is set to the specified \a pathname. If 
+        \a read_only is 'true', you cannot create new datasets or
+        overwrite data.
+
+        \warning In case the underlying HDF5 library used by Vigra is not
+        exactly the same library used to open the file with the given id,
+        this method will lead to crashes.
+        */
+    explicit HDF5File(HDF5HandleShared const & fileHandle,
+                      const std::string & pathname = "",
+                      bool read_only = false)
+    : fileHandle_(fileHandle),
+      read_only_(read_only)
+      
+    {
+        // get group handle for given pathname        
+        // calling openCreateGroup_ without setting a valid cGroupHandle does
+        // not work. Starting from root() is a safe bet.
+        root();
+        cGroupHandle_ = HDF5Handle(openCreateGroup_(pathname), &H5Gclose,
+                "HDF5File(fileHandle, pathname): Failed to open group");
+
+        // extract track_time attribute
+        hbool_t track_times_tmp;
+        HDF5Handle plist_id(H5Fget_create_plist(fileHandle_), &H5Pclose,
+                "HDF5File(fileHandle, pathname): Failed to open file creation property list");
+        herr_t status = H5Pget_obj_track_times(plist_id, &track_times_tmp );
+        vigra_postcondition(status >= 0,
+            "HDF5File(fileHandle, pathname): cannot access track time attribute");
+        track_time = track_times_tmp;
+    }
+
+        /** \brief Copy a HDF5File object.
+
+            The new object will refer to the same file and group as \a other.
+        */
+    HDF5File(HDF5File const & other)
+    : fileHandle_(other.fileHandle_),
+      track_time(other.track_time),
+      read_only_(other.read_only_)
+    {
+        cGroupHandle_ = HDF5Handle(openCreateGroup_(other.currentGroupName_()), &H5Gclose, 
+                                   "HDF5File(HDF5File const &): Failed to open group.");
     }
 
         /** \brief The destructor flushes and closes the file.
@@ -653,27 +1118,59 @@ class HDF5File
         // http://www.hdfgroup.org/HDF5/doc/RM/RM_H5F.html#File-Close .
     }
     
-    // copying is not permitted.
-  private:
-    HDF5File(const HDF5File &);
-    void operator=(const HDF5File &);
+        /** \brief Assign a HDF5File object.
 
-  public:
+            Calls close() on the present file and The new object will refer to the same file and group as \a other.
+        */
+    HDF5File & operator=(HDF5File const & other)
+    {
+        if(this != &other)
+        {
+            close();
+            fileHandle_ = other.fileHandle_;
+            cGroupHandle_ = HDF5Handle(openCreateGroup_(other.currentGroupName_()), &H5Gclose, 
+                                       "HDF5File::operator=(): Failed to open group.");
+            track_time = other.track_time;
+            read_only_ = other.read_only_;
+        }
+        return *this;
+    }
+
+    int file_use_count() const
+    {
+        return fileHandle_.use_count();
+    }
+    
+    bool isOpen() const
+    {
+        return fileHandle_ != 0;
+    }
+    
+    bool isReadOnly() const
+    {
+        return read_only_;
+    }
+    
+    void setReadOnly(bool stat=true)
+    {
+        read_only_ = stat;
+    }
   
         /** \brief Open or create the given file in the given mode and set the group to "/".
             If another file is currently open, it is first closed.
          */
-    void open(std::string filename, OpenMode mode)
+    void open(std::string filePath, OpenMode mode)
     {
         close();
         
-        std::string errorMessage = "HDF5File.open(): Could not open or create file '" + filename + "'.";
-        fileHandle_ = HDF5Handle(createFile_(filename, mode), &H5Fclose, errorMessage.c_str());
+        std::string errorMessage = "HDF5File.open(): Could not open or create file '" + filePath + "'.";
+        fileHandle_ = HDF5HandleShared(createFile_(filePath, mode), &H5Fclose, errorMessage.c_str());
         cGroupHandle_ = HDF5Handle(openCreateGroup_("/"), &H5Gclose, "HDF5File.open(): Failed to open root group.");
+        setReadOnly(mode == OpenReadOnly);
     }
 
         /** \brief Close the current file.
-         */
+        */
     void close()
     {
         bool success = cGroupHandle_.close() >= 0 && fileHandle_.close() >= 0;
@@ -745,6 +1242,9 @@ class HDF5File
         */
     inline void mkdir(std::string groupName)
     {
+        vigra_precondition(!isReadOnly(),
+            "HDF5File::mkdir(): file is read-only.");
+        
         std::string message = "HDF5File::mkdir(): Could not create group '" + groupName + "'.\n";
 
         // make groupName clean
@@ -759,6 +1259,9 @@ class HDF5File
         */
     inline void cd_mk(std::string groupName)
     {
+        vigra_precondition(!isReadOnly(),
+            "HDF5File::cd_mk(): file is read-only.");
+        
         std::string  message = "HDF5File::cd_mk(): Could not create group '" + groupName + "'.";
 
         // make groupName clean
@@ -823,7 +1326,7 @@ class HDF5File
 
         /** \brief Check if given datasetName exists.
         */
-    inline bool existsDataset(std::string datasetName)
+    inline bool existsDataset(std::string datasetName) const
     {
         // make datasetName clean
         datasetName = get_absolute_path(datasetName);
@@ -834,17 +1337,17 @@ class HDF5File
              If the first character is a "/", the path will be interpreted as absolute path,
              otherwise it will be interpreted as path relative to the current group.
         */
-    hssize_t getDatasetDimensions(std::string datasetName)
+    hssize_t getDatasetDimensions(std::string datasetName) const
     {
-        // make datasetName clean
-        datasetName = get_absolute_path(datasetName);
+        HDF5Handle datasetHandle = getDatasetHandle(datasetName);
 
-        //Open dataset and dataspace
-        std::string errorMessage = "HDF5File::getDatasetDimensions(): Unable to open dataset '" + datasetName + "'.";
-        HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
+        return getDatasetDimensions_(datasetHandle);
+    }
 
-        errorMessage = "HDF5File::getDatasetDimensions(): Unable to access dataspace.";
-        HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, errorMessage.c_str());
+    hssize_t getDatasetDimensions_(hid_t dataset) const
+    {
+        std::string errorMessage = "HDF5File::getDatasetDimensions(): Unable to access dataspace.";
+        HDF5Handle dataspaceHandle(H5Dget_space(dataset), &H5Sclose, errorMessage.c_str());
 
         //return dimension information
         return H5Sget_simple_extent_ndims(dataspaceHandle);
@@ -863,7 +1366,7 @@ class HDF5File
             ordered as 'z', 'y', 'x', this function will return the shape in the order
             'x', 'y', 'z'.
         */
-    ArrayVector<hsize_t> getDatasetShape(std::string datasetName)
+    ArrayVector<hsize_t> getDatasetShape(std::string datasetName) const
     {
         // make datasetName clean
         datasetName = get_absolute_path(datasetName);
@@ -904,7 +1407,7 @@ class HDF5File
             <DT>"UNKNOWN"<DD> any other type
             </DL>
          */
-    std::string getDatasetType(std::string const & datasetName)
+    std::string getDatasetType(std::string const & datasetName) const
     {
         HDF5Handle datasetHandle = getDatasetHandle(datasetName);
 
@@ -950,15 +1453,24 @@ class HDF5File
         
         /** \brief Obtain the HDF5 handle of a dataset.
         */
-    inline HDF5Handle getDatasetHandle(std::string const & datasetName)
+    HDF5Handle getDatasetHandle(std::string const & datasetName) const
     {
         std::string errorMessage = "HDF5File::getDatasetHandle(): Unable to open dataset '" + datasetName + "'.";
         return HDF5Handle(getDatasetHandle_(get_absolute_path(datasetName)), &H5Dclose, errorMessage.c_str());
     }
+        
+        /** \brief Obtain a shared HDF5 handle of a dataset.
+        */
+    HDF5HandleShared getDatasetHandleShared(std::string const & datasetName) const
+    {
+        std::string errorMessage = "HDF5File::getDatasetHandle(): Unable to open dataset '" + datasetName + "'.";
+        return HDF5HandleShared(getDatasetHandle_(get_absolute_path(datasetName)), &H5Dclose, errorMessage.c_str());
+    }
 
-        /** \brief Obtain the HDF5 handle of a group.
+        /** \brief Obtain the HDF5 handle of a group (create the group if it doesn't exist).
          */
-    inline HDF5Handle getGroupHandle(std::string group_name, std::string function_name = "HDF5File::getGroupHandle()")
+    HDF5Handle getGroupHandle(std::string group_name, 
+                              std::string function_name = "HDF5File::getGroupHandle()")
     {
         std::string errorMessage = function_name + ": Group '" + group_name + "' not found.";
 
@@ -973,9 +1485,54 @@ class HDF5File
         return HDF5Handle(openCreateGroup_(group_name), &H5Gclose, "Internal error");
     }
 
+        // helper function for the various listAttributes() variants.
+    void ls_H5Aiterate(std::string const & group_or_dataset, ls_closure & data) const
+    {
+        H5O_type_t h5_type = get_object_type_(group_or_dataset);
+        vigra_precondition(h5_type == H5O_TYPE_GROUP || h5_type == H5O_TYPE_DATASET, 
+            "HDF5File::listAttributes(): object \"" + group_or_dataset + "\" is neither a group nor a dataset.");
+        // get object handle
+        HDF5Handle object_handle(h5_type == H5O_TYPE_GROUP
+                                     ? const_cast<HDF5File*>(this)->openCreateGroup_(group_or_dataset)
+                                     : getDatasetHandle_(group_or_dataset),
+                                 h5_type == H5O_TYPE_GROUP
+                                     ? &H5Gclose
+                                     : &H5Dclose,
+                                 "HDF5File::listAttributes(): unable to open object.");
+        hsize_t n = 0;
+        H5Aiterate2(object_handle, H5_INDEX_NAME, H5_ITER_NATIVE, &n,
+                    HDF5_listAttributes_inserter_callback, static_cast<void*>(&data));
+    }
+
+        /** \brief List the attribute names of the given group or dataset.
+        
+            If \a group_or_dataset is empty or <tt>"."</tt> (a dot), the command
+            refers to the current group of this file object.
+        */
+    inline std::vector<std::string> listAttributes(std::string const & group_or_dataset) const
+    {
+        std::vector<std::string> list;
+        lsOpData data(list);
+        ls_H5Aiterate(group_or_dataset, data);
+        return list;
+    }
+
+        /** \brief Insert the attribute names of the given group or dataset into the given 
+                   \a container by calling <tt>container.insert(std::string)</tt>.
+        
+            If \a group_or_dataset is empty or <tt>"."</tt> (a dot), the command
+            refers to the current group of this file object.
+        */
+    template<class Container>
+    void listAttributes(std::string const & group_or_dataset, Container & container) const
+    {
+        ls_container_data<Container> data(container);
+        ls_H5Aiterate(group_or_dataset, data);
+    }
+
         /** \brief Obtain the HDF5 handle of a attribute.
          */
-    inline HDF5Handle getAttributeHandle(std::string dataset_name, std::string attribute_name)
+    HDF5Handle getAttributeHandle(std::string dataset_name, std::string attribute_name) const
     {
         std::string message = "HDF5File::getAttributeHandle(): Attribute '" + attribute_name + "' not found.";
         return HDF5Handle(H5Aopen(getDatasetHandle(dataset_name), attribute_name.c_str(), H5P_DEFAULT),
@@ -1228,8 +1785,19 @@ class HDF5File
     {
         // make datasetName clean
         datasetName = get_absolute_path(datasetName);
+        typedef detail::HDF5TypeTraits<T> TypeTraits;
+        writeBlock_(datasetName, blockOffset, array, 
+                    TypeTraits::getH5DataType(), TypeTraits::numberOfBands());
+    }
 
-        writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<T>(), 1);
+    template<unsigned int N, class T, class Stride>
+    inline herr_t writeBlock(HDF5HandleShared dataset, 
+                             typename MultiArrayShape<N>::type blockOffset, 
+                             const MultiArrayView<N, T, Stride> & array)
+    {
+        typedef detail::HDF5TypeTraits<T> TypeTraits;
+        return writeBlock_(dataset, blockOffset, array, 
+                           TypeTraits::getH5DataType(), TypeTraits::numberOfBands());
     }
 
     // non-scalar (TinyVector) and unstrided multi arrays
@@ -1275,22 +1843,11 @@ class HDF5File
                       int compression = 0)
     {
         // convert to a (trivial) MultiArrayView and forward.
-        MultiArrayShape<1>::type shape(array.size());
+        MultiArrayShape<1>::type shape(static_cast<MultiArrayIndex>(array.size()));
         const MultiArrayView<1, T> m_array(shape, const_cast<T*>(array.data()));
         write(datasetName, m_array, compression);
     }
 
-    template<unsigned int N, class T, int SIZE, class Stride>
-    inline void writeBlock(std::string datasetName, 
-                           typename MultiArrayShape<N>::type blockOffset, 
-                           const MultiArrayView<N, TinyVector<T, SIZE>, Stride> & array)
-    {
-        // make datasetName clean
-        datasetName = get_absolute_path(datasetName);
-
-        writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<T>(), SIZE);
-    }
-
     // non-scalar (RGBValue) and unstrided multi arrays
     template<unsigned int N, class T, class Stride>
     inline void write(std::string datasetName, 
@@ -1318,17 +1875,6 @@ class HDF5File
         write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize, compression);
     }
 
-    template<unsigned int N, class T, class Stride>
-    inline void writeBlock(std::string datasetName, 
-                           typename MultiArrayShape<N>::type blockOffset, 
-                           const MultiArrayView<N, RGBValue<T>, Stride> & array)
-    {
-        // make datasetName clean
-        datasetName = get_absolute_path(datasetName);
-
-        writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<T>(), 3);
-    }
-
          /** \brief Write a single value.
             Specialization of the write function for simple datatypes
          */
@@ -1393,8 +1939,8 @@ class HDF5File
 
         // reshape target MultiArray
         typename MultiArrayShape<N>::type shape;
-        for(int k=0; k < (int)dimshape.size(); ++k)
-            shape[k] = (MultiArrayIndex)dimshape[k];
+        for(int k=0; k < static_cast<int>(dimshape.size()); ++k)
+            shape[k] = static_cast<MultiArrayIndex>(dimshape[k]);
         array.reshape(shape);
 
         read_(datasetName, array, detail::getH5DataType<T>(), 1);
@@ -1434,7 +1980,7 @@ class HDF5File
         // resize target array vector
         array.resize((typename ArrayVector<T>::size_type)dimshape[0]);
         // convert to a (trivial) MultiArrayView and forward.
-        MultiArrayShape<1>::type shape(array.size());
+        MultiArrayShape<1>::type shape(static_cast<MultiArrayIndex>(array.size()));
         MultiArrayView<1, T> m_array(shape, (array.data()));
 
         read_(datasetName, m_array, detail::getH5DataType<T>(), 1);
@@ -1463,8 +2009,20 @@ class HDF5File
     {
         // make datasetName clean
         datasetName = get_absolute_path(datasetName);
+        typedef detail::HDF5TypeTraits<T> TypeTraits;
+        readBlock_(datasetName, blockOffset, blockShape, array, 
+                   TypeTraits::getH5DataType(), TypeTraits::numberOfBands());
+    }
 
-        readBlock_(datasetName, blockOffset, blockShape, array, detail::getH5DataType<T>(), 1);
+    template<unsigned int N, class T, class Stride>
+    inline herr_t readBlock(HDF5HandleShared dataset, 
+                          typename MultiArrayShape<N>::type blockOffset, 
+                          typename MultiArrayShape<N>::type blockShape, 
+                          MultiArrayView<N, T, Stride> array)
+    {
+        typedef detail::HDF5TypeTraits<T> TypeTraits;
+        return readBlock_(dataset, blockOffset, blockShape, array, 
+                          TypeTraits::getH5DataType(), TypeTraits::numberOfBands());
     }
 
     // non-scalar (TinyVector) and unstrided target MultiArrayView
@@ -1494,25 +2052,13 @@ class HDF5File
         
         // reshape target MultiArray
         typename MultiArrayShape<N>::type shape;
-        for(int k=1; k < (int)dimshape.size(); ++k)
-            shape[k-1] = (MultiArrayIndex)dimshape[k];
+        for(int k=1; k < static_cast<int>(dimshape.size()); ++k)
+            shape[k-1] = static_cast<MultiArrayIndex>(dimshape[k]);
         array.reshape(shape);
 
         read_(datasetName, array, detail::getH5DataType<T>(), SIZE);
     }
 
-    template<unsigned int N, class T, int SIZE, class Stride>
-    inline void readBlock(std::string datasetName, 
-                          typename MultiArrayShape<N>::type blockOffset, 
-                          typename MultiArrayShape<N>::type blockShape, 
-                          MultiArrayView<N, TinyVector<T, SIZE>, Stride> array)
-    {
-        // make datasetName clean
-        datasetName = get_absolute_path(datasetName);
-
-        readBlock_(datasetName, blockOffset, blockShape, array, detail::getH5DataType<T>(), SIZE);
-    }
-
     // non-scalar (RGBValue) and unstrided target MultiArrayView
     template<unsigned int N, class T, class Stride>
     inline void read(std::string datasetName, MultiArrayView<N, RGBValue<T>, Stride> array)
@@ -1540,25 +2086,13 @@ class HDF5File
 
         // reshape target MultiArray
         typename MultiArrayShape<N>::type shape;
-        for(int k=1; k < (int)dimshape.size(); ++k)
-            shape[k-1] = (MultiArrayIndex)dimshape[k];
+        for(int k=1; k < static_cast<int>(dimshape.size()); ++k)
+            shape[k-1] = static_cast<MultiArrayIndex>(dimshape[k]);
         array.reshape(shape);
 
         read_(datasetName, array, detail::getH5DataType<T>(), 3);
     }
 
-    template<unsigned int N, class T, class Stride>
-    inline void readBlock(std::string datasetName, 
-                          typename MultiArrayShape<N>::type blockOffset, 
-                          typename MultiArrayShape<N>::type blockShape, 
-                          MultiArrayView<N, RGBValue<T>, Stride> array)
-    {
-        // make datasetName clean
-        datasetName = get_absolute_path(datasetName);
-
-        readBlock_(datasetName, blockOffset, blockShape, array, detail::getH5DataType<T>(), 3);
-    }
-
         /** \brief Read a single value.
             Specialization of the read function for simple datatypes
          */
@@ -1579,10 +2113,8 @@ class HDF5File
     inline void read(std::string datasetName, std::string &data) { readAtomic(datasetName,data); }
 
         /** \brief Create a new dataset.
-            This function can be used to create a dataset filled with a default value,
+            This function can be used to create a dataset filled with a default value \a init,
             for example before writing data into it using \ref writeBlock().
-            Attention: only atomic datatypes are provided. For spectral data, add an
-            dimension (case RGB: add one dimension of size 3).
 
             shape determines the dimension and the size of the dataset.
 
@@ -1592,7 +2124,9 @@ class HDF5File
             Compression can be activated by setting 
             \code compression = parameter; // 0 \< parameter \<= 9 
             \endcode
-            where 0 stands for no compression and 9 for maximum compression.
+            where 0 stands for no compression and 9 for maximum compression. If 
+            a non-zero compression level is specified, but the chunk size is zero,
+            a default chunk size will be chosen (compression always requires chunks).
 
             If the first character of datasetName is a "/", the path will be interpreted as absolute path,
             otherwise it will be interpreted as path relative to the current group.
@@ -1602,80 +2136,34 @@ class HDF5File
             whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
             upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'. 
         */
-    template<unsigned int N, class T>
-    inline void createDataset(std::string datasetName, 
-                              typename MultiArrayShape<N>::type shape, 
-                              T init = T(), 
-                              int iChunkSize = 0, 
-                              int compressionParameter = 0)
-    {
-        // make datasetName clean
-        datasetName = get_absolute_path(datasetName);
+    template<int N, class T>
+    HDF5HandleShared 
+    createDataset(std::string datasetName, 
+                  TinyVector<MultiArrayIndex, N> const & shape, 
+                  typename detail::HDF5TypeTraits<T>::value_type init = 
+                                                     typename detail::HDF5TypeTraits<T>::value_type(), 
+#ifdef _MSC_VER
+                  TinyVector<MultiArrayIndex, N> const & chunkSize = TinyVector<MultiArrayIndex, N>(), 
+#else
+                  TinyVector<MultiArrayIndex, N> const & chunkSize = (TinyVector<MultiArrayIndex, N>()), 
+#endif
+                  int compressionParameter = 0);
 
+        // for backwards compatibility
+    template<int N, class T>
+    HDF5HandleShared 
+    createDataset(std::string datasetName, 
+                  TinyVector<MultiArrayIndex, N> const & shape, 
+                  T init, 
+                  int iChunkSize, 
+                  int compressionParameter = 0)
+    {
         typename MultiArrayShape<N>::type chunkSize;
         for(int i = 0; i < N; i++){
             chunkSize[i] = iChunkSize;
         }
-        createDataset<N,T>(datasetName, shape, init, chunkSize, compressionParameter);
-    }
-
-    template<unsigned int N, class T>
-    inline void createDataset(std::string datasetName, 
-                              typename MultiArrayShape<N>::type shape, 
-                              T init, 
-                              typename MultiArrayShape<N>::type chunkSize, 
-                              int compressionParameter = 0)
-    {
-        // make datasetName clean
-        datasetName = get_absolute_path(datasetName);
-
-        std::string groupname = SplitString(datasetName).first();
-        std::string setname = SplitString(datasetName).last();
-
-        hid_t parent = openCreateGroup_(groupname);
-
-        // delete the dataset if it already exists
-        deleteDataset_(parent, setname);
-
-        // create dataspace
-        // add an extra dimension in case that the data is non-scalar
-        HDF5Handle dataspaceHandle;
-
-        // invert dimensions to guarantee c-order
-        hsize_t shape_inv[N];
-        for(unsigned int k=0; k<N; ++k)
-            shape_inv[N-1-k] = shape[k];
-
-        // create dataspace
-        dataspaceHandle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
-                                    &H5Sclose, "HDF5File::createDataset(): unable to create dataspace for scalar data.");
-
-        // set fill value
-        HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5File::createDataset(): unable to create property list." );
-        H5Pset_fill_value(plist,detail::getH5DataType<T>(), &init);
-
-        // turn off time tagging of datasets by default.
-        H5Pset_obj_track_times(plist, track_time);
-
-        // enable chunks
-        ArrayVector<hsize_t> chunks(defineChunks(chunkSize, shape, 1, compressionParameter));
-        if(chunks.size() > 0)
-        {
-            std::reverse(chunks.begin(), chunks.end());
-            H5Pset_chunk (plist, chunks.size(), chunks.begin());
-        }
-
-        // enable compression
-        if(compressionParameter > 0)
-        {
-            H5Pset_deflate(plist, compressionParameter);
-        }
-
-        //create the dataset.
-        HDF5Handle datasetHandle ( H5Dcreate(parent, setname.c_str(), detail::getH5DataType<T>(), dataspaceHandle, H5P_DEFAULT, plist, H5P_DEFAULT),
-                                  &H5Dclose, "HDF5File::createDataset(): unable to create dataset.");
-        if(parent != cGroupHandle_)
-            H5Gclose(parent);
+        return this->template createDataset<N, T>(datasetName, shape, init, 
+                                                  chunkSize, compressionParameter);
     }
 
         /** \brief Immediately write all data to disk
@@ -1702,46 +2190,41 @@ class HDF5File
         // return the part of the string before the delimiter
         std::string first(char delimiter = '/')
         {
-            size_t last = find_last_of(delimiter);
-            if(last == std::string::npos) // delimiter not found --> no first
+            size_t lastPos = find_last_of(delimiter);
+            if(lastPos == std::string::npos) // delimiter not found --> no first
                 return "";
 
-            return std::string(begin(), begin()+last+1);
+            return std::string(begin(), begin()+lastPos+1);
         }
 
         // return the part of the string after the delimiter
         std::string last(char delimiter = '/')
         {
-            size_t last = find_last_of(delimiter);
-            if(last == std::string::npos) // delimiter not found --> only last
+            size_t lastPos = find_last_of(delimiter);
+            if(lastPos == std::string::npos) // delimiter not found --> only last
                 return std::string(*this);
-            return std::string(begin()+last+1, end());
+            return std::string(begin()+lastPos+1, end());
         }
     };
     
     template <class Shape>
     ArrayVector<hsize_t> 
-    defineChunks(Shape const & chunks, Shape const & shape, int numBands, int compression = 0)
+    defineChunks(Shape chunks, Shape const & shape, int numBands, int compression = 0)
     {
-        if(chunks[0] > 0)
+        if(prod(chunks) > 0)
         {
             ArrayVector<hsize_t> res(chunks.begin(), chunks.end());
             if(numBands > 1)
-                res.insert(res.begin(), numBands);
+                res.insert(res.begin(), static_cast<hsize_t>(numBands));
             return res;
         }
         else if(compression > 0)
         {
-            // set default chunks to enable compression 
-            // (arbitrarily include about 300k pixels into each chunk, but make sure
-            //  that the chunk size doesn't exceed the shape)
-            ArrayVector<hsize_t> res(shape.begin(), shape.end());
-            hsize_t chunk_length = (hsize_t)std::pow(300000.0, 1.0 / shape.size());
-            for(unsigned int k=0; k < shape.size(); ++k)
-                if(res[k] > chunk_length)
-                    res[k] = chunk_length;
+            // set default chunks to enable compression
+            chunks = min(detail::ChunkShape<Shape::static_size>::defaultShape(), shape);
+            ArrayVector<hsize_t> res(chunks.begin(), chunks.end());
             if(numBands > 1)
-                res.insert(res.begin(), numBands);
+                res.insert(res.begin(), static_cast<hsize_t>(numBands));
             return res;
         }
         else
@@ -1854,7 +2337,7 @@ class HDF5File
         return std::string(name.begin());
     }
 
-        /* create an empty file and open is
+        /* create an empty file or open an existing one
          */
     inline hid_t createFile_(std::string filePath, OpenMode mode = Open)
     {
@@ -1866,29 +2349,49 @@ class HDF5File
         // check if opening was successful (= file exists)
         if ( pFile == NULL )
         {
+            vigra_precondition(mode != OpenReadOnly,
+                "HDF5File::open(): cannot open non-existing file in read-only mode.");
             fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
         }
-        else if(mode == Open)
-        {
-            fclose( pFile );
-            fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
-        }
-        else if(mode == OpenReadOnly) {
-            fclose( pFile );
-            fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
-        }
-        else
+        else 
         {
             fclose(pFile);
-            std::remove(filePath.c_str());
-            fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
+            if(mode == OpenReadOnly) 
+            {
+                fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
+            }
+            else if(mode == New)
+            {
+                std::remove(filePath.c_str());
+                fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
+            }
+            else
+            {
+                fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
+            }
         }
         return fileId;
     }
 
-        /* open a group and subgroups. Create if necessary.
+        /* \brief Open a group. 
+        
+           A negative value is returned when the group does not exist or when opening 
+           fails for other reasons.
+         */
+    hid_t openGroup_(std::string groupName) const
+    {
+        return const_cast<HDF5File *>(this)->openCreateGroup_(groupName, false);
+    }
+
+        /* \brief Open or create a group. 
+        
+           If \a create is <tt>true</tt> and the group does not exist, it will be created, 
+           including all necessary parent groups. If group creation fails, a negative
+           value is returned. Likewise, a negative value is returned when \a create
+           is <tt>false</tt> and the group does not exist or when opening of the group 
+           fails for other reasons.
          */
-    inline hid_t openCreateGroup_(std::string groupName)
+    hid_t openCreateGroup_(std::string groupName, bool create = true)
     {
         // make groupName clean
         groupName = get_absolute_path(groupName);
@@ -1918,8 +2421,13 @@ class HDF5File
 
             if(H5LTfind_dataset(parent, group.c_str()) == 0)
             {
-                parent = H5Gcreate(prevParent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
-            } else {
+                if(create)
+                    parent = H5Gcreate(prevParent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+                else
+                    parent = -1;
+            } 
+            else 
+            {
                 parent = H5Gopen(prevParent, group.c_str(), H5P_DEFAULT);
             }
             H5Gclose(prevParent);
@@ -1960,7 +2468,7 @@ class HDF5File
 
         /* get the handle of a dataset specified by a string
          */
-    inline hid_t getDatasetHandle_(std::string datasetName)
+    hid_t getDatasetHandle_(std::string datasetName) const
     {
         // make datasetName clean
         datasetName = get_absolute_path(datasetName);
@@ -1975,14 +2483,14 @@ class HDF5File
         }
 
         // Open parent group
-        HDF5Handle groupHandle(openCreateGroup_(groupname), &H5Gclose, "HDF5File::getDatasetHandle_(): Internal error");
+        HDF5Handle groupHandle(openGroup_(groupname), &H5Gclose, "HDF5File::getDatasetHandle_(): Internal error");
 
         return H5Dopen(groupHandle, setname.c_str(), H5P_DEFAULT);
     }
 
         /* get the type of an object specified by a string
          */
-    H5O_type_t get_object_type_(std::string name)
+    H5O_type_t get_object_type_(std::string name) const
     {
         name = get_absolute_path(name);
         std::string group_name = SplitString(name).first();
@@ -1995,7 +2503,7 @@ class HDF5File
                                         "object \"" + name + "\" "
                                         "not found.");
         // open parent group
-        HDF5Handle group_handle(openCreateGroup_(group_name), &H5Gclose, "Internal error");
+        HDF5Handle group_handle(openGroup_(group_name), &H5Gclose, "Internal error");
         return HDF5_get_type(group_handle, name.c_str());
     }
 
@@ -2134,7 +2642,26 @@ class HDF5File
                      typename MultiArrayShape<N>::type &blockOffset, 
                      const MultiArrayView<N, T, Stride> & array, 
                      const hid_t datatype, 
-                     const int numBandsOfType);
+                     const int numBandsOfType)
+    {
+        // open dataset if it exists
+        std::string errorMessage = "HDF5File::writeBlock(): Error opening dataset '" + datasetName + "'.";
+        HDF5HandleShared dataset(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
+        herr_t status = writeBlock_(dataset, blockOffset, array, datatype, numBandsOfType);
+        vigra_postcondition(status >= 0,
+            "HDF5File::writeBlock(): write to dataset '" + datasetName + "' via H5Dwrite() failed.");
+    }
+
+       /* low-level write function to write vigra unstrided MultiArray data into a 
+          sub-block of a dataset.  Returns the result of the internal call
+           to <tt>H5Dwrite()</tt>.
+       */
+    template<unsigned int N, class T, class Stride>
+    herr_t writeBlock_(HDF5HandleShared dataset, 
+                       typename MultiArrayShape<N>::type &blockOffset, 
+                       const MultiArrayView<N, T, Stride> & array, 
+                       const hid_t datatype, 
+                       const int numBandsOfType);
 
         /* low-level read function to read vigra unstrided MultiArray data from a sub-block of a dataset.
         
@@ -2144,12 +2671,109 @@ class HDF5File
     void readBlock_(std::string datasetName, 
                     typename MultiArrayShape<N>::type &blockOffset, 
                     typename MultiArrayShape<N>::type &blockShape, 
-                    MultiArrayView<N, T, Stride> &array, 
-                    const hid_t datatype, const int numBandsOfType);
+                    MultiArrayView<N, T, Stride> array, 
+                    const hid_t datatype, const int numBandsOfType)
+    {
+        std::string errorMessage ("HDF5File::readBlock(): Unable to open dataset '" + datasetName + "'.");
+        HDF5HandleShared dataset(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
+        herr_t status = readBlock_(dataset, blockOffset, blockShape, array, datatype, numBandsOfType);
+        vigra_postcondition(status >= 0,
+            "HDF5File::readBlock(): read from dataset '" + datasetName + "' via H5Dread() failed.");
+    }
+
+        /* low-level read function to read vigra unstrided MultiArray data from a sub-block of a dataset.
+        
+           The array must have the same shape as the block. Returns the result of the internal call
+           to <tt>H5Dread()</tt>.
+        */
+    template<unsigned int N, class T, class Stride>
+    herr_t readBlock_(HDF5HandleShared dataset, 
+                      typename MultiArrayShape<N>::type &blockOffset, 
+                      typename MultiArrayShape<N>::type &blockShape, 
+                      MultiArrayView<N, T, Stride> array, 
+                      const hid_t datatype, const int numBandsOfType);
 };  /* class HDF5File */
 
 /********************************************************************/
 
+template<int N, class T>
+HDF5HandleShared 
+HDF5File::createDataset(std::string datasetName, 
+                        TinyVector<MultiArrayIndex, N> const & shape, 
+                        typename detail::HDF5TypeTraits<T>::value_type init, 
+                         TinyVector<MultiArrayIndex, N> const & chunkSize, 
+                         int compressionParameter)
+{
+    vigra_precondition(!isReadOnly(),
+        "HDF5File::createDataset(): file is read-only.");
+    
+    // make datasetName clean
+    datasetName = get_absolute_path(datasetName);
+
+    std::string groupname = SplitString(datasetName).first();
+    std::string setname = SplitString(datasetName).last();
+
+    hid_t parent = openCreateGroup_(groupname);
+
+    // delete the dataset if it already exists
+    deleteDataset_(parent, setname);
+
+    // invert dimensions to guarantee c-order
+    // add an extra dimension in case that the data is non-scalar
+    typedef detail::HDF5TypeTraits<T> TypeTraits;
+    ArrayVector<hsize_t> shape_inv;
+    if(TypeTraits::numberOfBands() > 1)
+    {
+        shape_inv.resize(N+1);
+        shape_inv[N] = TypeTraits::numberOfBands();
+    }
+    else
+    {
+        shape_inv.resize(N);
+    }
+    for(int k=0; k<N; ++k)
+        shape_inv[N-1-k] = shape[k];
+
+    // create dataspace
+    HDF5Handle 
+    dataspaceHandle = HDF5Handle(H5Screate_simple(shape_inv.size(), shape_inv.data(), NULL),
+                                &H5Sclose, "HDF5File::createDataset(): unable to create dataspace for scalar data.");
+
+    // set fill value
+    HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5File::createDataset(): unable to create property list." );
+    H5Pset_fill_value(plist, TypeTraits::getH5DataType(), &init);
+
+    // turn off time tagging of datasets by default.
+    H5Pset_obj_track_times(plist, track_time);
+
+    // enable chunks
+    ArrayVector<hsize_t> chunks(defineChunks(chunkSize, shape, TypeTraits::numberOfBands(), compressionParameter));
+    if(chunks.size() > 0)
+    {
+        std::reverse(chunks.begin(), chunks.end());
+        H5Pset_chunk (plist, chunks.size(), chunks.begin());
+    }
+
+    // enable compression
+    if(compressionParameter > 0)
+    {
+        H5Pset_deflate(plist, compressionParameter);
+    }
+
+    //create the dataset.
+    HDF5HandleShared datasetHandle(H5Dcreate(parent, setname.c_str(), 
+                                             TypeTraits::getH5DataType(), 
+                                             dataspaceHandle, H5P_DEFAULT, plist, H5P_DEFAULT),
+                                   &H5Dclose, 
+                                   "HDF5File::createDataset(): unable to create dataset.");
+    if(parent != cGroupHandle_)
+        H5Gclose(parent);
+        
+    return datasetHandle;
+}
+
+/********************************************************************/
+
 template<unsigned int N, class T, class Stride>
 void HDF5File::write_(std::string &datasetName, 
                       const MultiArrayView<N, T, Stride> & array, 
@@ -2158,6 +2782,9 @@ void HDF5File::write_(std::string &datasetName,
                       typename MultiArrayShape<N>::type &chunkSize, 
                       int compressionParameter)
 {
+    vigra_precondition(!isReadOnly(),
+        "HDF5File::write(): file is read-only.");
+        
     std::string groupname = SplitString(datasetName).first();
     std::string setname = SplitString(datasetName).last();
 
@@ -2250,7 +2877,7 @@ void HDF5File::write_(std::string &datasetName,
         for(unsigned int k=offset; k<chunks.size(); ++k)
         {
             chunkMaxShape[k-offset] = chunks[k];
-            chunkCount[k-offset] = (MultiArrayIndex)std::ceil(double(shape[k]) / chunks[k]);
+            chunkCount[k-offset] = static_cast<MultiArrayIndex>(std::ceil(double(shape[k]) / chunks[k]));
         }
         
         typename CoupledIteratorType<N>::type chunkIter = createCoupledIterator(chunkCount),
@@ -2277,13 +2904,13 @@ void HDF5File::write_(std::string &datasetName,
             if(status < 0)
                 break;
                 
-            HDF5Handle dataspace(H5Screate_simple(count.size(), count.data(), NULL),
+            HDF5Handle dataspace2(H5Screate_simple(count.size(), count.data(), NULL),
                                  &H5Sclose, "HDF5File::write(): unable to create hyperslabs."); 
-            status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, null.data(), NULL, count.data(), NULL);
+            status = H5Sselect_hyperslab(dataspace2, H5S_SELECT_SET, null.data(), NULL, count.data(), NULL);
             if(status < 0)
                 break;
                 
-            status = H5Dwrite(datasetHandle, datatype, dataspace, filespace, H5P_DEFAULT, buffer.data());
+            status = H5Dwrite(datasetHandle, datatype, dataspace2, filespace, H5P_DEFAULT, buffer.data());
             if(status < 0)
                 break;
         }
@@ -2295,33 +2922,50 @@ void HDF5File::write_(std::string &datasetName,
 /********************************************************************/
 
 template<unsigned int N, class T, class Stride>
-void HDF5File::writeBlock_(std::string datasetName, 
-                           typename MultiArrayShape<N>::type &blockOffset, 
-                           const MultiArrayView<N, T, Stride> & array, 
-                           const hid_t datatype, 
-                           const int numBandsOfType)
+herr_t HDF5File::writeBlock_(HDF5HandleShared datasetHandle, 
+                             typename MultiArrayShape<N>::type &blockOffset, 
+                             const MultiArrayView<N, T, Stride> & array, 
+                             const hid_t datatype, 
+                             const int numBandsOfType)
 {
-    // open dataset if it exists
-    std::string errorMessage = "HDF5File::writeBlock(): Error opening dataset '" + datasetName + "'.";
-    HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
-
-    // hyperslab parameters for position, size, ...
-    hsize_t boffset [N];
-    hsize_t bshape [N];
-    hsize_t bones [N];
+    vigra_precondition(!isReadOnly(),
+        "HDF5File::writeBlock(): file is read-only.");
+        
+    ArrayVector<hsize_t> boffset, bshape, bones(N+1, 1);
+    hssize_t dimensions = getDatasetDimensions_(datasetHandle);
+    if(numBandsOfType > 1)
+    {
+        vigra_precondition(N+1 == dimensions,
+            "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
+        bshape.resize(N+1);
+        boffset.resize(N+1);
+        bshape[N] = numBandsOfType;
+        boffset[N] = 0;
+    }
+    else
+    {
+        vigra_precondition(N == dimensions,
+            "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
+        bshape.resize(N);
+        boffset.resize(N);
+    }
 
-    for(int i = 0; i < N; i++){
-        boffset[i] = blockOffset[N-1-i];
-        bshape[i] = array.size(N-1-i);
-        bones[i] = 1;
+    for(int i = 0; i < N; ++i)
+    {
+        // vigra and hdf5 use different indexing
+        bshape[N-1-i] = array.shape(i);
+        boffset[N-1-i] = blockOffset[i];
     }
 
     // create a target dataspace in memory with the shape of the desired block
-    HDF5Handle memspace_handle (H5Screate_simple(N,bshape,NULL),&H5Sclose,"Unable to get origin dataspace");
+    HDF5Handle memspace_handle (H5Screate_simple(bshape.size(), bshape.data(), NULL),
+                                &H5Sclose,
+                                "Unable to get origin dataspace");
 
     // get file dataspace and select the desired block
     HDF5Handle dataspaceHandle (H5Dget_space(datasetHandle),&H5Sclose,"Unable to create target dataspace");
-    H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, boffset, bones, bones, bshape);
+    H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, 
+                        boffset.data(), bones.data(), bones.data(), bshape.data());
 
     herr_t status = 0;
     if(array.isUnstrided())
@@ -2335,8 +2979,7 @@ void HDF5File::writeBlock_(std::string datasetName,
         MultiArray<N, T> buffer(array);
         status = H5Dwrite( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, buffer.data());
     }
-    vigra_postcondition(status >= 0,
-        "HDF5File::writeBlock(): write to dataset '" + datasetName + "' via H5Dwrite() failed.");
+    return status;
 }
 
 /********************************************************************/
@@ -2348,6 +2991,9 @@ void HDF5File::write_attribute_(std::string name,
                                 const hid_t datatype, 
                                 const int numBandsOfType)
 {
+    vigra_precondition(!isReadOnly(),
+        "HDF5File::writeAttribute(): file is read-only.");
+        
     // shape of the array. Add one dimension, if array contains non-scalars.
     ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end());
     std::reverse(shape.begin(), shape.end());
@@ -2425,7 +3071,7 @@ void HDF5File::read_(std::string datasetName,
                     ? 1
                     : 0;
 
-    vigra_precondition((N + offset ) == MultiArrayIndex(dimshape.size()), 
+    vigra_precondition(MultiArrayIndex(N + offset) == MultiArrayIndex(dimshape.size()), 
         "HDF5File::read(): Array dimension disagrees with dataset dimension.");
 
     typename MultiArrayShape<N>::type shape;
@@ -2458,7 +3104,7 @@ void HDF5File::read_(std::string datasetName,
         if(H5D_CHUNKED == H5Pget_layout(properties))
         {
             // if the file is chunked, we use a buffer that matches the chunk size.
-            H5Pget_chunk(properties, chunks.size(), chunks.data());
+            H5Pget_chunk(properties, static_cast<int>(chunks.size()), chunks.data());
             std::reverse(chunks.begin(), chunks.end());
         }
         else
@@ -2475,7 +3121,7 @@ void HDF5File::read_(std::string datasetName,
             }
         }
         
-        count[N-1-offset] = numBandsOfType;
+        count[N-1-offset] = static_cast<hsize_t>(numBandsOfType);
         
         typedef typename MultiArrayShape<N>::type Shape;
         Shape chunkCount, chunkMaxShape;
@@ -2529,51 +3175,51 @@ void HDF5File::read_(std::string datasetName,
 /********************************************************************/
 
 template<unsigned int N, class T, class Stride>
-void HDF5File::readBlock_(std::string datasetName, 
-                          typename MultiArrayShape<N>::type &blockOffset, 
-                          typename MultiArrayShape<N>::type &blockShape, 
-                          MultiArrayView<N, T, Stride> &array, 
-                          const hid_t datatype, const int numBandsOfType)
+herr_t HDF5File::readBlock_(HDF5HandleShared datasetHandle, 
+                            typename MultiArrayShape<N>::type &blockOffset, 
+                            typename MultiArrayShape<N>::type &blockShape, 
+                            MultiArrayView<N, T, Stride> array, 
+                            const hid_t datatype, const int numBandsOfType)
 {
-    //Prepare to read without using HDF5ImportInfo
-    //ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName) ;
-    hssize_t dimensions = getDatasetDimensions(datasetName);
-
-    std::string errorMessage ("HDF5File::readBlock(): Unable to open dataset '" + datasetName + "'.");
-    HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
-
-    int offset = (numBandsOfType > 1)
-                     ? 1
-                     : 0;
-
-    vigra_precondition(( (N + offset ) ==  MultiArrayIndex(dimensions)), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
-        "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
-
     vigra_precondition(blockShape == array.shape(),
          "HDF5File::readBlock(): Array shape disagrees with block size.");
 
-    // hyperslab parameters for position, size, ...
-    hsize_t boffset [N];
-    hsize_t bshape [N];
-    hsize_t bones [N];
+    ArrayVector<hsize_t> boffset, bshape, bones(N+1, 1);
+    hssize_t dimensions = getDatasetDimensions_(datasetHandle);
+    if(numBandsOfType > 1)
+    {
+        vigra_precondition(N+1 == dimensions,
+            "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
+        bshape.resize(N+1);
+        boffset.resize(N+1);
+        bshape[N] = numBandsOfType;
+        boffset[N] = 0;
+    }
+    else
+    {
+        vigra_precondition(N == dimensions,
+            "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
+        bshape.resize(N);
+        boffset.resize(N);
+    }
 
-    for(int i = 0; i < N; i++){
+    for(int i = 0; i < N; ++i)
+    {
         // vigra and hdf5 use different indexing
-        boffset[i] = blockOffset[N-1-i];
-        //bshape[i] = blockShape[i];
-        bshape[i] = blockShape[N-1-i];
-        //boffset[i] = blockOffset[N-1-i];
-        bones[i] = 1;
+        bshape[N-1-i] = blockShape[i];
+        boffset[N-1-i] = blockOffset[i];
     }
 
     // create a target dataspace in memory with the shape of the desired block
-    HDF5Handle memspace_handle(H5Screate_simple(N,bshape,NULL),&H5Sclose,
+    HDF5Handle memspace_handle(H5Screate_simple(bshape.size(), bshape.data(), NULL),
+                               &H5Sclose,
                                "Unable to create target dataspace");
 
     // get file dataspace and select the desired block
-    HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle),&H5Sclose, 
+    HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, 
                                "Unable to get dataspace");
-    H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, boffset, bones, bones, bshape);
+    H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, 
+                        boffset.data(), bones.data(), bones.data(), bshape.data());
 
     herr_t status = 0;
     if(array.isUnstrided())
@@ -2590,8 +3236,7 @@ void HDF5File::readBlock_(std::string datasetName,
         if(status >= 0)
             array = buffer;
     }
-    vigra_postcondition(status >= 0,
-        "HDF5File::readBlock(): read from dataset '" + datasetName + "' via H5Dread() failed.");
+    return status;
 }
 
 /********************************************************************/
@@ -2628,7 +3273,7 @@ void HDF5File::read_attribute_(std::string datasetName,
                     : 0;
     message = "HDF5File::readAttribute(): Array dimension disagrees with dataset dimension.";
     // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
-    vigra_precondition((N + offset) == MultiArrayIndex(dims), message);
+    vigra_precondition(MultiArrayIndex(N + offset) == MultiArrayIndex(dims), message);
 
     for(int k=offset; k < (int)dimshape.size(); ++k)
         vigra_precondition(array.shape()[k-offset] == (MultiArrayIndex)dimshape[k],
diff --git a/include/vigra/hierarchical_clustering.hxx b/include/vigra/hierarchical_clustering.hxx
new file mode 100644
index 0000000..a4f5b30
--- /dev/null
+++ b/include/vigra/hierarchical_clustering.hxx
@@ -0,0 +1,797 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2011 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+
+
+#ifndef VIGRA_HIERARCHICAL_CLUSTERING_HXX
+#define VIGRA_HIERARCHICAL_CLUSTERING_HXX
+
+
+
+/*std*/
+#include <queue>
+#include <iomanip>
+
+/*vigra*/
+#include "priority_queue.hxx"
+#include "metrics.hxx"
+
+namespace vigra{
+
+namespace cluster_operators{
+
+template<
+        class MERGE_GRAPH,
+        class EDGE_INDICATOR_MAP,
+        class EDGE_SIZE_MAP,
+        class NODE_SIZE_MAP,
+        class MIN_WEIGHT_MAP
+    >
+class EdgeWeightedUcm
+{
+    typedef EdgeWeightedUcm<
+        MERGE_GRAPH,
+        EDGE_INDICATOR_MAP,
+        EDGE_SIZE_MAP,
+        NODE_SIZE_MAP,
+        MIN_WEIGHT_MAP
+    > SelfType;
+
+  public:
+
+    typedef typename EDGE_INDICATOR_MAP::Value ValueType;
+    typedef ValueType WeightType;
+    typedef MERGE_GRAPH MergeGraph;
+    typedef typename MergeGraph::Graph Graph;
+    typedef typename Graph::Edge BaseGraphEdge;
+    typedef typename Graph::Node BaseGraphNode;
+    typedef typename MergeGraph::Edge Edge;
+    typedef typename MergeGraph::Node Node;
+    typedef typename MergeGraph::EdgeIt EdgeIt;
+    typedef typename MergeGraph::NodeIt NodeIt;
+    typedef typename MergeGraph::IncEdgeIt IncEdgeIt;
+    typedef typename MergeGraph::index_type index_type;
+    typedef MergeGraphItemHelper<MergeGraph,Edge> EdgeHelper;
+    typedef MergeGraphItemHelper<MergeGraph,Node> NodeHelper;
+
+    typedef typename MergeGraph::MergeNodeCallBackType MergeNodeCallBackType;
+    typedef typename MergeGraph::MergeEdgeCallBackType MergeEdgeCallBackType;
+    typedef typename MergeGraph::EraseEdgeCallBackType EraseEdgeCallBackType;
+
+    typedef typename EDGE_INDICATOR_MAP::Reference EdgeIndicatorReference;
+    /// \brief construct cluster operator
+    EdgeWeightedUcm(
+        MergeGraph & mergeGraph,
+        EDGE_INDICATOR_MAP edgeIndicatorMap,
+        EDGE_SIZE_MAP edgeSizeMap,
+        NODE_SIZE_MAP nodeSizeMap,
+        MIN_WEIGHT_MAP minWeightEdgeMap,
+        const ValueType wardness=1.0
+    )
+    :   mergeGraph_(mergeGraph),
+        edgeIndicatorMap_(edgeIndicatorMap),
+        edgeSizeMap_(edgeSizeMap),
+        nodeSizeMap_(nodeSizeMap),
+        minWeightEdgeMap_(minWeightEdgeMap),
+        pq_(mergeGraph.maxEdgeId()+1),
+        wardness_(wardness)
+    {
+        MergeNodeCallBackType cbMn(MergeNodeCallBackType:: template from_method<SelfType,&SelfType::mergeNodes>(this));
+        MergeEdgeCallBackType cbMe(MergeEdgeCallBackType:: template from_method<SelfType,&SelfType::mergeEdges>(this));
+        EraseEdgeCallBackType cbEe(EraseEdgeCallBackType:: template from_method<SelfType,&SelfType::eraseEdge>(this));
+
+        mergeGraph_.registerMergeNodeCallBack(cbMn);
+        mergeGraph_.registerMergeEdgeCallBack(cbMe);
+        mergeGraph_.registerEraseEdgeCallBack(cbEe);
+
+        for(EdgeIt e(mergeGraph_);e!=lemon::INVALID;++e){
+            const Edge edge = *e;
+            const BaseGraphEdge graphEdge=EdgeHelper::itemToGraphItem(mergeGraph_,edge);
+            const index_type edgeId = mergeGraph_.id(edge);
+            const ValueType currentWeight = this->getEdgeWeight(edge);
+            pq_.push(edgeId,currentWeight);
+            minWeightEdgeMap_[graphEdge]=currentWeight;
+        }
+    }
+
+    void setWardness(const float w){
+        wardness_ = w;
+    }
+
+    void resetMgAndPq(){
+        mergeGraph_.reset();
+
+        MergeNodeCallBackType cbMn(MergeNodeCallBackType:: template from_method<SelfType,&SelfType::mergeNodes>(this));
+        MergeEdgeCallBackType cbMe(MergeEdgeCallBackType:: template from_method<SelfType,&SelfType::mergeEdges>(this));
+        EraseEdgeCallBackType cbEe(EraseEdgeCallBackType:: template from_method<SelfType,&SelfType::eraseEdge>(this));
+
+        mergeGraph_.registerMergeNodeCallBack(cbMn);
+        mergeGraph_.registerMergeEdgeCallBack(cbMe);
+        mergeGraph_.registerEraseEdgeCallBack(cbEe);
+
+        pq_.reset();
+        for(EdgeIt e(mergeGraph_);e!=lemon::INVALID;++e){
+            const Edge edge = *e;
+            const BaseGraphEdge graphEdge=EdgeHelper::itemToGraphItem(mergeGraph_,edge);
+            const index_type edgeId = mergeGraph_.id(edge);
+            const ValueType currentWeight = this->getEdgeWeight(edge);
+            pq_.push(edgeId,currentWeight);
+            minWeightEdgeMap_[graphEdge]=currentWeight;
+        }
+    }
+
+    /// \brief will be called via callbacks from mergegraph
+    void mergeEdges(const Edge & a,const Edge & b){
+        // update features / weigts etc
+        const BaseGraphEdge aa=EdgeHelper::itemToGraphItem(mergeGraph_,a);
+        const BaseGraphEdge bb=EdgeHelper::itemToGraphItem(mergeGraph_,b);
+        EdgeIndicatorReference va=edgeIndicatorMap_[aa];
+        EdgeIndicatorReference vb=edgeIndicatorMap_[bb];
+        va*=edgeSizeMap_[aa];
+        vb*=edgeSizeMap_[bb];
+
+        va+=vb;
+        edgeSizeMap_[aa]+=edgeSizeMap_[bb];
+        va/=(edgeSizeMap_[aa]);
+        vb/=edgeSizeMap_[bb];
+        // delete b from pq
+        pq_.deleteItem(b.id());
+    }
+
+    /// \brief will be called via callbacks from mergegraph
+    void mergeNodes(const Node & a,const Node & b){
+        const BaseGraphNode aa=NodeHelper::itemToGraphItem(mergeGraph_,a);
+        const BaseGraphNode bb=NodeHelper::itemToGraphItem(mergeGraph_,b);
+        nodeSizeMap_[aa]+=nodeSizeMap_[bb];
+    }
+
+    /// \brief will be called via callbacks from mergegraph
+    void eraseEdge(const Edge & edge){
+
+        //std::cout<<"start to erase edge "<<mergeGraph_.id(edge)<<"\n";
+        // delete edge from pq
+        pq_.deleteItem(edge.id());
+        // get the new region the edge is in
+        // (since the edge is no any more an active edge)
+        //std::cout<<"get the new node  \n";
+        const Node newNode = mergeGraph_.inactiveEdgesNode(edge);
+        //std::cout<<"new node "<<mergeGraph_.id(newNode)<<"\n";
+
+        // iterate over all edges of this node
+        for (IncEdgeIt e(mergeGraph_,newNode);e!=lemon::INVALID;++e)
+        {
+            //std::cout<<"get inc edge\n";
+            const Edge incEdge(*e);
+
+            //std::cout<<"get inc graph edge\n";
+            const BaseGraphEdge incGraphEdge = EdgeHelper::itemToGraphItem(mergeGraph_,incEdge);
+
+            //std::cout<<"get inc edge weight"<<counter<<"\n";
+            // compute the new weight for this edge
+            // (this should involve region differences)
+            const ValueType newWeight =    getEdgeWeight(incEdge);
+
+            // change the weight in pq by repushing
+            pq_.push(incEdge.id(),newWeight);
+            minWeightEdgeMap_[incGraphEdge]=newWeight;
+
+        }
+        //std::cout<<"done\n";
+    }
+
+    /// \brief get the edge which should be contracted next
+    Edge contractionEdge(){
+        index_type minLabel = pq_.top();
+        while(mergeGraph_.hasEdgeId(minLabel)==false){
+            eraseEdge(Edge(minLabel));
+            minLabel = pq_.top();
+        }
+        return Edge(minLabel);
+    }
+
+    /// \brief get the edge weight of the edge which should be contracted next
+    WeightType contractionWeight(){
+        index_type minLabel = pq_.top();
+        while(mergeGraph_.hasEdgeId(minLabel)==false){
+            eraseEdge(Edge(minLabel));
+            minLabel = pq_.top();
+        }
+        return pq_.topPriority();
+
+    }
+
+
+    /// \brief get a reference to the merge
+    MergeGraph & mergeGraph(){
+        return mergeGraph_;
+    }
+
+    bool done(){
+
+        index_type minLabel = pq_.top();
+        while(mergeGraph_.hasEdgeId(minLabel)==false){
+            eraseEdge(Edge(minLabel));
+            minLabel = pq_.top();
+        }
+        return mergeGraph_.edgeNum()==0 || mergeGraph_.nodeNum()==1;
+    }
+
+  private:
+    ValueType getEdgeWeight(const Edge & e){
+
+        const Node u = mergeGraph_.u(e);
+        const Node v = mergeGraph_.v(e);
+
+        const size_t dU = mergeGraph_.degree(u);
+        const size_t dV = mergeGraph_.degree(u);
+        const BaseGraphEdge ee=EdgeHelper::itemToGraphItem(mergeGraph_,e);
+        const BaseGraphNode uu=NodeHelper::itemToGraphItem(mergeGraph_,u);
+        const BaseGraphNode vv=NodeHelper::itemToGraphItem(mergeGraph_,v);
+
+        const float sizeU = nodeSizeMap_[uu] ;
+        const float sizeV = nodeSizeMap_[vv] ;
+
+        const ValueType wardFac = 2.0 / ( 1.0/std::pow(sizeU,wardness_) + 1/std::pow(sizeV,wardness_) );
+        //const ValueType wardFac = (wardFacRaw*wardness_) + (1.0-wardness_);
+
+        const ValueType fromEdgeIndicator = edgeIndicatorMap_[ee];
+        const ValueType totalWeight = fromEdgeIndicator*wardFac;
+        return totalWeight;
+    }
+
+
+    MergeGraph & mergeGraph_;
+    EDGE_INDICATOR_MAP edgeIndicatorMap_;
+    EDGE_SIZE_MAP edgeSizeMap_;
+    NODE_SIZE_MAP nodeSizeMap_;
+    MIN_WEIGHT_MAP minWeightEdgeMap_;
+    vigra::ChangeablePriorityQueue< ValueType > pq_;
+    ValueType wardness_;;
+};
+
+    /// \brief  This Cluster Operator is a MONSTER.
+    /// It can really do a lot.
+    ///
+    /// Each edge has a single scalar weight w_e.
+    /// Each node has a feature vector f_n.
+    /// (all f_n's have the same length).
+    /// Edges and nodes have a length / size
+    ///
+    /// The total edge weight is computed via a complicated formula
+    ///
+    /// The main idea is the following.
+    /// Use a  mixture between the edge weights w_e,
+    /// and node based edge weights which are computed
+    /// via a metric which measures the 'difference' between
+    /// the u/v feature vectors f_n.
+    ///
+    /// Furthermore a 'Ward'-like regularization can be applied.
+    /// This is useful if one  have clusters with sizes
+    /// in the same magnitude (or 'similar' sizes).
+    /// The amount of 'ward'-regularization is controlled
+    /// with the 'wardness' parameter.
+    ///
+    /// Also labels (in the sense of seeds) can be attached to get a 'watershed-ish'
+    /// behavior (nodes with different labels will never be merged)
+    /// The '0'-Label is used to indicate that there is no label at all.
+    /// If certain connected regions share the same seed/label
+    /// it is not guaranteed that they will merge. But a certain prior / multiplier
+    /// must be specified. The total weight of an edge where the u/v node have
+    /// the same label is multiplied with this very multiplier.
+    template<
+        class MERGE_GRAPH,
+        class EDGE_INDICATOR_MAP,
+        class EDGE_SIZE_MAP,
+        class NODE_FEATURE_MAP,
+        class NODE_SIZE_MAP,
+        class MIN_WEIGHT_MAP,
+        class NODE_LABEL_MAP
+    >
+    class EdgeWeightNodeFeatures{
+
+        typedef EdgeWeightNodeFeatures<
+            MERGE_GRAPH,
+            EDGE_INDICATOR_MAP,
+            EDGE_SIZE_MAP,
+            NODE_FEATURE_MAP,
+            NODE_SIZE_MAP,
+            MIN_WEIGHT_MAP,
+            NODE_LABEL_MAP
+        > SelfType;
+    public:
+
+
+        typedef typename EDGE_INDICATOR_MAP::Value ValueType;
+        typedef ValueType WeightType;
+        typedef MERGE_GRAPH MergeGraph;
+        typedef typename MergeGraph::Graph Graph;
+        typedef typename Graph::Edge BaseGraphEdge;
+        typedef typename Graph::Node BaseGraphNode;
+        typedef typename MergeGraph::Edge Edge;
+        typedef typename MergeGraph::Node Node;
+        typedef typename MergeGraph::EdgeIt EdgeIt;
+        typedef typename MergeGraph::NodeIt NodeIt;
+        typedef typename MergeGraph::IncEdgeIt IncEdgeIt;
+        typedef typename MergeGraph::index_type index_type;
+        typedef MergeGraphItemHelper<MergeGraph,Edge> EdgeHelper;
+        typedef MergeGraphItemHelper<MergeGraph,Node> NodeHelper;
+
+
+        typedef typename EDGE_INDICATOR_MAP::Reference EdgeIndicatorReference;
+        typedef typename NODE_FEATURE_MAP::Reference NodeFeatureReference;
+        /// \brief construct cluster operator
+        EdgeWeightNodeFeatures(
+            MergeGraph & mergeGraph,
+            EDGE_INDICATOR_MAP edgeIndicatorMap,
+            EDGE_SIZE_MAP edgeSizeMap,
+            NODE_FEATURE_MAP nodeFeatureMap,
+            NODE_SIZE_MAP nodeSizeMap,
+            MIN_WEIGHT_MAP minWeightEdgeMap,
+            NODE_LABEL_MAP nodeLabelMap,
+            const ValueType beta,
+            const metrics::MetricType metricType,
+            const ValueType wardness=1.0,
+            const ValueType gamma = 10000000.0,
+            const ValueType sameLabelMultiplier = 0.8
+        )
+        :   mergeGraph_(mergeGraph),
+            edgeIndicatorMap_(edgeIndicatorMap),
+            edgeSizeMap_(edgeSizeMap),
+            nodeFeatureMap_(nodeFeatureMap),
+            nodeSizeMap_(nodeSizeMap),
+            minWeightEdgeMap_(minWeightEdgeMap),
+            nodeLabelMap_(nodeLabelMap),
+            pq_(mergeGraph.maxEdgeId()+1),
+            beta_(beta),
+            wardness_(wardness),
+            gamma_(gamma),
+            sameLabelMultiplier_(sameLabelMultiplier),
+            metric_(metricType)
+        {
+            typedef typename MergeGraph::MergeNodeCallBackType MergeNodeCallBackType;
+            typedef typename MergeGraph::MergeEdgeCallBackType MergeEdgeCallBackType;
+            typedef typename MergeGraph::EraseEdgeCallBackType EraseEdgeCallBackType;
+
+
+            MergeNodeCallBackType cbMn(MergeNodeCallBackType:: template from_method<SelfType,&SelfType::mergeNodes>(this));
+            MergeEdgeCallBackType cbMe(MergeEdgeCallBackType:: template from_method<SelfType,&SelfType::mergeEdges>(this));
+            EraseEdgeCallBackType cbEe(EraseEdgeCallBackType:: template from_method<SelfType,&SelfType::eraseEdge>(this));
+
+            mergeGraph_.registerMergeNodeCallBack(cbMn);
+            mergeGraph_.registerMergeEdgeCallBack(cbMe);
+            mergeGraph_.registerEraseEdgeCallBack(cbEe);
+
+
+
+            for(EdgeIt e(mergeGraph);e!=lemon::INVALID;++e){
+                const Edge edge = *e;
+                const BaseGraphEdge graphEdge=EdgeHelper::itemToGraphItem(mergeGraph_,edge);
+                const index_type edgeId = mergeGraph_.id(edge);
+                const ValueType currentWeight = this->getEdgeWeight(edge);
+                pq_.push(edgeId,currentWeight);
+                minWeightEdgeMap_[graphEdge]=currentWeight;
+            }
+
+        }
+
+        /// \brief will be called via callbacks from mergegraph
+        void mergeEdges(const Edge & a,const Edge & b){
+            // update features / weigts etc
+            const BaseGraphEdge aa=EdgeHelper::itemToGraphItem(mergeGraph_,a);
+            const BaseGraphEdge bb=EdgeHelper::itemToGraphItem(mergeGraph_,b);
+            EdgeIndicatorReference va=edgeIndicatorMap_[aa];
+            EdgeIndicatorReference vb=edgeIndicatorMap_[bb];
+            va*=edgeSizeMap_[aa];
+            vb*=edgeSizeMap_[bb];
+
+
+            va+=vb;
+            edgeSizeMap_[aa]+=edgeSizeMap_[bb];
+            va/=(edgeSizeMap_[aa]);
+            vb/=edgeSizeMap_[bb];
+            // delete b from pq
+            pq_.deleteItem(b.id());
+        }
+
+        /// \brief will be called via callbacks from mergegraph
+        void mergeNodes(const Node & a,const Node & b){
+            const BaseGraphNode aa=NodeHelper::itemToGraphItem(mergeGraph_,a);
+            const BaseGraphNode bb=NodeHelper::itemToGraphItem(mergeGraph_,b);
+            NodeFeatureReference va=nodeFeatureMap_[aa];
+            NodeFeatureReference vb=nodeFeatureMap_[bb];
+            va*=nodeSizeMap_[aa];
+            vb*=nodeSizeMap_[bb];
+            va+=vb;
+            nodeSizeMap_[aa]+=nodeSizeMap_[bb];
+            va/=(nodeSizeMap_[aa]);
+            vb/=nodeSizeMap_[bb];
+
+
+            // update labels
+            const UInt32 labelA = nodeLabelMap_[aa];
+            const UInt32 labelB = nodeLabelMap_[bb];
+
+            if(labelA!=0 && labelB!=0 && labelA!=labelB){
+                throw std::runtime_error("both nodes have labels");
+            }
+            else{
+                const UInt32 newLabel  = std::max(labelA, labelB);
+                nodeLabelMap_[aa] = newLabel;
+            }
+        }
+
+        /// \brief will be called via callbacks from mergegraph
+        void eraseEdge(const Edge & edge){
+
+            //std::cout<<"start to erase edge "<<mergeGraph_.id(edge)<<"\n";
+            // delete edge from pq
+            pq_.deleteItem(edge.id());
+            // get the new region the edge is in
+            // (since the edge is no any more an active edge)
+            //std::cout<<"get the new node  \n";
+            const Node newNode = mergeGraph_.inactiveEdgesNode(edge);
+            //std::cout<<"new node "<<mergeGraph_.id(newNode)<<"\n";
+
+
+            // iterate over all edges of this node
+            for (IncEdgeIt e(mergeGraph_,newNode);e!=lemon::INVALID;++e){
+
+                //std::cout<<"get inc edge\n";
+                const Edge incEdge(*e);
+
+                //std::cout<<"get inc graph edge\n";
+                const BaseGraphEdge incGraphEdge = EdgeHelper::itemToGraphItem(mergeGraph_,incEdge);
+
+                //std::cout<<"get inc edge weight"<<counter<<"\n";
+                // compute the new weight for this edge
+                // (this should involve region differences)
+                const ValueType newWeight =    getEdgeWeight(incEdge);
+
+
+                // change the weight in pq by repushing
+
+                //std::cout<<"push\n";
+                pq_.push(incEdge.id(),newWeight);
+                minWeightEdgeMap_[incGraphEdge]=newWeight;
+
+            }
+            //std::cout<<"done\n";
+        }
+
+        /// \brief get the edge which should be contracted next
+        Edge contractionEdge(){
+            index_type minLabel = pq_.top();
+            while(mergeGraph_.hasEdgeId(minLabel)==false){
+                pq_.deleteItem(minLabel);
+                minLabel = pq_.top();
+            }
+            return Edge(minLabel);
+        }
+
+        /// \brief get the edge weight of the edge which should be contracted next
+        WeightType contractionWeight(){
+            index_type minLabel = pq_.top();
+            while(mergeGraph_.hasEdgeId(minLabel)==false){
+                pq_.deleteItem(minLabel);
+                minLabel = pq_.top();
+            }
+            return pq_.topPriority();
+
+        }
+
+
+        /// \brief get a reference to the merge
+        MergeGraph & mergeGraph(){
+            return mergeGraph_;
+        }
+
+        bool done(){
+
+            index_type minLabel = pq_.top();
+            while(mergeGraph_.hasEdgeId(minLabel)==false){
+                pq_.deleteItem(minLabel);
+                minLabel = pq_.top();
+            }
+            const ValueType p =  pq_.topPriority();
+
+            return p>= gamma_;
+        }
+
+    private:
+        ValueType getEdgeWeight(const Edge & e){
+
+            const Node u = mergeGraph_.u(e);
+            const Node v = mergeGraph_.v(e);
+
+            const size_t dU = mergeGraph_.degree(u);
+            const size_t dV = mergeGraph_.degree(u);
+            const BaseGraphEdge ee=EdgeHelper::itemToGraphItem(mergeGraph_,e);
+            const BaseGraphNode uu=NodeHelper::itemToGraphItem(mergeGraph_,u);
+            const BaseGraphNode vv=NodeHelper::itemToGraphItem(mergeGraph_,v);
+
+            const float sizeU = nodeSizeMap_[uu];
+            const float sizeV = nodeSizeMap_[vv];
+
+
+            const ValueType wardFac = 2.0 / ( 1.0/std::pow(sizeU,wardness_) + 1/std::pow(sizeV,wardness_) );
+
+            const ValueType fromEdgeIndicator = edgeIndicatorMap_[ee];
+            ValueType fromNodeDist = metric_(nodeFeatureMap_[uu],nodeFeatureMap_[vv]);
+            ValueType totalWeight = ((1.0-beta_)*fromEdgeIndicator + beta_*fromNodeDist)*wardFac;
+
+
+            const UInt32 labelA = nodeLabelMap_[uu];
+            const UInt32 labelB = nodeLabelMap_[vv];
+
+            if(labelA!=0 && labelB!=0){
+                if(labelA == labelB){
+                    totalWeight*=sameLabelMultiplier_;
+                }
+                else{
+                    totalWeight += gamma_;
+                }
+            }
+            return totalWeight;
+        }
+
+
+        MergeGraph & mergeGraph_;
+        EDGE_INDICATOR_MAP edgeIndicatorMap_;
+        EDGE_SIZE_MAP edgeSizeMap_;
+        NODE_FEATURE_MAP nodeFeatureMap_;
+        NODE_SIZE_MAP nodeSizeMap_;
+        MIN_WEIGHT_MAP minWeightEdgeMap_;
+        NODE_LABEL_MAP nodeLabelMap_;
+        vigra::ChangeablePriorityQueue< ValueType > pq_;
+        ValueType beta_;
+        ValueType wardness_;
+        ValueType gamma_;
+        ValueType sameLabelMultiplier_;
+        metrics::Metric<float> metric_;
+    };
+
+
+
+} // end namespace cluster_operators
+
+
+
+    /// \brief  do hierarchical clustering with a given cluster operator
+    template< class CLUSTER_OPERATOR>
+    class HierarchicalClustering{
+
+    public:
+        typedef CLUSTER_OPERATOR                        ClusterOperator;
+        typedef typename ClusterOperator::MergeGraph    MergeGraph;
+        typedef typename MergeGraph::Graph              Graph;
+        typedef typename Graph::Edge                    BaseGraphEdge;
+        typedef typename Graph::Node                    BaseGraphNode;
+        typedef typename MergeGraph::Edge               Edge;
+        typedef typename MergeGraph::Node               Node;
+        typedef typename CLUSTER_OPERATOR::WeightType   ValueType;
+        typedef typename MergeGraph::index_type         MergeGraphIndexType;
+
+        struct Parameter{
+            Parameter(
+                const size_t      nodeNumStopCond = 1,
+                const bool        buildMergeTree  = true,
+                const bool        verbose         = false
+            )
+            :   nodeNumStopCond_ (nodeNumStopCond),
+                buildMergeTreeEncoding_(buildMergeTree),
+                verbose_(verbose){
+            }
+            size_t nodeNumStopCond_;
+            bool   buildMergeTreeEncoding_;
+            bool   verbose_;
+        };
+
+        struct MergeItem{
+            MergeItem(
+                const MergeGraphIndexType  a,
+                const MergeGraphIndexType  b,
+                const MergeGraphIndexType  r,
+                const ValueType            w
+            ):
+            a_(a),b_(b),r_(r),w_(w){
+            }
+            MergeGraphIndexType a_;
+            MergeGraphIndexType b_;
+            MergeGraphIndexType r_;
+            ValueType           w_;
+        };
+
+        typedef std::vector<MergeItem> MergeTreeEncoding;
+
+        /// \brief construct HierarchicalClustering from clusterOperator and an optional parameter object
+        HierarchicalClustering(
+            ClusterOperator & clusterOperator,
+            const Parameter & parameter = Parameter()
+        )
+        :
+            clusterOperator_(clusterOperator),
+            param_(parameter),
+            mergeGraph_(clusterOperator_.mergeGraph()),
+            graph_(mergeGraph_.graph()),
+            timestamp_(graph_.maxNodeId()+1),
+            toTimeStamp_(),
+            timeStampIndexToMergeIndex_(),
+            mergeTreeEndcoding_()
+        {
+            if(param_.buildMergeTreeEncoding_){
+                // this can be be made smater since user can pass
+                // stoping condition based on nodeNum
+                mergeTreeEndcoding_.reserve(graph_.nodeNum()*2);
+                toTimeStamp_.resize(graph_.maxNodeId()+1);
+                timeStampIndexToMergeIndex_.resize(graph_.maxNodeId()+1);
+                for(MergeGraphIndexType nodeId=0;nodeId<=mergeGraph_.maxNodeId();++nodeId){
+                    toTimeStamp_[nodeId]=nodeId;
+                }
+            }
+
+
+
+        }
+
+        /// \brief start the clustering
+        void cluster(){
+            if(param_.verbose_)
+                std::cout<<"\n";
+            while(mergeGraph_.nodeNum()>param_.nodeNumStopCond_ && mergeGraph_.edgeNum()>0 && !clusterOperator_.done()){
+
+                const Edge edgeToRemove = clusterOperator_.contractionEdge();
+                if(param_.buildMergeTreeEncoding_){
+                    const MergeGraphIndexType uid = mergeGraph_.id(mergeGraph_.u(edgeToRemove));
+                    const MergeGraphIndexType vid = mergeGraph_.id(mergeGraph_.v(edgeToRemove));
+                    const ValueType w             = clusterOperator_.contractionWeight();
+                    // do the merge
+                    mergeGraph_.contractEdge( edgeToRemove);
+                    const MergeGraphIndexType aliveNodeId = mergeGraph_.hasNodeId(uid) ? uid : vid;
+                    const MergeGraphIndexType deadNodeId  = aliveNodeId==vid ? uid : vid;
+                    timeStampIndexToMergeIndex_[timeStampToIndex(timestamp_)]=mergeTreeEndcoding_.size();
+                    mergeTreeEndcoding_.push_back(MergeItem( toTimeStamp_[aliveNodeId],toTimeStamp_[deadNodeId],timestamp_,w));
+                    toTimeStamp_[aliveNodeId]=timestamp_;
+                    timestamp_+=1;
+                }
+                else{
+                    //std::cout<<"constract\n";
+                    // do the merge
+                    mergeGraph_.contractEdge( edgeToRemove );
+                }
+                if(param_.verbose_ && mergeGraph_.nodeNum()%1==0){
+                    std::cout<<"\rNodes: "<<std::setw(10)<<mergeGraph_.nodeNum()<<std::flush;
+                }
+
+            }
+            if(param_.verbose_)
+                std::cout<<"\n";
+        }
+
+        /// \brief get the encoding of the merge tree
+        const MergeTreeEncoding & mergeTreeEndcoding()const{
+            return mergeTreeEndcoding_;
+        }
+
+        template<class EDGE_MAP>
+        void ucmTransform(EDGE_MAP & edgeMap)const{
+            typedef typename Graph::EdgeIt  BaseGraphEdgeIt;
+
+            for(BaseGraphEdgeIt iter(graph()); iter!=lemon::INVALID; ++iter ){
+                const BaseGraphEdge edge=*iter;
+                edgeMap[edge] = edgeMap[mergeGraph().reprGraphEdge(edge)];
+            }
+        }
+
+        /// \brief get the node id's which are the leafes of a treeNodeId
+        template<class OUT_ITER>
+        size_t leafNodeIds(const MergeGraphIndexType treeNodeId, OUT_ITER begin)const{
+            if(treeNodeId<=graph_.maxNodeId()){
+                *begin=treeNodeId;
+                ++begin;
+                return 1;
+            }
+            else{
+                size_t leafNum=0;
+                std::queue<MergeGraphIndexType>     queue;
+                queue.push(treeNodeId);
+
+                while(!queue.empty()){
+
+                    const MergeGraphIndexType id = queue.front();
+                    queue.pop();
+                    const MergeGraphIndexType mergeIndex = timeStampToMergeIndex(id);
+                    const MergeGraphIndexType ab[]= { mergeTreeEndcoding_[mergeIndex].a_, mergeTreeEndcoding_[mergeIndex].b_};
+
+                    for(size_t i=0;i<2;++i){
+                        if(ab[i]<=graph_.maxNodeId()){
+                            *begin=ab[i];
+                            ++begin;
+                            ++leafNum;
+                        }
+                        else{
+                            queue.push(ab[i]);
+                        }
+                    }
+                }
+                return leafNum;
+            }
+        }
+
+        /// \brief get the graph the merge graph is based on
+        const Graph & graph()const{
+            return graph_;
+        }
+
+        /// \brief get the merge graph
+        const MergeGraph & mergeGraph()const{
+            return mergeGraph_;
+        }
+
+        /// \brief get the representative node id
+        const MergeGraphIndexType reprNodeId(const MergeGraphIndexType id)const{
+            return mergeGraph_.reprNodeId(id);
+        }
+    private:
+
+        MergeGraphIndexType timeStampToIndex(const MergeGraphIndexType timestamp)const{
+            return timestamp- graph_.maxNodeId();
+        }
+
+
+        MergeGraphIndexType timeStampToMergeIndex(const MergeGraphIndexType timestamp)const{
+            return timeStampIndexToMergeIndex_[timeStampToIndex(timestamp)];
+        }
+
+        ClusterOperator & clusterOperator_;
+        Parameter          param_;
+        MergeGraph & mergeGraph_;
+        const Graph  & graph_;
+        // parameter object
+
+
+        // timestamp
+        MergeGraphIndexType timestamp_;
+        std::vector<MergeGraphIndexType> toTimeStamp_;
+        std::vector<MergeGraphIndexType> timeStampIndexToMergeIndex_;
+        // data which can reconstruct the merge tree
+        MergeTreeEncoding mergeTreeEndcoding_;
+
+
+    };
+
+
+}
+
+#endif // VIGRA_HIERARCHICAL_CLUSTERING_HXX
diff --git a/include/vigra/histogram.hxx b/include/vigra/histogram.hxx
index 3ec602a..730a2de 100644
--- a/include/vigra/histogram.hxx
+++ b/include/vigra/histogram.hxx
@@ -64,9 +64,9 @@ class HistogramOptions
     
     /** Initialize members with default values:
 
-	- minimum, maximum = 0.0
-	- binCount = 64
-	- local_auto_init = false
+    - minimum, maximum = 0.0
+    - binCount = 64
+    - local_auto_init = false
     */
     HistogramOptions()
     : minimum(0.0), maximum(0.0),
@@ -179,15 +179,15 @@ class HistogramView
         return *(bins_ + k*stride_);
     }
 
-	double mapItem(DataType const & d) const
-	{
-		return scale_ * (d - offset_);
-	}
+    double mapItem(DataType const & d) const
+    {
+        return scale_ * (d - offset_);
+    }
     
-	DataType mapItemInverse(double d) const
-	{
-		return DataType(d * scaleInverse_ + offset_);
-	}
+    DataType mapItemInverse(double d) const
+    {
+        return DataType(d * scaleInverse_ + offset_);
+    }
     
     void add(DataType const & d, BinType weight = NumericTraits<BinType>::one())
     {
@@ -196,14 +196,14 @@ class HistogramView
 
   protected:
 
-	BinType & get(int index)
-	{
+    BinType & get(int index)
+    {
         if(index < 0)
             index = 0;
         if(index >= size_)
             index = size_ - 1;
-		return *(bins_ + index*stride_);
-	}
+        return *(bins_ + index*stride_);
+    }
 };
 
 template <class T>
@@ -287,7 +287,7 @@ class KernelHistogramView
         for(int k=center+radius_; k>=center-radius_; --k, f += 1.0)
         {   
             this->get(k) += weight*kernel_[f];
-		}
+        }
     }
     
     DataType findMode() const
diff --git a/include/vigra/imagecontainer.hxx b/include/vigra/imagecontainer.hxx
index c7386d6..a6f0f80 100644
--- a/include/vigra/imagecontainer.hxx
+++ b/include/vigra/imagecontainer.hxx
@@ -449,9 +449,12 @@ public:
     An ImagePyramid manages an array of images of the type given as
     template parameter, where each level has half the width and height
     of its predecessor.  It actually represents a sequence of pyramid
-    levels whose start and end index are configurable.  For Burt-style
-    pyramids, see also \ref pyramidReduceBurtFilter and \ref
-    pyramidExpandBurtFilter.
+    levels whose start and end index are configurable.  
+    
+    To initialize all pyramid levels in the sense of a Gaussian pyramid,
+    use \ref pyramidReduceBurtFilter() and \ref pyramidExpandBurtFilter().
+    To create and reconstruct a Laplcaian pyramid, use 
+    \ref pyramidReduceBurtLaplacian() and \ref pyramidExpandBurtLaplacian().
 
     A customized allocator can be passed as a template argument and
     via the constructor.  By default, the allocator of the
diff --git a/include/vigra/imageinfo.hxx b/include/vigra/imageinfo.hxx
index 1c49525..22e6265 100644
--- a/include/vigra/imageinfo.hxx
+++ b/include/vigra/imageinfo.hxx
@@ -322,10 +322,11 @@ class ImageExportInfo
 
             Currently only supported by TIFF, PNG and OpenEXR files.
 
-            The offset is encoded in the XPosition and YPosition TIFF tags.
+            The offset is encoded in the XPosition and YPosition TIFF tags. TIFF
+            requires that the resolution must also be set.
 
             @param pos     position of the upper left corner in pixels
-                           (must be >= 0)
+                           (must be >= 0 for TIFF)
          **/
     VIGRA_EXPORT ImageExportInfo & setPosition(const Diff2D & pos);
 
diff --git a/include/vigra/imageiterator.hxx b/include/vigra/imageiterator.hxx
index 7e443a7..496f294 100644
--- a/include/vigra/imageiterator.hxx
+++ b/include/vigra/imageiterator.hxx
@@ -387,8 +387,8 @@ class DirectionSelector<UnstridedArrayTag>
         void operator++(int) {++current_;}
         void operator--() {--current_;}
         void operator--(int) {--current_;}
-        void operator+=(int dx) {current_ += dx; }
-        void operator-=(int dx) {current_ -= dx; }
+        void operator+=(std::ptrdiff_t dx) {current_ += dx; }
+        void operator-=(std::ptrdiff_t dx) {current_ -= dx; }
 
         bool operator==(type const & rhs) const
          { return current_ == rhs.current_; }
@@ -408,13 +408,13 @@ class DirectionSelector<UnstridedArrayTag>
         bool operator>=(type const & rhs) const
          { return current_ >= rhs.current_; }
 
-        int operator-(type const & rhs) const
+        std::ptrdiff_t operator-(type const & rhs) const
          { return current_ - rhs.current_; }
 
         T operator()() const
         { return current_; }
 
-        T operator()(int d) const
+        T operator()(std::ptrdiff_t d) const
         { return current_ + d; }
 
         T current_;
@@ -430,7 +430,7 @@ class DirectionSelector<StridedArrayTag>
     class type
     {
       public:
-        type(int stride, T base = 0)
+        type(std::ptrdiff_t stride, T base = 0)
         : stride_(stride),
           current_(base)
         {}
@@ -451,8 +451,8 @@ class DirectionSelector<StridedArrayTag>
         void operator++(int) {current_ += stride_; }
         void operator--() {current_ -= stride_; }
         void operator--(int) {current_ -= stride_; }
-        void operator+=(int dy) {current_ += dy*stride_; }
-        void operator-=(int dy) {current_ -= dy*stride_; }
+        void operator+=(std::ptrdiff_t dy) {current_ += dy*stride_; }
+        void operator-=(std::ptrdiff_t dy) {current_ -= dy*stride_; }
 
         bool operator==(type const & rhs) const
          { return (current_ == rhs.current_); }
@@ -472,16 +472,16 @@ class DirectionSelector<StridedArrayTag>
         bool operator>=(type const & rhs) const
          { return (current_ >= rhs.current_); }
 
-        int operator-(type const & rhs) const
+        std::ptrdiff_t operator-(type const & rhs) const
          { return (current_ - rhs.current_) / stride_; }
 
         T operator()() const
         { return current_; }
 
-        T operator()(int d) const
+        T operator()(std::ptrdiff_t d) const
         { return current_ + d*stride_; }
 
-        int stride_;
+        std::ptrdiff_t stride_;
         T current_;
     };
 };
@@ -616,7 +616,7 @@ class ImageIteratorBase
         /** Let operations act in Y direction
         */
     typedef typename
-        vigra::detail::DirectionSelector<StridedArrayTag>::template type<int> MoveY;
+        vigra::detail::DirectionSelector<StridedArrayTag>::template type<std::ptrdiff_t> MoveY;
 
     /** @name Comparison of Iterators */
     //@{
@@ -680,7 +680,7 @@ class ImageIteratorBase
         must only be called for unstrided iterators
         (<tt>StridedOrUnstrided == UnstridedArrayTag</tt>)
         */
-    ImageIteratorBase(pointer base, int ystride)
+    ImageIteratorBase(pointer base, std::ptrdiff_t ystride)
     : x(base),
       y(ystride)
     {}
@@ -691,7 +691,7 @@ class ImageIteratorBase
         must only be called for strided iterators
         (<tt>StridedOrUnstrided == StridedArrayTag</tt>)
         */
-    ImageIteratorBase(pointer base, int xstride, int ystride)
+    ImageIteratorBase(pointer base, std::ptrdiff_t xstride, std::ptrdiff_t ystride)
     : x(xstride, base),
       y(ystride)
     {}
@@ -791,7 +791,7 @@ class ImageIteratorBase
         /** Access pixel at offset (dx, dy) from current location. <br>
             usage: <TT> SomePixelType value = iterator(dx, dy) </TT>
         */
-    index_reference operator()(int dx, int dy) const
+    index_reference operator()(std::ptrdiff_t dx, std::ptrdiff_t dy) const
     {
         return *current(dx, dy);
     }
@@ -800,7 +800,7 @@ class ImageIteratorBase
             Note that the 'x' index is the trailing index. <br>
             usage: <TT> SomePixelType value = iterator[dy][dx] </TT>
         */
-    pointer operator[](int dy) const
+    pointer operator[](std::ptrdiff_t dy) const
     {
         return x() + y(dy);
     }
@@ -821,7 +821,7 @@ class ImageIteratorBase
     pointer current() const
         { return x() + y(); }
 
-    pointer current(int dx, int dy) const
+    pointer current(std::ptrdiff_t dx, std::ptrdiff_t dy) const
         { return x(dx) + y(dy); }
 };
 
@@ -863,7 +863,7 @@ class ImageIterator
         object should have a factory function that constructs the
         iterator.
         */
-    ImageIterator(pointer base, int ystride)
+    ImageIterator(pointer base, std::ptrdiff_t ystride)
     : Base(base, ystride)
     {}
 
@@ -908,7 +908,7 @@ class ConstImageIterator
         object should have a factory function that constructs the
         iterator.
         */
-    ConstImageIterator(pointer base, int ystride)
+    ConstImageIterator(pointer base, std::ptrdiff_t ystride)
     : Base(base, ystride)
     {}
 
@@ -978,7 +978,7 @@ class StridedImageIterator
         jumping by <tt>xskip</tt> horizontally and <tt>yskip</tt> vertically.
         <tt>ystride</tt> must be the physical width (row length) of the image.
         */
-    StridedImageIterator(pointer base, int ystride, int xskip, int yskip)
+    StridedImageIterator(pointer base, std::ptrdiff_t ystride, std::ptrdiff_t xskip, std::ptrdiff_t yskip)
     : Base(base, xskip, ystride*yskip)
     {}
 
@@ -1040,7 +1040,7 @@ class ConstStridedImageIterator
         jumping by <tt>xskip</tt> horizontally and <tt>yskip</tt> vertically.
         <tt>ystride</tt> must be the physical width (row length) of the image.
         */
-    ConstStridedImageIterator(pointer base, int ystride, int xskip, int yskip)
+    ConstStridedImageIterator(pointer base, std::ptrdiff_t ystride, std::ptrdiff_t xskip, std::ptrdiff_t yskip)
     : Base(base, xskip, ystride*yskip)
     {}
 
@@ -1224,7 +1224,7 @@ class ConstValueIteratorPolicy
   public:
 
     typedef PIXELTYPE                       value_type;
-    typedef int                             difference_type;
+    typedef std::ptrdiff_t                  difference_type;
     typedef PIXELTYPE const &               reference;
     typedef PIXELTYPE const &               index_reference;
     typedef PIXELTYPE const *               pointer;
@@ -1232,15 +1232,15 @@ class ConstValueIteratorPolicy
 
     struct BaseType
     {
-        BaseType(PIXELTYPE const & v = PIXELTYPE(), int p = 0)
+        BaseType(PIXELTYPE const & v = PIXELTYPE(), std::ptrdiff_t p = 0)
         : value(v), pos(p)
         {}
 
         PIXELTYPE value;
-        int pos;
+        std::ptrdiff_t pos;
     };
 
-    static void initialize(BaseType & d) {}
+    static void initialize(BaseType & /* d */) {}
 
     static reference dereference(BaseType const & d)
         { return d.value; }
@@ -1327,11 +1327,11 @@ class ConstValueIterator
 
         /** Let operations act in X direction
         */
-    typedef int MoveX;
+    typedef std::ptrdiff_t MoveX;
 
         /** Let operations act in Y direction
         */
-    typedef int MoveY;
+    typedef std::ptrdiff_t MoveY;
 
         /** Default Constructor. (the constant is set to
         <TT>NumericTraits<PIXELTYPE>::zero()</TT> )
@@ -1438,7 +1438,7 @@ class ConstValueIterator
 
         /** Read pixel at a distance (return specified constant).
         */
-    index_reference operator()(int const &, int const &) const
+    index_reference operator()(std::ptrdiff_t const &, std::ptrdiff_t const &) const
     {
         return value_;
     }
@@ -1463,9 +1463,9 @@ class ConstValueIterator
     /** @name Specify coordinate direction for navigation commands */
     //@{
         /// refer to x coordinate
-    int x;
+    std::ptrdiff_t x;
         /// refer to y coordinate
-    int y;
+    std::ptrdiff_t y;
     //@}
 
   private:
diff --git a/include/vigra/impex.hxx b/include/vigra/impex.hxx
index 00c5eb2..b492f0f 100644
--- a/include/vigra/impex.hxx
+++ b/include/vigra/impex.hxx
@@ -240,7 +240,8 @@ namespace vigra
                     ImageIterator image_iterator, ImageAccessor image_accessor,
                     /* isScalar? */ VigraFalseType)
         {
-            vigra_precondition(import_info.numBands() == image_accessor.size(image_iterator) ||
+            vigra_precondition((static_cast<unsigned int>(import_info.numBands())
+                                == image_accessor.size(image_iterator)) ||
                                import_info.numBands() == 1,
                 "importImage(): Number of channels in input and destination image don't match.");
 
diff --git a/include/vigra/impexalpha.hxx b/include/vigra/impexalpha.hxx
index 0426d67..41299fc 100644
--- a/include/vigra/impexalpha.hxx
+++ b/include/vigra/impexalpha.hxx
@@ -789,7 +789,7 @@ namespace vigra
 
             encoder->setPixelType(pixel_type);
 
-            vigra_precondition(isBandNumberSupported(encoder->getFileType(), image_accessor.size(image_upper_left)),
+            vigra_precondition(isBandNumberSupported(encoder->getFileType(), image_accessor.size(image_upper_left) + 1U),
                                "exportImageAlpha(): file format does not support requested number of bands (color channels)");
 
             const range_t image_source_range(find_source_value_range(export_info,
diff --git a/include/vigra/impexbase.hxx b/include/vigra/impexbase.hxx
index 7a1fbc8..2c1084a 100644
--- a/include/vigra/impexbase.hxx
+++ b/include/vigra/impexbase.hxx
@@ -62,7 +62,11 @@ namespace vigra
         inline static pixel_t
         pixel_t_of_string(const std::string& pixel_type)
         {
-            if (pixel_type == "UINT8")
+            if (pixel_type == "BILEVEL")
+            {
+                return UNSIGNED_INT_8;
+            }
+            else if (pixel_type == "UINT8")
             {
                 return UNSIGNED_INT_8;
             }
diff --git a/include/vigra/integral_image.hxx b/include/vigra/integral_image.hxx
new file mode 100644
index 0000000..1fb4149
--- /dev/null
+++ b/include/vigra/integral_image.hxx
@@ -0,0 +1,219 @@
+/************************************************************************/
+/*                                                                      */
+/*    Copyright 2012-2013 by Ullrich Koethe and Anna Kreshuk            */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_INTEGRALIMAGE_HXX
+#define VIGRA_INTEGRALIMAGE_HXX
+
+#include <vigra/multi_array.hxx>
+#include <vigra/multi_pointoperators.hxx>
+#include <vigra/utilities.hxx>
+#include <vigra/functorexpression.hxx>
+
+namespace vigra {
+
+template <unsigned int N, class T1, class S1, class T2, class S2, class FUNCTOR>
+void 
+cumulativeSum(MultiArrayView<N, T1, S1> const & image, 
+              MultiArrayView<N, T2, S2> out,
+              int axis,
+              FUNCTOR const & functor)
+{
+    typedef typename MultiArrayShape<N>::type ShapeN;
+    ShapeN offset = ShapeN::unitVector(axis);
+    
+    MultiCoordinateIterator<N> i(image.shape()),
+                               end(i.getEndIterator());
+    for(; i != end; ++i)
+    {
+        if((*i)[axis] == 0)
+        {
+            out[*i] = functor(image[*i]);
+        }
+        else
+        {
+            out[*i] = functor(image[*i]) + out[*i - offset];
+        }
+    }
+}
+
+template <unsigned int N, class T1, class S1, class T2, class S2, class FUNCTOR>
+void 
+integralMultiArrayImpl(MultiArrayView<N, T1, S1> const & array, 
+                       MultiArrayView<N, T2, S2> intarray,
+                       FUNCTOR const & f)
+{
+    vigra_precondition(array.shape() == intarray.shape(),
+        "integralMultiArray(): shape mismatch between input and output.");
+        
+    cumulativeSum(array, intarray, 0, f);
+    
+    for(int axis=1; axis < N; ++axis)
+        cumulativeSum(intarray, intarray, axis, functor::Identity());
+}
+
+template <class T1, class S1, class T2, class S2, class FUNCTOR>
+void 
+integralMultiArrayImpl(MultiArrayView<2, T1, S1> const & image, 
+                       MultiArrayView<2, T2, S2> intimage,
+                       FUNCTOR const & functor)
+{
+    vigra_precondition(image.shape() == intimage.shape(),
+        "integralMultiArray(): shape mismatch between input and output.");
+        
+    int width = image.shape(0);
+    int height = image.shape(1);
+
+    T2 s = T2();
+    for (int x=0; x<width; ++x)
+    {
+        s += functor(image(x, 0));
+        intimage(x, 0) = s;
+    }
+    for (int y=1; y<height; ++y)
+    {
+        s = T2();
+        for (int x=0; x<width; ++x)
+        {
+            s += functor(image(x, y));
+            intimage(x, y) = s + intimage(x, y-1);
+        }
+    }
+}
+
+template <class T1, class S1, class T2, class S2, class FUNCTOR>
+void 
+integralMultiArrayImpl(MultiArrayView<3, T1, S1> const & volume, 
+                       MultiArrayView<3, T2, S2> intvolume,
+                       FUNCTOR const & functor)
+{
+    vigra_precondition(volume.shape() == intvolume.shape(),
+        "integralMultiArray(): shape mismatch between input and output.");
+        
+    int nx = volume.shape(0);
+    int ny = volume.shape(1);
+    int nz = volume.shape(2);
+
+    //this vector will store s2(x, y-1) for all values of x
+    MultiArray<1, T2> s2_temp(nx);
+    
+    T2 s1 = T2();
+    T2 s2 = T2();
+
+    for (int iy=0; iy<ny; ++iy)
+    {
+        s1 = T2();
+        for (int ix=0; ix<nx; ++ix)
+        {
+            s1 += functor(volume(ix, iy, 0));
+            s2 = s2_temp(ix) + s1;
+            s2_temp(ix) = s2;
+            intvolume(ix, iy, 0) = s2;
+        }
+    }
+    
+    for (int iz=1; iz<nz; ++iz)
+    {    
+        s2_temp = T2();
+        
+        for (int iy=0; iy<ny; ++iy)
+        {
+            s1 = T2();
+            for (int ix=0; ix<nx; ++ix)
+            {
+                s1 += functor(volume(ix, iy, iz));
+                s2 = s2_temp(ix) + s1;
+                s2_temp(ix) = s2;
+                intvolume(ix, iy, iz) = s2 + intvolume(ix, iy, iz-1);
+            }
+        }
+    }
+}
+
+template <unsigned int N, class T1, class S1, class T2, class S2, class FUNCTOR>
+inline void 
+integralMultiArray(MultiArrayView<N, T1, S1> const & array, 
+                   MultiArrayView<N, T2, S2> intarray,
+                   FUNCTOR const & f)
+{
+    integralMultiArrayImpl(array, intarray, f);
+}
+
+template <unsigned int N, class T1, class S1, class T2, class S2, class FUNCTOR>
+inline void 
+integralMultiArray(MultiArrayView<N, Multiband<T1>, S1> const & array, 
+                   MultiArrayView<N, Multiband<T2>, S2> intarray,
+                   FUNCTOR const & f)
+{
+    for(int channel=0; channel < array.shape(N-1); ++channel)
+        integralMultiArrayImpl(array.bindOuter(channel), intarray.bindOuter(channel), f);
+}
+
+template <unsigned int N, class T1, class S1, class T2, class S2>
+inline void 
+integralMultiArray(MultiArrayView<N, T1, S1> const & array, 
+                   MultiArrayView<N, T2, S2> intarray)
+{
+    integralMultiArray(array, intarray, functor::Identity());
+}
+
+template <unsigned int N, class T1, class S1, class T2, class S2>
+inline void 
+integralMultiArray(MultiArrayView<N, Multiband<T1>, S1> const & array, 
+                   MultiArrayView<N, Multiband<T2>, S2> intarray)
+{
+    integralMultiArray(array, intarray, functor::Identity());
+}
+
+template <unsigned int N, class T1, class S1, class T2, class S2>
+inline void 
+integralMultiArraySquared(MultiArrayView<N, T1, S1> const & array, 
+                          MultiArrayView<N, T2, S2> intarray)
+{
+    using namespace functor;
+    integralMultiArray(array, intarray, sq(Arg1()));
+}
+
+template <unsigned int N, class T1, class S1, class T2, class S2>
+inline void 
+integralMultiArraySquared(MultiArrayView<N, Multiband<T1>, S1> const & array, 
+                          MultiArrayView<N, Multiband<T2>, S2> intarray)
+{
+    using namespace functor;
+    integralMultiArray(array, intarray, sq(Arg1()));
+}
+
+} // namespace vigra
+    
+#endif // VIGRA_INTEGRALIMAGE_HXX
diff --git a/include/vigra/iteratoradapter.hxx b/include/vigra/iteratoradapter.hxx
index 3d86c0e..d447ed0 100644
--- a/include/vigra/iteratoradapter.hxx
+++ b/include/vigra/iteratoradapter.hxx
@@ -32,11 +32,10 @@
 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
 /*                                                                      */
 /************************************************************************/
-
-
 #ifndef VIGRA_ITERATORADAPTER_HXX
 #define VIGRA_ITERATORADAPTER_HXX
 
+
 namespace vigra {
 
 /********************************************************/
@@ -296,6 +295,27 @@ class IteratorAdaptor
     BaseType adaptee_;
 };
 
+
+
+
+
+
+
+
+namespace detail_iterator_facade{
+
+
+
+
+}
+
+
+
+
+
+
+
+
 } // namespace vigra
 
 
diff --git a/include/vigra/iteratorfacade.hxx b/include/vigra/iteratorfacade.hxx
new file mode 100644
index 0000000..59b6251
--- /dev/null
+++ b/include/vigra/iteratorfacade.hxx
@@ -0,0 +1,174 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2014 by Thorsten Beier                       */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*                                                                      */
+/************************************************************************/
+#ifndef VIGRA_ITERATORFACADE_HXX
+#define VIGRA_ITERATORFACADE_HXX
+
+/*std*/
+#include <iterator> 
+
+/*vigra*/
+#include "metaprogramming.hxx"
+
+namespace vigra {
+
+// facade needs to make this class 
+// a friend class
+class IteratorFacadeCoreAccess{
+public:
+    template<class F>
+    static bool equal(const F & fa,const F & fb){
+        return fa.equal(fb);
+    }
+
+    template<class F,class REFERENCE>
+    static REFERENCE dereference(const F & f){
+        return f.dereference();
+    }
+
+    template<class F>
+    static void increment(F & f){
+        f.increment();
+    }
+};
+
+
+// see boost iterator facade 
+template<class FACADE,class VALUE_TYPE,bool IS_CONST = true>
+class ForwardIteratorFacade{
+private:
+    
+public:
+
+    typedef std::forward_iterator_tag iterator_category;
+    typedef typename UnqualifiedType<VALUE_TYPE>::type value_type;
+    typedef typename IfBool<IS_CONST, value_type const * , value_type *>::type  pointer;
+    typedef typename IfBool<IS_CONST, const value_type  & , value_type &>::type  reference;
+    typedef std::ptrdiff_t difference_type;
+    
+
+    FACADE & operator++()
+    {
+        IteratorFacadeCoreAccess::increment(getF());
+        return getF();
+    }
+
+    FACADE operator++(int)
+    {
+        FACADE res(getF());
+        IteratorFacadeCoreAccess::increment(getF());
+        return res;
+    }
+
+    bool operator ==(const FACADE & f)const{
+        return IteratorFacadeCoreAccess::equal(getF(),f);
+    }
+    bool operator !=(const FACADE & f)const{
+        return !IteratorFacadeCoreAccess::equal(getF(),f);
+    }
+
+    reference operator*()const{
+        return IteratorFacadeCoreAccess:: template dereference<FACADE,reference>(getF());
+    }
+
+    pointer operator->()const{
+        return &IteratorFacadeCoreAccess:: template dereference<FACADE,reference>(getF());
+    }
+
+private:
+
+
+    const FACADE & getF()const{
+        return *static_cast<FACADE const *>(this);
+    }
+    FACADE & getF(){
+        return *static_cast<FACADE *>(this);
+    }
+};
+
+template<class MAP>
+class MapKeyIterator
+ : public ForwardIteratorFacade<MapKeyIterator<MAP>,typename MAP::key_type,true>
+{
+
+public:
+    typedef ForwardIteratorFacade<MapKeyIterator<MAP>,typename MAP::key_type,true> BaseType;
+    typedef typename MAP::const_iterator InternalIterator;
+    typedef typename BaseType::value_type value_type;
+    typedef typename BaseType::reference reference;
+    typedef typename BaseType::pointer pointer;
+    
+    MapKeyIterator(InternalIterator i)
+    : iter_(i)
+    {}
+
+  private:
+
+    friend class IteratorFacadeCoreAccess;
+    
+    bool equal(const MapKeyIterator & other) const{
+        return iter_ == other.iter_;
+    }
+
+    void increment(){
+        ++iter_;
+    }
+    
+    reference dereference()const{
+        return iter_->first;
+    }
+    
+    InternalIterator iter_;
+};
+
+template <class MAP>
+inline MapKeyIterator<MAP>
+key_begin(MAP const & m)
+{
+    return MapKeyIterator<MAP>(m.begin());
+
+}
+
+template <class MAP>
+inline MapKeyIterator<MAP>
+key_end(MAP const & m)
+{
+    return MapKeyIterator<MAP>(m.end());
+
+}
+
+} // namespace vigra
+
+
+#endif /* VIGRA_ITERATORFACADE_HXX */
diff --git a/include/vigra/iteratortraits.hxx b/include/vigra/iteratortraits.hxx
index e7f3577..dd83e45 100644
--- a/include/vigra/iteratortraits.hxx
+++ b/include/vigra/iteratortraits.hxx
@@ -165,7 +165,7 @@ struct IteratorTraitsBase
 
     The argument objects are created via a number of factory functions.
     Since these functions have descriptive names, they also serve
-    to improve readability: the name of each factory tells te purpose of its
+    to improve readability: the name of each factory tells the purpose of its
     argument object.
 
     Consider the following example. Without argument objects we had to
diff --git a/include/vigra/labelimage.hxx b/include/vigra/labelimage.hxx
index 13bfe8b..da22c00 100644
--- a/include/vigra/labelimage.hxx
+++ b/include/vigra/labelimage.hxx
@@ -61,6 +61,8 @@ namespace vigra {
 
 /** \brief Find the connected components of a segmented image.
 
+    Deprecated. Use \ref labelMultiArray() instead.
+
     Connected components are defined as regions with uniform pixel
     values. Thus, <TT>T1</TT> either must be
     equality comparable, or a suitable EqualityFunctor must be
@@ -70,13 +72,13 @@ namespace vigra {
     starting with one and ending with the region number returned by
     the function (inclusive). The parameter '<TT>eight_neighbors</TT>'
     determines whether the regions should be 4-connected (false) or
-    8-connected (true). 
+    8-connected (true).
 
     Return:  the number of regions found (= largest region label)
-    
-    See \ref labelMultiArray() for a dimension-independent implementation of 
+
+    See \ref labelMultiArray() for a dimension-independent implementation of
     connected components labelling.
-    
+
     <b> Declarations:</b>
 
     pass 2D array views:
@@ -191,7 +193,7 @@ unsigned int labelImage(SrcIterator upperlefts,
                         bool eight_neighbors, EqualityFunctor equal)
 {
     typedef typename DestAccessor::value_type LabelType;
-    
+
     int w = lowerrights.x - upperlefts.x;
     int h = lowerrights.y - upperlefts.y;
     int x,y,i;
@@ -208,8 +210,8 @@ unsigned int labelImage(SrcIterator upperlefts,
 
     SrcIterator ys = upperlefts;
     DestIterator yd = upperleftd;
-    
-    detail::UnionFindArray<LabelType>  label;    
+
+    UnionFindArray<LabelType>  label;
 
     // pass 1: scan image from upper left to lower right
     // to find connected components
@@ -242,39 +244,39 @@ unsigned int labelImage(SrcIterator upperlefts,
             {
                 if(equal(sa(xs), sa(xs, neighbor[i])))
                 {
-                    LabelType neighborLabel = label.find(da(xd,neighbor[i]));
+                    LabelType neighborIndex = label.findIndex(da(xd,neighbor[i]));
 
                     for(int j=i+2; j<=endNeighbor; j+=step)
                     {
                         if(equal(sa(xs), sa(xs, neighbor[j])))
                         {
-                            neighborLabel = label.makeUnion(da(xd, neighbor[j]), neighborLabel);
+                            neighborIndex = label.makeUnion(da(xd, neighbor[j]), neighborIndex);
                             break;
                         }
                     }
-                    da.set(neighborLabel, xd);
+                    da.set(neighborIndex, xd);
                     break;
                 }
 
             }
             if(i > endNeighbor)
             {
-                da.set(label.makeNewLabel(), xd);
+                da.set(label.makeNewIndex(), xd);
             }
         }
     }
 
     // pass 2: assign one label to each region (tree)
     // so that labels form a consecutive sequence 1, 2, ...
-    unsigned int count = label.makeContiguous();    
-    
+    unsigned int count = label.makeContiguous();
+
     yd = upperleftd;
     for(y=0; y != h; ++y, ++yd.y)
     {
         typename DestIterator::row_iterator xd = yd.rowIterator();
         for(x = 0; x != w; ++x, ++xd)
         {
-            da.set(label[da(xd)], xd);
+            da.set(label.findLabel(da(xd)), xd);
         }
     }
     return count;
@@ -352,6 +354,8 @@ labelImage(MultiArrayView<2, T1, S1> const & src,
 /** \brief Find the connected components of a segmented image,
     excluding the background from labeling.
 
+    Deprecated. Use \ref labelMultiArray() instead.
+
     This function works like \ref labelImage(), but considers all background pixels
     (i.e. pixels having the given '<TT>background_value</TT>') as a single region that
     is ignored when determining connected components and remains untouched in the
@@ -359,7 +363,7 @@ labelImage(MultiArrayView<2, T1, S1> const & src,
     the background gets label 0 (remember that actual region labels start at one).
 
     Return:  the number of non-background regions found (= largest region label)
-    
+
     See \ref labelMultiArrayWithBackground() for a dimension-independent implementation
     if this algorithm.
 
@@ -370,13 +374,13 @@ labelImage(MultiArrayView<2, T1, S1> const & src,
     namespace vigra {
         template <class T1, class S1,
                   class T2, class S2,
-                  class ValueType, 
+                  class ValueType,
                   class EqualityFunctor = std::equal_to<T1> >
-        unsigned int 
+        unsigned int
         labelImageWithBackground(MultiArrayView<2, T1, S1> const & src,
                                  MultiArrayView<2, T2, S2> dest,
                                  bool eight_neighbors,
-                                 ValueType background_value, 
+                                 ValueType background_value,
                                  EqualityFunctor equal = EqualityFunctor());
     }
     \endcode
@@ -480,7 +484,7 @@ labelImage(MultiArrayView<2, T1, S1> const & src,
     \deprecatedEnd
 */
 doxygen_overloaded_function(template <...> unsigned int labelImageWithBackground)
-    
+
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor,
           class ValueType, class EqualityFunctor>
@@ -507,7 +511,7 @@ unsigned int labelImageWithBackground(
 
     SrcIterator ys(upperlefts);
     SrcIterator xs(ys);
-    
+
     // temporary image to store region labels
     typedef BasicImage<IntBiggest> TmpImage;
     TmpImage labelimage(w, h);
@@ -540,7 +544,7 @@ unsigned int labelImageWithBackground(
                 {
                     if(equal(sa(xs), sa(xs, neighbor[i])))
                     {
-                        IntBiggest neighborLabel = xt[neighbor[i]];
+                        IntBiggest neighborIndex = xt[neighbor[i]];
 
                         for(int j=i+2; j<=endNeighbor; j+=step)
                         {
@@ -548,12 +552,12 @@ unsigned int labelImageWithBackground(
                             {
                                 IntBiggest neighborLabel1 = xt[neighbor[j]];
 
-                                if(neighborLabel != neighborLabel1)
+                                if(neighborIndex != neighborLabel1)
                                 {
                                     // find roots of the region trees
-                                    while(neighborLabel != label[neighborLabel])
+                                    while(neighborIndex != label[neighborIndex])
                                     {
-                                        neighborLabel = label[neighborLabel];
+                                        neighborIndex = label[neighborIndex];
                                     }
                                     while(neighborLabel1 != label[neighborLabel1])
                                     {
@@ -561,20 +565,20 @@ unsigned int labelImageWithBackground(
                                     }
 
                                     // merge the trees
-                                    if(neighborLabel1 < neighborLabel)
+                                    if(neighborLabel1 < neighborIndex)
                                     {
-                                        label[neighborLabel] = neighborLabel1;
-                                        neighborLabel = neighborLabel1;
+                                        label[neighborIndex] = neighborLabel1;
+                                        neighborIndex = neighborLabel1;
                                     }
-                                    else if(neighborLabel < neighborLabel1)
+                                    else if(neighborIndex < neighborLabel1)
                                     {
-                                        label[neighborLabel1] = neighborLabel;
+                                        label[neighborLabel1] = neighborIndex;
                                     }
                                 }
                                 break;
                             }
                         }
-                        *xt = neighborLabel;
+                        *xt = neighborIndex;
                         break;
                     }
 
@@ -638,7 +642,7 @@ unsigned int labelImageWithBackground(
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor,
           class ValueType, class EqualityFunctor>
-inline unsigned int 
+inline unsigned int
 labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                          pair<DestIterator, DestAccessor> dest,
                          bool eight_neighbors,
@@ -667,7 +671,7 @@ labelImageWithBackground(triple<SrcIterator, SrcIterator, SrcAccessor> src,
 template <class T1, class S1,
           class T2, class S2,
           class ValueType, class EqualityFunctor>
-inline unsigned int 
+inline unsigned int
 labelImageWithBackground(MultiArrayView<2, T1, S1> const & src,
                          MultiArrayView<2, T2, S2> dest,
                          bool eight_neighbors,
@@ -712,7 +716,7 @@ labelImageWithBackground(MultiArrayView<2, T1, S1> const & src,
     namespace vigra {
         template <class T1, class S1,
                   class T2, class S2, class DestValue>
-        void 
+        void
         regionImageToCrackEdgeImage(MultiArrayView<2, T1, S1> const & src,
                                     MultiArrayView<2, T2, S2> dest,
                                     DestValue edge_marker);
@@ -932,7 +936,7 @@ void regionImageToCrackEdgeImage(
 
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor, class DestValue>
-inline void 
+inline void
 regionImageToCrackEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                             pair<DestIterator, DestAccessor> dest,
                             DestValue edge_marker)
@@ -944,7 +948,7 @@ regionImageToCrackEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
 
 template <class T1, class S1,
           class T2, class S2, class DestValue>
-inline void 
+inline void
 regionImageToCrackEdgeImage(MultiArrayView<2, T1, S1> const & src,
                             MultiArrayView<2, T2, S2> dest,
                             DestValue edge_marker)
@@ -971,7 +975,7 @@ regionImageToCrackEdgeImage(MultiArrayView<2, T1, S1> const & src,
     namespace vigra {
         template <class T1, class S1,
                   class T2, class S2, class DestValue>
-        void 
+        void
         regionImageToEdgeImage(MultiArrayView<2, T1, S1> const & src,
                                MultiArrayView<2, T2, S2> dest,
                                DestValue edge_marker);
@@ -1136,7 +1140,7 @@ void regionImageToEdgeImage(
 
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor, class DestValue>
-inline void 
+inline void
 regionImageToEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                        pair<DestIterator, DestAccessor> dest,
                        DestValue edge_marker)
@@ -1148,7 +1152,7 @@ regionImageToEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
 
 template <class T1, class S1,
           class T2, class S2, class DestValue>
-inline void 
+inline void
 regionImageToEdgeImage(MultiArrayView<2, T1, S1> const & src,
                        MultiArrayView<2, T2, S2> dest,
                        DestValue edge_marker)
diff --git a/include/vigra/labelvolume.hxx b/include/vigra/labelvolume.hxx
index abf7396..fccee05 100644
--- a/include/vigra/labelvolume.hxx
+++ b/include/vigra/labelvolume.hxx
@@ -29,7 +29,7 @@
 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
-/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
 
@@ -57,18 +57,20 @@ namespace vigra{
 
 /** \brief Find the connected components of a segmented volume.
 
+    Deprecated. Use \ref labelMultiArray() instead.
+
     Connected components are defined as regions with uniform voxel
-    values. Thus, <TT>T1</TT> either must be equality comparable, 
-    or an EqualityFunctor must be provided explicitly that realizes 
-    the desired equivalence predicate. The destination's value type 
+    values. Thus, <TT>T1</TT> either must be equality comparable,
+    or an EqualityFunctor must be provided explicitly that realizes
+    the desired equivalence predicate. The destination's value type
     <tt>T2</tt> should be large enough to hold the labels
     without overflow. Region numbers will be a consecutive sequence
     starting with one and ending with the region number returned by
     the function (inclusive).
 
     Return:  the number of regions found (= largest region label)
-    
-    See \ref labelMultiArray() for a dimension-independent implementation of 
+
+    See \ref labelMultiArray() for a dimension-independent implementation of
     connected components labelling.
 
     <b> Declarations:</b>
@@ -78,7 +80,7 @@ namespace vigra{
     namespace vigra {
         template <class T1, class S1,
                   class T2, class S2,
-                  class Neighborhood3D, 
+                  class Neighborhood3D,
                   class EqualityFunctor = std::equal_to<T1> >
         unsigned int
         labelVolume(MultiArrayView<3, T1, S1> const & source,
@@ -132,16 +134,16 @@ namespace vigra{
     \endcode
     use with 3D-Six-Neighborhood:
     \code
-    namespace vigra {    
-    
+    namespace vigra {
+
         template <class SrcIterator, class SrcAccessor,class SrcShape,
                   class DestIterator, class DestAccessor>
         unsigned int labelVolumeSix(triple<SrcIterator, SrcShape, SrcAccessor> src,
                                     pair<DestIterator, DestAccessor> dest);
-                                    
+
     }
     \endcode
-    \deprecatedEnd    
+    \deprecatedEnd
 
     <b> Usage:</b>
 
@@ -152,7 +154,7 @@ namespace vigra{
     typedef MultiArray<3,int> IntVolume;
     IntVolume src(Shape3(w,h,d));
     IntVolume dest(Shape3(w,h,d));
-    
+
     // find 6-connected regions
     int max_region_label = labelVolumeSix(src, dest);
 
@@ -165,7 +167,7 @@ namespace vigra{
     typedef vigra::MultiArray<3,int> IntVolume;
     IntVolume src(IntVolume::difference_type(w,h,d));
     IntVolume dest(IntVolume::difference_type(w,h,d));
-    
+
     // find 6-connected regions
     int max_region_label = vigra::labelVolumeSix(srcMultiArrayRange(src), destMultiArray(dest));
 
@@ -204,14 +206,14 @@ unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
                          Neighborhood3D, EqualityFunctor equal)
 {
     typedef typename DestAccessor::value_type LabelType;
-    
+
     //basically needed for iteration and border-checks
     int w = srcShape[0], h = srcShape[1], d = srcShape[2];
-    int x,y,z;       
-        
+    int x,y,z;
+
     // temporary image to store region labels
-    detail::UnionFindArray<LabelType>  label;
-        
+    UnionFindArray<LabelType>  label;
+
     //Declare traversers for all three dims at target
     SrcIterator zs = s_Iter;
     DestIterator zd = d_Iter;
@@ -244,7 +246,7 @@ unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
 
             for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0())
             {
-                LabelType currentLabel = label.nextFreeLabel();
+                LabelType currentIndex = label.nextFreeIndex();
 
                 //check whether there is a special border treatment to be used or not
                 AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,d);
@@ -253,47 +255,42 @@ unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
                 if(atBorder == NotAtBorder)
                 {
                     NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst);
-                
+
                     do
-                    {            
+                    {
                         // if colors are equal
                         if(equal(sa(xs), sa(xs, *nc)))
                         {
-                            currentLabel = label.makeUnion(label[da(xd,*nc)], currentLabel);
+                            currentIndex = label.makeUnion(da(xd,*nc), currentIndex);
                         }
                         ++nc;
                     }
                     while(nc!=nce);
-                }               
+                }
                 else //we are at a border - handle this!!
                 {
                     NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::nearBorderDirectionsCausal(atBorder,0));
                     int j=0;
                     while(nc.direction() != Neighborhood3D::Error)
                     {
-                        
-                        SrcShape s(x,y,z), sn = s + *nc;
-                        
-                        if (sn[0]<0 || sn[0]>=w || sn[1]<0 || sn[1]>=h || sn[2]<0 || sn[2]>=d)
-                        {  
-                          std::cerr << "coordinate error at " << s << ", offset " << *nc << ", index " << (nc).direction() << " at border " <<
-                                                                                                                              atBorder << std::endl;
-                        
+                        int dummy = x+(*nc)[0];  // prevents an apparently incorrect optimization in gcc 4.8
+                        if (dummy<0)
+                        {
+                            std::cerr << "internal error " << dummy << std::endl;
                         }
-                        
                         //   colors equal???
                         if(equal(sa(xs), sa(xs, *nc)))
                         {
-                            currentLabel = label.makeUnion(label[da(xd,*nc)], currentLabel);
+                            currentIndex = label.makeUnion(da(xd,*nc), currentIndex);
                         }
                         nc.turnTo(Neighborhood3D::nearBorderDirectionsCausal(atBorder,++j));
                     }
                 }
-                da.set(label.finalizeLabel(currentLabel), xd);
+                da.set(label.finalizeIndex(currentIndex), xd);
             }
         }
     }
-    
+
     LabelType count = label.makeContiguous();
 
     // pass 2: assign one label to each region (tree)
@@ -309,7 +306,7 @@ unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
 
             for(x = 0; x != w; ++x, ++xd.dim0())
             {
-                da.set(label[da(xd)], xd);
+                da.set(label.findLabel(da(xd)), xd);
             }
         }
     }
@@ -326,7 +323,7 @@ unsigned int labelVolume(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
         return labelVolume(s_Iter, srcShape, sa, d_Iter, da, neighborhood3D, std::equal_to<typename SrcAccessor::value_type>());
 }
 
-template <class SrcIterator, class SrcShape, class SrcAccessor, 
+template <class SrcIterator, class SrcShape, class SrcAccessor,
           class DestIterator, class DestAccessor,
           class Neighborhood3D>
 unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
@@ -346,7 +343,7 @@ unsigned int labelVolume(triple<SrcIterator, SrcShape, SrcAccessor> src,
     return labelVolume(src.first, src.second, src.third, dest.first, dest.second, neighborhood3D, equal);
 }
 
-template <class T1, class S1, 
+template <class T1, class S1,
           class T2, class S2,
           class Neighborhood3D, class EqualityFunctor>
 inline unsigned int
@@ -360,7 +357,7 @@ labelVolume(MultiArrayView<3, T1, S1> const & source,
     return labelVolume(srcMultiArrayRange(source), destMultiArray(dest), neighborhood3D, equal);
 }
 
-template <class T1, class S1, 
+template <class T1, class S1,
           class T2, class S2,
           class Neighborhood3D>
 inline unsigned int
@@ -381,7 +378,7 @@ labelVolume(MultiArrayView<3, T1, S1> const & source,
 
 /** \brief Find the connected components of a segmented volume
      using the 6-neighborhood.
-     
+
      See \ref labelVolume() for detailed documentation.
 
 */
@@ -398,7 +395,7 @@ template <class T1, class S1,
 unsigned int labelVolumeSix(MultiArrayView<3, T1, S1> const & source,
                             MultiArrayView<3, T2, S2> dest)
 {
-    return labelVolume(srcMultiArrayRange(source), destMultiArray(dest), 
+    return labelVolume(srcMultiArrayRange(source), destMultiArray(dest),
                        NeighborCode3DSix(), std::equal_to<T1>());
 }
 
@@ -411,6 +408,8 @@ unsigned int labelVolumeSix(MultiArrayView<3, T1, S1> const & source,
 /** \brief Find the connected components of a segmented volume,
      excluding the background from labeling.
 
+    Deprecated. Use \ref labelMultiArray() instead.
+
     This function works like \ref labelVolume(), but considers all background voxels
     (i.e. voxels having the given '<TT>background_value</TT>') as a single region that
     is ignored when determining connected components and remains untouched in the
@@ -493,7 +492,7 @@ unsigned int labelVolumeSix(MultiArrayView<3, T1, S1> const & source,
 
     \code
     typedef vigra::MultiArray<3,int> IntVolume;
-    
+
     IntVolume src(Shape3(w,h,d));
     IntVolume dest(Shape3(w,h,d));
 
@@ -544,14 +543,14 @@ unsigned int labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShape, Sr
                                        ValueType backgroundValue, EqualityFunctor equal)
 {
     typedef typename DestAccessor::value_type LabelType;
-    
+
     //basically needed for iteration and border-checks
     int w = srcShape[0], h = srcShape[1], d = srcShape[2];
-    int x,y,z;       
-        
+    int x,y,z;
+
     // temporary image to store region labels
-    detail::UnionFindArray<LabelType>  label;
-        
+    UnionFindArray<LabelType>  label;
+
     //Declare traversers for all three dims at target
     SrcIterator zs = s_Iter;
     DestIterator zd = d_Iter;
@@ -586,58 +585,56 @@ unsigned int labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShape, Sr
             {
                 if(equal(sa(xs), backgroundValue))
                 {
-                    da.set(label[0], xd);
+                    //da.set(label.getIndex(0), xd);
+                    da.set(0, xd);
                     continue;
                 }
 
-                LabelType currentLabel = label.nextFreeLabel();
+                LabelType currentIndex = label.nextFreeIndex();
 
                 //check whether there is a special border treatment to be used or not
                 AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,d);
-                    
+
                 //We are not at the border!
                 if(atBorder == NotAtBorder)
                 {
                     NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst);
-                
+
                     do
-                    {            
+                    {
                         // if colors are equal
                         if(equal(sa(xs), sa(xs, *nc)))
                         {
-                            currentLabel = label.makeUnion(label[da(xd,*nc)], currentLabel);
+                            currentIndex = label.makeUnion(da(xd,*nc), currentIndex);
                         }
                         ++nc;
                     }
                     while(nc!=nce);
-                }               
+                }
                 else //we are at a border - handle this!!
                 {
                     NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::nearBorderDirectionsCausal(atBorder,0));
                     int j=0;
                     while(nc.direction() != Neighborhood3D::Error)
                     {
-                        SrcShape s(x,y,z), sn = s + *nc;
-                        
-                        if (sn[0]<0 || sn[0]>=w || sn[1]<0 || sn[1]>=h || sn[2]<0 || sn[2]>=d)
-                        {  
-                          std::cerr << "coordinate error at " << s << ", offset " << *nc << ", index " << (nc).direction() << " at border " <<
-                                                                                                                              atBorder << std::endl;
-                        
+                        int dummy = x+(*nc)[0];  // prevents an apparently incorrect optimization in gcc 4.8
+                        if (dummy<0)
+                        {
+                            std::cerr << "internal error " << dummy << std::endl;
                         }
                         //   colors equal???
                         if(equal(sa(xs), sa(xs, *nc)))
                         {
-                            currentLabel = label.makeUnion(label[da(xd,*nc)], currentLabel);
+                            currentIndex = label.makeUnion(da(xd,*nc), currentIndex);
                         }
                         nc.turnTo(Neighborhood3D::nearBorderDirectionsCausal(atBorder,++j));
                     }
                 }
-                da.set(label.finalizeLabel(currentLabel), xd);
+                da.set(label.finalizeIndex(currentIndex), xd);
             }
         }
     }
-    
+
     LabelType count = label.makeContiguous();
 
     // pass 2: assign one label to each region (tree)
@@ -653,7 +650,7 @@ unsigned int labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShape, Sr
 
             for(x = 0; x != w; ++x, ++xd.dim0())
             {
-                da.set(label[da(xd)], xd);
+                da.set(label.findLabel(da(xd)), xd);
             }
         }
     }
@@ -664,7 +661,7 @@ template <class SrcIterator, class SrcAccessor,class SrcShape,
           class DestIterator, class DestAccessor,
           class Neighborhood3D,
           class ValueType>
-inline unsigned int 
+inline unsigned int
 labelVolumeWithBackground(SrcIterator s_Iter, SrcShape srcShape, SrcAccessor sa,
                           DestIterator d_Iter, DestAccessor da,
                           Neighborhood3D neighborhood3D, ValueType backgroundValue)
@@ -694,7 +691,7 @@ labelVolumeWithBackground(triple<SrcIterator, SrcShape, SrcAccessor> src,
                           pair<DestIterator, DestAccessor> dest,
                           Neighborhood3D neighborhood3D, ValueType backgroundValue)
 {
-    return labelVolumeWithBackground(src.first, src.second, src.third, dest.first, dest.second, 
+    return labelVolumeWithBackground(src.first, src.second, src.third, dest.first, dest.second,
                                      neighborhood3D, backgroundValue, std::equal_to<typename SrcAccessor::value_type>());
 }
 
@@ -712,7 +709,7 @@ labelVolumeWithBackground(MultiArrayView<3, T1, S1> const & source,
 {
     vigra_precondition(source.shape() == dest.shape(),
         "labelVolumeWithBackground(): shape mismatch between input and output.");
-    return labelVolumeWithBackground(srcMultiArrayRange(source), destMultiArray(dest), 
+    return labelVolumeWithBackground(srcMultiArrayRange(source), destMultiArray(dest),
                                      neighborhood3D, backgroundValue, equal);
 }
 
@@ -728,7 +725,7 @@ labelVolumeWithBackground(MultiArrayView<3, T1, S1> const & source,
 {
     vigra_precondition(source.shape() == dest.shape(),
         "labelVolumeWithBackground(): shape mismatch between input and output.");
-    return labelVolumeWithBackground(srcMultiArrayRange(source), destMultiArray(dest), 
+    return labelVolumeWithBackground(srcMultiArrayRange(source), destMultiArray(dest),
                                      neighborhood3D, backgroundValue,
                                      std::equal_to<T1>());
 }
diff --git a/include/vigra/linear_solve.hxx b/include/vigra/linear_solve.hxx
index f6dd258..d7d2969 100644
--- a/include/vigra/linear_solve.hxx
+++ b/include/vigra/linear_solve.hxx
@@ -162,7 +162,7 @@ qrGivensStepImpl(MultiArrayIndex i, MultiArrayView<2, T, C1> r, MultiArrayView<2
                        "qrGivensStepImpl(): Matrix shape mismatch.");
 
     Matrix<T> givens(2,2);
-    for(int k=m-1; k>(int)i; --k)
+    for(int k=m-1; k>static_cast<int>(i); --k)
     {
         if(!givensReflectionMatrix(r(k-1,i), r(k,i), givens))
             continue; // r(k,i) was already zero
@@ -246,7 +246,7 @@ upperTriangularSwapColumns(MultiArrayIndex i, MultiArrayIndex j,
     std::swap(permutation[i], permutation[j]);
     
     Matrix<T> givens(2,2);
-    for(int k=m-1; k>(int)i; --k)
+    for(int k=m-1; k>static_cast<int>(i); --k)
     {
         if(!givensReflectionMatrix(r(k-1,i), r(k,i), givens))
             continue; // r(k,i) was already zero
@@ -390,12 +390,13 @@ incrementalMinSingularValueApproximation(MultiArrayView<2, T, C1> const & newCol
         return;
     }
     
-    T yv = dot(columnVector(newColumn, Shape(0,0),n), columnVector(z, Shape(0,0),n));
+    T yv = dot(columnVector(newColumn, Shape(0,0), static_cast<int>(n)),
+               columnVector(z, Shape(0,0), static_cast<int>(n)));
     // use atan2 as it is robust against overflow/underflow
     T t = 0.5*std::atan2(T(-2.0*yv), T(squaredNorm(gamma / v) + squaredNorm(yv) - 1.0)),
       s = std::sin(t),
       c = std::cos(t);
-    columnVector(z, Shape(0,0),n) *= c;
+    columnVector(z, Shape(0,0), static_cast<int>(n)) *= c;
     z(n,0) = (s - c*yv) / gamma;
     v *= norm(gamma) / hypot(c*gamma, v*(s - c*yv));
 }
@@ -427,7 +428,7 @@ qrTransformToTriangularImpl(MultiArrayView<2, T, C1> & r, MultiArrayView<2, T, C
                        "qrTransformToTriangularImpl(): Householder matrix shape mismatch.");
                        
     bool pivoting = permutation.size() > 0;
-    vigra_precondition(!pivoting || n == (MultiArrayIndex)permutation.size(),
+    vigra_precondition(!pivoting || n == static_cast<MultiArrayIndex>(permutation.size()),
                        "qrTransformToTriangularImpl(): Permutation array size mismatch.");
 
     if(n == 0)
@@ -482,7 +483,7 @@ qrTransformToTriangularImpl(MultiArrayView<2, T, C1> & r, MultiArrayView<2, T, C
             for(MultiArrayIndex l=k; l<n; ++l)
                 columnSquaredNorms[l] -= squaredNorm(r(k, l));
             int pivot = k + argMax(rowVector(columnSquaredNorms, Shape(0,k), n));
-            if(pivot != (int)k)
+            if(pivot != static_cast<int>(k))
             {
                 columnVector(r, k).swapData(columnVector(r, pivot));
                 std::swap(columnSquaredNorms[k], columnSquaredNorms[pivot]);
@@ -518,7 +519,7 @@ qrTransformToTriangularImpl(MultiArrayView<2, T, C1> & r, MultiArrayView<2, T, C
         else
             pivoting = false; // matrix doesn't have full rank, triangulize the rest without pivoting
     }
-    return (unsigned int)rank;
+    return static_cast<unsigned int>(rank);
 }
 
 template <class T, class C1, class C2>
@@ -536,8 +537,8 @@ unsigned int
 qrTransformToLowerTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2, T, C2> & rhs, MultiArrayView<2, T, C3> & householderMatrix, 
                       double epsilon = 0.0)
 {
-    ArrayVector<MultiArrayIndex> permutation((unsigned int)rowCount(rhs));
-    for(MultiArrayIndex k=0; k<(MultiArrayIndex)permutation.size(); ++k)
+    ArrayVector<MultiArrayIndex> permutation(static_cast<unsigned int>(rowCount(rhs)));
+    for(MultiArrayIndex k=0; k<static_cast<MultiArrayIndex>(permutation.size()); ++k)
         permutation[k] = k;
     Matrix<T> dontTransformRHS; // intentionally empty
     MultiArrayView<2, T, StridedArrayTag> rt = transpose(r),
@@ -546,7 +547,7 @@ qrTransformToLowerTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2, T,
     
     // apply row permutation to RHS
     Matrix<T> tempRHS(rhs);
-    for(MultiArrayIndex k=0; k<(MultiArrayIndex)permutation.size(); ++k)
+    for(MultiArrayIndex k=0; k<static_cast<MultiArrayIndex>(permutation.size()); ++k)
         rowVector(rhs, k) = rowVector(tempRHS, permutation[k]);
     return rank;
 }
@@ -560,7 +561,7 @@ qrTransformToUpperTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2, T,
     ArrayVector<MultiArrayIndex> noPivoting; // intentionally empty
     
     return (qrTransformToUpperTriangular(r, rhs, noPivoting, epsilon) == 
-            (unsigned int)columnCount(r));
+            static_cast<unsigned int>(columnCount(r)));
 }
 
 // QR algorithm without row pivoting
@@ -572,7 +573,7 @@ qrTransformToLowerTriangular(MultiArrayView<2, T, C1> & r, MultiArrayView<2, T,
     Matrix<T> noPivoting; // intentionally empty
     
     return (qrTransformToLowerTriangular(r, noPivoting, householder, epsilon) == 
-           (unsigned int)rowCount(r));
+           static_cast<unsigned int>(rowCount(r)));
 }
 
 // restore ordering of result vector elements after QR solution with column pivoting
@@ -632,7 +633,7 @@ linearSolveQRReplace(MultiArrayView<2, T, C1> &A, MultiArrayView<2, T, C2> &b,
         // minimum norm solution of underdetermined system
         Matrix<T> householderMatrix(n, m);
         MultiArrayView<2, T, StridedArrayTag> ht = transpose(householderMatrix);
-        rank = (MultiArrayIndex)detail::qrTransformToLowerTriangular(A, b, ht, epsilon);
+        rank = static_cast<MultiArrayIndex>(detail::qrTransformToLowerTriangular(A, b, ht, epsilon));
         res.subarray(Shape(rank,0), Shape(n, rhsCount)).init(NumericTraits<T>::zero());
         if(rank < m)
         {
@@ -655,11 +656,11 @@ linearSolveQRReplace(MultiArrayView<2, T, C1> &A, MultiArrayView<2, T, C2> &b,
     else
     {
         // solution of well-determined or overdetermined system
-        ArrayVector<MultiArrayIndex> permutation((unsigned int)n);
+        ArrayVector<MultiArrayIndex> permutation(static_cast<unsigned int>(n));
         for(MultiArrayIndex k=0; k<n; ++k)
             permutation[k] = k;
 
-        rank = (MultiArrayIndex)detail::qrTransformToUpperTriangular(A, b, permutation, epsilon);
+        rank = static_cast<MultiArrayIndex>(detail::qrTransformToUpperTriangular(A, b, permutation, epsilon));
         
         Matrix<T> permutedSolution(n, rhsCount);
         if(rank < n)
@@ -683,7 +684,7 @@ linearSolveQRReplace(MultiArrayView<2, T, C1> &A, MultiArrayView<2, T, C2> &b,
         }
         detail::inverseRowPermutation(permutedSolution, res, permutation);
     }
-    return (unsigned int)rank;
+    return static_cast<unsigned int>(rank);
 }
 
 template <class T, class C1, class C2, class C3>
@@ -973,7 +974,7 @@ bool qrDecomposition(MultiArrayView<2, T, C1> const & a,
     MultiArrayView<2,T, StridedArrayTag> tq = transpose(q);
     r = a;
     ArrayVector<MultiArrayIndex> noPivoting; // intentionally empty
-    return ((MultiArrayIndex)detail::qrTransformToUpperTriangular(r, tq, noPivoting, epsilon) == std::min(m,n));
+    return (static_cast<MultiArrayIndex>(detail::qrTransformToUpperTriangular(r, tq, noPivoting, epsilon) == std::min(m,n)));
 }
 
     /** Deprecated, use \ref linearSolveUpperTriangular().
@@ -1217,7 +1218,7 @@ bool linearSolve(MultiArrayView<2, T, C1> const & A,
     }
     else if(method == "qr")
     {
-        return (MultiArrayIndex)linearSolveQR(A, b, res) == n;
+        return static_cast<MultiArrayIndex>(linearSolveQR(A, b, res)) == n;
     }
     else if(method == "ne")
     {
@@ -1228,7 +1229,7 @@ bool linearSolve(MultiArrayView<2, T, C1> const & A,
         MultiArrayIndex rhsCount = columnCount(b);
         Matrix<T> u(A.shape()), s(n, 1), v(n, n);
 
-        MultiArrayIndex rank = (MultiArrayIndex)singularValueDecomposition(A, u, s, v);
+        MultiArrayIndex rank = static_cast<MultiArrayIndex>(singularValueDecomposition(A, u, s, v));
 
         Matrix<T> t = transpose(u)*b;
         for(MultiArrayIndex l=0; l<rhsCount; ++l)
diff --git a/include/vigra/mathutil.hxx b/include/vigra/mathutil.hxx
index 2a3360b..5515ab6 100644
--- a/include/vigra/mathutil.hxx
+++ b/include/vigra/mathutil.hxx
@@ -29,7 +29,7 @@
 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
-/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
 
@@ -56,8 +56,8 @@
 
     <b>\#include</b> \<vigra/mathutil.hxx\>
 
-    Since mathematical constants such as <TT>M_PI</TT> and <TT>M_SQRT2</TT> 
-    are not officially standardized, we provide definitions here for those 
+    Since mathematical constants such as <TT>M_PI</TT> and <TT>M_SQRT2</TT>
+    are not officially standardized, we provide definitions here for those
     compilers that don't support them.
 
     \code
@@ -123,15 +123,15 @@ namespace vigra {
 //@{
 // import functions into namespace vigra which VIGRA is going to overload
 
-using VIGRA_CSTD::pow;  
-using VIGRA_CSTD::floor;  
-using VIGRA_CSTD::ceil;  
-using VIGRA_CSTD::exp;  
+using VIGRA_CSTD::pow;
+using VIGRA_CSTD::floor;
+using VIGRA_CSTD::ceil;
+using VIGRA_CSTD::exp;
 
 // import abs(float), abs(double), abs(long double) from <cmath>
 //        abs(int), abs(long), abs(long long) from <cstdlib>
 //        abs(std::complex<T>) from <complex>
-using std::abs;  
+using std::abs;
 
 // define the missing variants of abs() to avoid 'ambiguous overload'
 // errors in template functions
@@ -159,6 +159,27 @@ VIGRA_DEFINE_MISSING_ABS(signed long long)
 
 #undef VIGRA_DEFINE_MISSING_ABS
 
+#ifndef _MSC_VER
+
+using std::isinf;
+using std::isnan;
+
+#else
+
+template <class REAL>
+inline bool isinf(REAL v)
+{
+    return _finite(v) == 0;
+}
+
+template <class REAL>
+inline bool isnan(REAL v)
+{
+    return _isnan(v) != 0;
+}
+
+#endif
+
 // scalar dot is needed for generic functions that should work with
 // scalars and vectors alike
 
@@ -197,7 +218,7 @@ inline long double pow(long double v, double e)
 
     /** \brief The rounding function.
 
-        Defined for all floating point types. Rounds towards the nearest integer 
+        Defined for all floating point types. Rounds towards the nearest integer
         such that <tt>abs(round(t)) == round(abs(t))</tt> for all <tt>t</tt>.
 
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
@@ -231,17 +252,17 @@ inline long double round(long double t)
 
     /** \brief Round and cast to integer.
 
-        Rounds to the nearest integer like round(), but casts the result to 
-        <tt>int</tt> (this will be faster and is usually needed anyway).
+        Rounds to the nearest integer like round(), but casts the result to
+        <tt>long long</tt> (this will be faster and is usually needed anyway).
 
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
-inline int roundi(double t)
+inline long long roundi(double t)
 {
      return t >= 0.0
-                ? int(t + 0.5)
-                : int(t - 0.5);
+                ? (long long)(t + 0.5)
+                : (long long)(t - 0.5);
 }
 
     /** \brief Round up to the nearest power of 2.
@@ -254,10 +275,10 @@ inline int roundi(double t)
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
-inline UInt32 ceilPower2(UInt32 x) 
+inline UInt32 ceilPower2(UInt32 x)
 {
     if(x == 0) return 0;
-    
+
     x = x - 1;
     x = x | (x >> 1);
     x = x | (x >> 2);
@@ -265,8 +286,8 @@ inline UInt32 ceilPower2(UInt32 x)
     x = x | (x >> 8);
     x = x | (x >>16);
     return x + 1;
-} 
-    
+}
+
     /** \brief Round down to the nearest power of 2.
 
         Efficient algorithm for finding the largest power of 2 which is not greater than \a x
@@ -276,8 +297,8 @@ inline UInt32 ceilPower2(UInt32 x)
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
-inline UInt32 floorPower2(UInt32 x) 
-{ 
+inline UInt32 floorPower2(UInt32 x)
+{
     x = x | (x >> 1);
     x = x | (x >> 2);
     x = x | (x >> 4);
@@ -296,10 +317,10 @@ struct IntLog2
 
 template <class T>
 Int32 IntLog2<T>::table[64] = {
-         -1,  0,  -1,  15,  -1,  1,  28,  -1,  16,  -1,  -1,  -1,  2,  21,  
-         29,  -1,  -1,  -1,  19,  17,  10,  -1,  12,  -1,  -1,  3,  -1,  6,  
-         -1,  22,  30,  -1,  14,  -1,  27,  -1,  -1,  -1,  20,  -1,  18,  9,  
-         11,  -1,  5,  -1,  -1,  13,  26,  -1,  -1,  8,  -1,  4,  -1,  25,  
+         -1,  0,  -1,  15,  -1,  1,  28,  -1,  16,  -1,  -1,  -1,  2,  21,
+         29,  -1,  -1,  -1,  19,  17,  10,  -1,  12,  -1,  -1,  3,  -1,  6,
+         -1,  22,  30,  -1,  14,  -1,  27,  -1,  -1,  -1,  20,  -1,  18,  9,
+         11,  -1,  5,  -1,  -1,  13,  26,  -1,  -1,  8,  -1,  4,  -1,  25,
          -1,  7,  24,  -1,  23,  -1,  31,  -1};
 
 } // namespace detail
@@ -308,11 +329,11 @@ Int32 IntLog2<T>::table[64] = {
 
         Returns the position of the left-most 1-bit in the given number \a x, or
         -1 if \a x == 0. That is,
-        
+
         \code
         assert(k >= 0 && k < 32 && log2i(1 << k) == k);
         \endcode
-        
+
         The function uses Robert Harley's algorithm to determine the number of leading zeros
         in \a x (algorithm nlz10() at http://www.hackersdelight.org/). But note that the functions
         \ref floorPower2() or \ref ceilPower2() are more efficient and should be preferred when possible.
@@ -320,15 +341,15 @@ Int32 IntLog2<T>::table[64] = {
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
-inline Int32 log2i(UInt32 x) 
-{ 
+inline Int32 log2i(UInt32 x)
+{
     // Propagate leftmost 1-bit to the right.
     x = x | (x >> 1);
     x = x | (x >> 2);
     x = x | (x >> 4);
     x = x | (x >> 8);
     x = x | (x >>16);
-    x = x*0x06EB14F9; // Multiplier is 7*255**3. 
+    x = x*0x06EB14F9; // Multiplier is 7*255**3.
     return detail::IntLog2<Int32>::table[x >> 26];
 }
 
@@ -340,7 +361,7 @@ inline Int32 log2i(UInt32 x)
         Namespace: vigra
     */
 template <class T>
-inline 
+inline
 typename NumericTraits<T>::Promote sq(T t)
 {
     return t*t;
@@ -372,7 +393,7 @@ struct power_static
 template <class V>
 struct power_static<V, 0>
 {
-    static V call(const V & x)
+    static V call(const V & /* x */)
     {
         return V(1);
     }
@@ -425,7 +446,7 @@ UInt32 IntSquareRoot<T>::sqq_table[] = {
 };
 
 template <class T>
-UInt32 IntSquareRoot<T>::exec(UInt32 x) 
+UInt32 IntSquareRoot<T>::exec(UInt32 x)
 {
     UInt32 xn;
     if (x >= 0x10000)
@@ -491,7 +512,7 @@ UInt32 IntSquareRoot<T>::exec(UInt32 x)
 using VIGRA_CSTD::sqrt;
 
     /** \brief Signed integer square root.
-    
+
         Useful for fast fixed-point computations.
 
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
@@ -525,15 +546,15 @@ inline UInt32 sqrti(UInt32 v)
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
-inline double hypot(double a, double b) 
-{ 
+inline double hypot(double a, double b)
+{
     double absa = VIGRA_CSTD::fabs(a), absb = VIGRA_CSTD::fabs(b);
-    if (absa > absb) 
-        return absa * VIGRA_CSTD::sqrt(1.0 + sq(absb/absa)); 
-    else 
+    if (absa > absb)
+        return absa * VIGRA_CSTD::sqrt(1.0 + sq(absb/absa));
+    else
         return absb == 0.0
                    ? 0.0
-                   : absb * VIGRA_CSTD::sqrt(1.0 + sq(absa/absb)); 
+                   : absb * VIGRA_CSTD::sqrt(1.0 + sq(absa/absb));
 }
 
 #else
@@ -550,8 +571,8 @@ using ::hypot;
         Namespace: vigra
     */
 template <class T>
-inline T sign(T t) 
-{ 
+inline T sign(T t)
+{
     return t > NumericTraits<T>::zero()
                ? NumericTraits<T>::one()
                : t < NumericTraits<T>::zero()
@@ -567,8 +588,8 @@ inline T sign(T t)
         Namespace: vigra
     */
 template <class T>
-inline int signi(T t) 
-{ 
+inline int signi(T t)
+{
     return t > NumericTraits<T>::zero()
                ? 1
                : t < NumericTraits<T>::zero()
@@ -584,8 +605,8 @@ inline int signi(T t)
         Namespace: vigra
     */
 template <class T1, class T2>
-inline T1 sign(T1 t1, T2 t2) 
-{ 
+inline T1 sign(T1 t1, T2 t2)
+{
     return t2 >= NumericTraits<T2>::zero()
                ? abs(t1)
                : -abs(t1);
@@ -675,7 +696,7 @@ NormTraits<T>::SquaredNormType squaredNorm(T const & t);
         Namespace: vigra
     */
 template <class T>
-inline typename NormTraits<T>::NormType 
+inline typename NormTraits<T>::NormType
 norm(T const & t)
 {
     typedef typename NormTraits<T>::SquaredNormType SNT;
@@ -683,12 +704,12 @@ norm(T const & t)
 }
 
     /** \brief Compute the eigenvalues of a 2x2 real symmetric matrix.
-      
-        This uses the analytical eigenvalue formula 
+
+        This uses the analytical eigenvalue formula
         \f[
            \lambda_{1,2} = \frac{1}{2}\left(a_{00} + a_{11} \pm \sqrt{(a_{00} - a_{11})^2 + 4 a_{01}^2}\right)
         \f]
-      
+
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
@@ -703,12 +724,12 @@ void symmetric2x2Eigenvalues(T a00, T a01, T a11, T * r0, T * r1)
 }
 
     /** \brief Compute the eigenvalues of a 3x3 real symmetric matrix.
-        
+
         This uses a numerically stable version of the analytical eigenvalue formula according to
         <p>
         David Eberly: <a href="http://www.geometrictools.com/Documentation/EigenSymmetric3x3.pdf">
-        <em>"Eigensystems for 3 � 3 Symmetric Matrices (Revisited)"</em></a>, Geometric Tools Documentation, 2006
-        
+        <em>"Eigensystems for 3 × 3 Symmetric Matrices (Revisited)"</em></a>, Geometric Tools Documentation, 2006
+
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
@@ -717,17 +738,17 @@ void symmetric3x3Eigenvalues(T a00, T a01, T a02, T a11, T a12, T a22,
                              T * r0, T * r1, T * r2)
 {
     double inv3 = 1.0 / 3.0, root3 = std::sqrt(3.0);
-    
+
     double c0 = a00*a11*a22 + 2.0*a01*a02*a12 - a00*a12*a12 - a11*a02*a02 - a22*a01*a01;
     double c1 = a00*a11 - a01*a01 + a00*a22 - a02*a02 + a11*a22 - a12*a12;
     double c2 = a00 + a11 + a22;
     double c2Div3 = c2*inv3;
     double aDiv3 = (c1 - c2*c2Div3)*inv3;
-    if (aDiv3 > 0.0) 
+    if (aDiv3 > 0.0)
         aDiv3 = 0.0;
     double mbDiv2 = 0.5*(c0 + c2Div3*(2.0*c2Div3*c2Div3 - c1));
     double q = mbDiv2*mbDiv2 + aDiv3*aDiv3*aDiv3;
-    if (q > 0.0) 
+    if (q > 0.0)
         q = 0.0;
     double magnitude = std::sqrt(-aDiv3);
     double angle = std::atan2(std::sqrt(-q),mbDiv2)*inv3;
@@ -799,14 +820,14 @@ T ellipticRF(T x, T y, T z)
 } // namespace detail
 
     /** \brief The incomplete elliptic integral of the first kind.
-    
+
         This function computes
 
         \f[
              \mbox{F}(x, k) = \int_0^x \frac{1}{\sqrt{1 - k^2 \sin(t)^2}} dt
         \f]
-  
-        according to the algorithm given in Press et al. "Numerical Recipes". 
+
+        according to the algorithm given in Press et al. "Numerical Recipes".
 
         Note: In some libraries (e.g. Mathematica), the second parameter of the elliptic integral
         functions must be k^2 rather than k. Check the documentation when results disagree!
@@ -822,19 +843,19 @@ inline double ellipticIntegralF(double x, double k)
 }
 
     /** \brief The incomplete elliptic integral of the second kind.
-      
+
         This function computes
-      
+
         \f[
             \mbox{E}(x, k) = \int_0^x \sqrt{1 - k^2 \sin(t)^2} dt
         \f]
-      
+
         according to the algorithm given in Press et al. "Numerical Recipes". The
         complete elliptic integral of the second kind is simply <tt>ellipticIntegralE(M_PI/2, k)</TT>.
-      
+
         Note: In some libraries (e.g. Mathematica), the second parameter of the elliptic integral
         functions must be k^2 rather than k. Check the documentation when results disagree!
-      
+
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
@@ -846,7 +867,7 @@ inline double ellipticIntegralE(double x, double k)
     return s*(detail::ellipticRF(c2, 1.0-k, 1.0) - k/3.0*detail::ellipticRD(c2, 1.0-k, 1.0));
 }
 
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && _MSC_VER < 1800
 
 namespace detail {
 
@@ -864,18 +885,18 @@ double erfImpl(T x)
         return ans - 1.0;
 }
 
-} // namespace detail 
+} // namespace detail
 
     /** \brief The error function.
 
         If <tt>erf()</tt> is not provided in the C standard math library (as it should according to the
-        new C99 standard ?), VIGRA implements <tt>erf()</tt> as an approximation of the error 
+        new C99 standard ?), VIGRA implements <tt>erf()</tt> as an approximation of the error
         function
-        
+
         \f[
             \mbox{erf}(x) = \int_0^x e^{-t^2} dt
         \f]
-        
+
         according to the formula given in Press et al. "Numerical Recipes".
 
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
@@ -950,7 +971,7 @@ std::pair<double, double> noncentralChi2CDF(unsigned int degreesOfFreedom, T non
         dans = VIGRA_CSTD::exp(lans);
         pans = 1.0 - dans;
     }
-    
+
     // Evaluate first term
     if(degreesOfFreedom == 0)
     {
@@ -992,9 +1013,9 @@ std::pair<double, double> noncentralChi2CDF(unsigned int degreesOfFreedom, T non
 
 } // namespace detail
 
-    /** \brief Chi square distribution. 
+    /** \brief Chi square distribution.
 
-        Computes the density of a chi square distribution with \a degreesOfFreedom 
+        Computes the density of a chi square distribution with \a degreesOfFreedom
         and tolerance \a accuracy at the given argument \a arg
         by calling <tt>noncentralChi2(degreesOfFreedom, 0.0, arg, accuracy)</tt>.
 
@@ -1006,9 +1027,9 @@ inline double chi2(unsigned int degreesOfFreedom, double arg, double accuracy =
     return detail::noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accuracy).first;
 }
 
-    /** \brief Cumulative chi square distribution. 
+    /** \brief Cumulative chi square distribution.
 
-        Computes the cumulative density of a chi square distribution with \a degreesOfFreedom 
+        Computes the cumulative density of a chi square distribution with \a degreesOfFreedom
         and tolerance \a accuracy at the given argument \a arg, i.e. the probability that
         a random number drawn from the distribution is below \a arg
         by calling <tt>noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accuracy)</tt>.
@@ -1021,50 +1042,50 @@ inline double chi2CDF(unsigned int degreesOfFreedom, double arg, double accuracy
     return detail::noncentralChi2CDF(degreesOfFreedom, 0.0, arg, accuracy).second;
 }
 
-    /** \brief Non-central chi square distribution. 
+    /** \brief Non-central chi square distribution.
 
-        Computes the density of a non-central chi square distribution with \a degreesOfFreedom, 
-        noncentrality parameter \a noncentrality and tolerance \a accuracy at the given argument 
-        \a arg. It uses Algorithm AS 231 from Appl. Statist. (1987) Vol.36, No.3 (code ported from 
+        Computes the density of a non-central chi square distribution with \a degreesOfFreedom,
+        noncentrality parameter \a noncentrality and tolerance \a accuracy at the given argument
+        \a arg. It uses Algorithm AS 231 from Appl. Statist. (1987) Vol.36, No.3 (code ported from
         http://lib.stat.cmu.edu/apstat/231). The algorithm has linear complexity in the number of
         degrees of freedom.
 
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
-inline double noncentralChi2(unsigned int degreesOfFreedom, 
+inline double noncentralChi2(unsigned int degreesOfFreedom,
               double noncentrality, double arg, double accuracy = 1e-7)
 {
     return detail::noncentralChi2CDF(degreesOfFreedom, noncentrality, arg, accuracy).first;
 }
 
-    /** \brief Cumulative non-central chi square distribution. 
+    /** \brief Cumulative non-central chi square distribution.
 
-        Computes the cumulative density of a chi square distribution with \a degreesOfFreedom, 
-        noncentrality parameter \a noncentrality and tolerance \a accuracy at the given argument 
+        Computes the cumulative density of a chi square distribution with \a degreesOfFreedom,
+        noncentrality parameter \a noncentrality and tolerance \a accuracy at the given argument
         \a arg, i.e. the probability that a random number drawn from the distribution is below \a arg
-        It uses Algorithm AS 231 from Appl. Statist. (1987) Vol.36, No.3 (code ported from 
+        It uses Algorithm AS 231 from Appl. Statist. (1987) Vol.36, No.3 (code ported from
         http://lib.stat.cmu.edu/apstat/231). The algorithm has linear complexity in the number of
         degrees of freedom (see noncentralChi2CDFApprox() for a constant-time algorithm).
 
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
         Namespace: vigra
     */
-inline double noncentralChi2CDF(unsigned int degreesOfFreedom, 
+inline double noncentralChi2CDF(unsigned int degreesOfFreedom,
               double noncentrality, double arg, double accuracy = 1e-7)
 {
     return detail::noncentralChi2CDF(degreesOfFreedom, noncentrality, arg, accuracy).second;
 }
 
-    /** \brief Cumulative non-central chi square distribution (approximate). 
+    /** \brief Cumulative non-central chi square distribution (approximate).
 
-        Computes approximate values of the cumulative density of a chi square distribution with \a degreesOfFreedom, 
-        and noncentrality parameter \a noncentrality at the given argument 
+        Computes approximate values of the cumulative density of a chi square distribution with \a degreesOfFreedom,
+        and noncentrality parameter \a noncentrality at the given argument
         \a arg, i.e. the probability that a random number drawn from the distribution is below \a arg
-        It uses the approximate transform into a normal distribution due to Wilson and Hilferty 
-        (see Abramovitz, Stegun: "Handbook of Mathematical Functions", formula 26.3.32). 
+        It uses the approximate transform into a normal distribution due to Wilson and Hilferty
+        (see Abramovitz, Stegun: "Handbook of Mathematical Functions", formula 26.3.32).
         The algorithm's running time is independent of the inputs, i.e. is should be used
-        when noncentralChi2CDF() is too slow, and approximate values are sufficient. The accuracy is only 
+        when noncentralChi2CDF() is too slow, and approximate values are sufficient. The accuracy is only
         about 0.1 for few degrees of freedom, but reaches about 0.001 above dof = 5.
 
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
@@ -1090,11 +1111,11 @@ T facLM(T l, T m)
 
 } // namespace detail
 
-    /** \brief Associated Legendre polynomial. 
+    /** \brief Associated Legendre polynomial.
 
-        Computes the value of the associated Legendre polynomial of order <tt>l, m</tt> 
-        for argument <tt>x</tt>. <tt>x</tt> must be in the range <tt>[-1.0, 1.0]</tt>, 
-        otherwise an exception is thrown. The standard Legendre polynomials are the 
+        Computes the value of the associated Legendre polynomial of order <tt>l, m</tt>
+        for argument <tt>x</tt>. <tt>x</tt> must be in the range <tt>[-1.0, 1.0]</tt>,
+        otherwise an exception is thrown. The standard Legendre polynomials are the
         special case <tt>m == 0</tt>.
 
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
@@ -1123,11 +1144,11 @@ REAL legendre(unsigned int l, int m, REAL x)
             f += 2.0;
         }
     }
-    if((int)l == m) 
+    if((int)l == m)
         return result;
 
     REAL result_1 = x * (2.0 * m + 1.0) * result;
-    if((int)l == m+1) 
+    if((int)l == m+1)
         return result_1;
     REAL other = 0.0;
     for(unsigned int i = m+2; i <= l; ++i)
@@ -1139,7 +1160,7 @@ REAL legendre(unsigned int l, int m, REAL x)
     return other;
 }
 
-    /** \brief \brief Legendre polynomial. 
+    /** \brief \brief Legendre polynomial.
 
         Computes the value of the Legendre polynomial of order <tt>l</tt> for argument <tt>x</tt>.
         <tt>x</tt> must be in the range <tt>[-1.0, 1.0]</tt>, otherwise an exception is thrown.
@@ -1153,7 +1174,7 @@ REAL legendre(unsigned int l, REAL x)
     return legendre(l, 0, x);
 }
 
-    /** \brief sin(pi*x). 
+    /** \brief sin(pi*x).
 
         Essentially calls <tt>std::sin(M_PI*x)</tt> but uses a more accurate implementation
         to make sure that <tt>sin_pi(1.0) == 0.0</tt> (which does not hold for
@@ -1187,12 +1208,12 @@ REAL sin_pi(REAL x)
         rem = NumericTraits<REAL>::one();
     else
         rem = std::sin(M_PI * rem);
-    return invert 
-              ? -rem 
+    return invert
+              ? -rem
               : rem;
 }
 
-    /** \brief cos(pi*x). 
+    /** \brief cos(pi*x).
 
         Essentially calls <tt>std::cos(M_PI*x)</tt> but uses a more accurate implementation
         to make sure that <tt>cos_pi(1.0) == -1.0</tt> and <tt>cos_pi(0.5) == 0.0</tt>.
@@ -1213,7 +1234,7 @@ struct GammaImpl
 {
     static REAL gamma(REAL x);
     static REAL loggamma(REAL x);
-    
+
     static double g[];
     static double a[];
     static double t[];
@@ -1266,7 +1287,7 @@ double GammaImpl<REAL>::a[] = {
     2.20862790713908385557e-04,
     1.08011567247583939954e-04,
     2.52144565451257326939e-05,
-    4.48640949618915160150e-05 
+    4.48640949618915160150e-05
 };
 
 template <class REAL>
@@ -1350,12 +1371,12 @@ REAL GammaImpl<REAL>::gamma(REAL x)
     vigra_precondition(x <= 171.0,
         "gamma(): argument cannot exceed 171.0.");
 
-    if (x == ix) 
+    if (x == ix)
     {
-        if (ix > 0) 
+        if (ix > 0)
         {
             ga = 1.0;               // use factorial
-            for (i=2; i<ix; ++i) 
+            for (i=2; i<ix; ++i)
             {
                ga *= i;
             }
@@ -1366,14 +1387,14 @@ REAL GammaImpl<REAL>::gamma(REAL x)
                  "gamma(): gamma function is undefined for 0 and negative integers.");
         }
      }
-     else 
+     else
      {
-        if (abs(x) > 1.0) 
+        if (abs(x) > 1.0)
         {
             z = abs(x);
             m = (int)z;
             r = 1.0;
-            for (k=1; k<=m; ++k) 
+            for (k=1; k<=m; ++k)
             {
                 r *= (z-k);
             }
@@ -1384,15 +1405,15 @@ REAL GammaImpl<REAL>::gamma(REAL x)
             z = x;
         }
         gr = g[24];
-        for (k=23; k>=0; --k) 
+        for (k=23; k>=0; --k)
         {
             gr = gr*z+g[k];
         }
         ga = 1.0/(gr*z);
-        if (abs(x) > 1.0) 
+        if (abs(x) > 1.0)
         {
             ga *= r;
-            if (x < 0.0) 
+            if (x < 0.0)
             {
                 ga = -M_PI/(x*ga*sin_pi(x));
             }
@@ -1403,13 +1424,13 @@ REAL GammaImpl<REAL>::gamma(REAL x)
 
 /*
  * the following code is derived from lgamma_r() by Sun
- * 
+ *
  * ====================================================
  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  *
  * Developed at SunPro, a Sun Microsystems, Inc. business.
  * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice 
+ * software is freely granted, provided that this notice
  * is preserved.
  * ====================================================
  *
@@ -1419,12 +1440,12 @@ REAL GammaImpl<REAL>::loggamma(REAL x)
 {
     vigra_precondition(x > 0.0,
         "loggamma(): argument must be positive.");
-    
+
     vigra_precondition(x <= 1.0e307,
         "loggamma(): argument must not exceed 1e307.");
 
     double res;
-    
+
     if (x < 4.2351647362715017e-22)
     {
         res = -std::log(x);
@@ -1528,7 +1549,7 @@ REAL GammaImpl<REAL>::loggamma(REAL x)
     {
         res =  x*(std::log(x) - 1.0);
     }
-    
+
     return res;
 }
 
@@ -1539,7 +1560,7 @@ REAL GammaImpl<REAL>::loggamma(REAL x)
 
         This function implements the algorithm from<br>
         Zhang and Jin: "Computation of Special Functions", John Wiley and Sons, 1996.
-        
+
         The argument must be <= 171.0 and cannot be zero or a negative integer. An
         exception is thrown when these conditions are violated.
 
@@ -1556,7 +1577,7 @@ inline double gamma(double x)
         This function is based on a free implementation by Sun Microsystems, Inc., see
         <a href="http://www.sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/src/newlib/libm/mathfp/er_lgamma.c?rev=1.6&content-type=text/plain&cvsroot=src">sourceware.org</a> archive. It can be removed once all compilers support the new C99
         math functions.
-        
+
         The argument must be positive and < 1e30. An exception is thrown when these conditions are violated.
 
         <b>\#include</b> \<vigra/mathutil.hxx\><br>
@@ -1576,16 +1597,16 @@ inline
 FPT safeFloatDivision( FPT f1, FPT f2 )
 {
     return  f2 < NumericTraits<FPT>::one() && f1 > f2 * NumericTraits<FPT>::max()
-                ? NumericTraits<FPT>::max() 
-                : (f2 > NumericTraits<FPT>::one() && f1 < f2 * NumericTraits<FPT>::smallestPositive()) || 
+                ? NumericTraits<FPT>::max()
+                : (f2 > NumericTraits<FPT>::one() && f1 < f2 * NumericTraits<FPT>::smallestPositive()) ||
                    f1 == NumericTraits<FPT>::zero()
-                     ? NumericTraits<FPT>::zero() 
+                     ? NumericTraits<FPT>::zero()
                      : f1/f2;
 }
 
 } // namespace detail
-    
-    /** \brief Tolerance based floating-point comparison.
+
+    /** \brief Tolerance based floating-point equality.
 
         Check whether two floating point numbers are equal within the given tolerance.
         This is useful because floating point numbers that should be equal in theory are
@@ -1596,7 +1617,7 @@ FPT safeFloatDivision( FPT f1, FPT f2 )
         Namespace: vigra
     */
 template <class T1, class T2>
-bool 
+bool
 closeAtTolerance(T1 l, T2 r, typename PromoteTraits<T1, T2>::Promote epsilon)
 {
     typedef typename PromoteTraits<T1, T2>::Promote T;
@@ -1618,8 +1639,112 @@ inline bool closeAtTolerance(T1 l, T2 r)
     return closeAtTolerance(l, r, T(2.0) * NumericTraits<T>::epsilon());
 }
 
+    /** \brief Tolerance based floating-point less-or-equal.
+
+        Check whether two floating point numbers are less or equal within the given tolerance.
+        That is, \a l can actually be greater than \a r within the given \a epsilon.
+        This is useful because floating point numbers that should be equal in theory are
+        rarely exactly equal in practice. If the tolerance \a epsilon is not given,
+        twice the machine epsilon is used.
+
+        <b>\#include</b> \<vigra/mathutil.hxx\><br>
+        Namespace: vigra
+    */
+template <class T1, class T2>
+inline bool
+lessEqualAtTolerance(T1 l, T2 r, typename PromoteTraits<T1, T2>::Promote epsilon)
+{
+    return l < r || closeAtTolerance(l, r, epsilon);
+}
+
+template <class T1, class T2>
+inline bool lessEqualAtTolerance(T1 l, T2 r)
+{
+    typedef typename PromoteTraits<T1, T2>::Promote T;
+    return lessEqualAtTolerance(l, r, T(2.0) * NumericTraits<T>::epsilon());
+}
+
+    /** \brief Tolerance based floating-point greater-or-equal.
+
+        Check whether two floating point numbers are greater or equal within the given tolerance.
+        That is, \a l can actually be less than \a r within the given \a epsilon.
+        This is useful because floating point numbers that should be equal in theory are
+        rarely exactly equal in practice. If the tolerance \a epsilon is not given,
+        twice the machine epsilon is used.
+
+        <b>\#include</b> \<vigra/mathutil.hxx\><br>
+        Namespace: vigra
+    */
+template <class T1, class T2>
+inline bool
+greaterEqualAtTolerance(T1 l, T2 r, typename PromoteTraits<T1, T2>::Promote epsilon)
+{
+    return r < l || closeAtTolerance(l, r, epsilon);
+}
+
+template <class T1, class T2>
+inline bool greaterEqualAtTolerance(T1 l, T2 r)
+{
+    typedef typename PromoteTraits<T1, T2>::Promote T;
+    return greaterEqualAtTolerance(l, r, T(2.0) * NumericTraits<T>::epsilon());
+}
+
 //@}
 
+#define VIGRA_MATH_FUNC_HELPER(TYPE) \
+    inline TYPE clipLower(const TYPE t){ \
+        return t < static_cast<TYPE>(0.0) ? static_cast<TYPE>(0.0) : t; \
+    } \
+    inline TYPE clipLower(const TYPE t,const TYPE valLow){ \
+        return t < static_cast<TYPE>(valLow) ? static_cast<TYPE>(valLow) : t; \
+    } \
+    inline TYPE clipUpper(const TYPE t,const TYPE valHigh){ \
+        return t > static_cast<TYPE>(valHigh) ? static_cast<TYPE>(valHigh) : t; \
+    } \
+    inline TYPE clip(const TYPE t,const TYPE valLow, const TYPE valHigh){ \
+        if(t<valLow) \
+            return valLow; \
+        else if(t>valHigh) \
+            return valHigh; \
+        else  \
+            return t; \
+    } \
+    inline TYPE sum(const TYPE t){ \
+        return t; \
+    }\
+    inline NumericTraits<TYPE>::RealPromote mean(const TYPE t){ \
+        return t; \
+    }\
+    inline TYPE isZero(const TYPE t){ \
+        return t==static_cast<TYPE>(0); \
+    } \
+    inline NumericTraits<TYPE>::RealPromote sizeDividedSquaredNorm(const TYPE t){ \
+        return  squaredNorm(t); \
+    } \
+    inline NumericTraits<TYPE>::RealPromote sizeDividedNorm(const TYPE t){ \
+        return  norm(t); \
+    }
+
+
+VIGRA_MATH_FUNC_HELPER(unsigned char)
+VIGRA_MATH_FUNC_HELPER(unsigned short)
+VIGRA_MATH_FUNC_HELPER(unsigned int)
+VIGRA_MATH_FUNC_HELPER(unsigned long)
+VIGRA_MATH_FUNC_HELPER(unsigned long long)
+VIGRA_MATH_FUNC_HELPER(signed char)
+VIGRA_MATH_FUNC_HELPER(signed short)
+VIGRA_MATH_FUNC_HELPER(signed int)
+VIGRA_MATH_FUNC_HELPER(signed long)
+VIGRA_MATH_FUNC_HELPER(signed long long)
+VIGRA_MATH_FUNC_HELPER(float)
+VIGRA_MATH_FUNC_HELPER(double)
+VIGRA_MATH_FUNC_HELPER(long double)
+
+
+
+#undef VIGRA_MATH_FUNC_HELPER
+
+
 } // namespace vigra
 
 #endif /* VIGRA_MATHUTIL_HXX */
diff --git a/include/vigra/matrix.hxx b/include/vigra/matrix.hxx
index 9a34c78..b2b81d9 100644
--- a/include/vigra/matrix.hxx
+++ b/include/vigra/matrix.hxx
@@ -152,9 +152,9 @@ class Matrix
             <tt>difference_type(rows, columns)</tt> which
             is the opposite of the usual VIGRA convention.
          */
-    explicit Matrix(const difference_type &shape,
+    explicit Matrix(const difference_type &aShape,
                     ALLOC const & alloc = allocator_type())
-    : BaseType(shape, alloc)
+    : BaseType(aShape, alloc)
     {}
 
         /** construct with given shape and init all
@@ -172,9 +172,9 @@ class Matrix
             <tt>difference_type(rows, columns)</tt> which
             is the opposite of the usual VIGRA convention.
          */
-    Matrix(const difference_type &shape, const_reference init,
+    Matrix(const difference_type &aShape, const_reference init,
            allocator_type const & alloc = allocator_type())
-    : BaseType(shape, init, alloc)
+    : BaseType(aShape, init, alloc)
     {}
 
         /** construct with given shape and init all
@@ -334,16 +334,16 @@ class Matrix
 
         /** reshape to the given shape and initialize with zero.
          */
-    void reshape(difference_type const & shape)
+    void reshape(difference_type const & newShape)
     {
-        BaseType::reshape(shape);
+        BaseType::reshape(newShape);
     }
 
         /** reshape to the given shape and initialize with \a init.
          */
-    void reshape(difference_type const & shape, const_reference init)
+    void reshape(difference_type const & newShape, const_reference init)
     {
-        BaseType::reshape(shape, init);
+        BaseType::reshape(newShape, init);
     }
 
         /** Create a matrix view that represents the row vector of row \a d.
@@ -1067,9 +1067,9 @@ void repeatMatrix(MultiArrayView<2, T, C1> const & v, MultiArrayView<2, T, C2> &
     vigra_precondition(m*verticalCount == rowCount(r) && n*horizontalCount == columnCount(r),
         "repeatMatrix(): Shape mismatch.");
         
-    for(MultiArrayIndex l=0; l<(MultiArrayIndex)horizontalCount; ++l)
+    for(MultiArrayIndex l=0; l<static_cast<MultiArrayIndex>(horizontalCount); ++l)
     {
-        for(MultiArrayIndex k=0; k<(MultiArrayIndex)verticalCount; ++k)
+        for(MultiArrayIndex k=0; k<static_cast<MultiArrayIndex>(verticalCount); ++k)
         {
             r.subarray(Shape(k*m, l*n), Shape((k+1)*m, (l+1)*n)) = v;
         }
@@ -2124,7 +2124,7 @@ linalg::TemporaryMatrix<int> pow(MultiArrayView<2, int, C> const & v, int expone
 
     for(MultiArrayIndex i = 0; i < n; ++i)
         for(MultiArrayIndex j = 0; j < m; ++j)
-            t(j, i) = (int)vigra::pow((double)v(j, i), exponent);
+            t(j, i) = static_cast<int>(vigra::pow(static_cast<double>(v(j, i)), exponent));
     return t;
 }
 
@@ -2136,7 +2136,7 @@ linalg::TemporaryMatrix<int> pow(linalg::TemporaryMatrix<int> const & v, int exp
 
     for(MultiArrayIndex i = 0; i < n; ++i)
         for(MultiArrayIndex j = 0; j < m; ++j)
-            t(j, i) = (int)vigra::pow((double)t(j, i), exponent);
+            t(j, i) = static_cast<int>(vigra::pow(static_cast<double>(t(j, i)), exponent));
     return t;
 }
 
@@ -2389,7 +2389,7 @@ columnStatistics2PassImpl(MultiArrayView<2, T1, C1> const & A,
     {
         mean += rowVector(A, k);
     }
-    mean /= (double)m;
+    mean /= static_cast<double>(m);
     
     sumOfSquaredDifferences.init(NumericTraits<T3>::zero());
     for(MultiArrayIndex k=0; k<m; ++k)
@@ -2618,8 +2618,8 @@ void updateCovarianceMatrix(MultiArrayView<2, T1, C1> const & features,
     // West's algorithm for incremental covariance matrix computation
     Matrix<T2> t = features - mean;
     ++count;
-    double f  = 1.0 / count,
-           f1 = 1.0 - f;
+    T2 f  = T2(1.0) / count,
+       f1 = T2(1.0) - f;
     mean += f*t;
     
     if(rowCount(features) == 1) // update column covariance from current row
@@ -2710,7 +2710,7 @@ void covarianceMatrixOfRows(MultiArrayView<2, T1, C1> const & features,
     covariance.init(NumericTraits<T2>::zero());
     for(MultiArrayIndex k=0; k<n; ++k)
         detail::updateCovarianceMatrix(columnVector(features, k), count, means, covariance);
-    covariance /= T2(m - 1);
+    covariance /= T2(n - 1);
 }
 
     /** \brief Compute the covariance matrix between the rows of a matrix \a features.
diff --git a/include/vigra/medianfilter.hxx b/include/vigra/medianfilter.hxx
new file mode 100644
index 0000000..5ff117a
--- /dev/null
+++ b/include/vigra/medianfilter.hxx
@@ -0,0 +1,193 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2007-2014 by Benjamin Seppke                 */
+/*       Cognitive Systems Group, University of Hamburg, Germany        */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_MEDIANFILTER_HXX
+#define VIGRA_MEDIANFILTER_HXX
+
+#include <vector>
+#include <algorithm>
+
+#include "applywindowfunction.hxx"
+
+namespace vigra
+{
+
+/********************************************************/
+/*                                                      */
+/*              Generic median filter                   */
+/*                                                      */
+/********************************************************/
+/**  
+    This function calculates the median of a window of given size for the complete image. 
+    It also allows a correct border handling, since it uses the \ref applyWindowFunction 
+    environment for computation! 
+*/
+//@{
+
+/** \brief This function calculates the median of a window of given size for the complete image.
+
+    All \ref BorderTreatmentMode "border treatment modes"  (except BORDER_TREATMENT_CLIP)  are supported.
+
+    The input pixel type <tt>T1</tt> must be a \ref LinearSpace "linear space" over 
+    the window functions' value_type <tt>T</tt>. Especially, the values must be sortable by
+    std::sort, to derive the mean values aka the median.
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2>
+        void
+        medianFilter(MultiArrayView<2, T1, S1> const & src,
+                     MultiArrayView<2, T2, S2> dest,
+                     Diff2D window_shape, 
+                     BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+
+    }
+    \endcode
+
+    \deprecatedAPI{medianFilter}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void medianFilter(SrcIterator supperleft,
+                          SrcIterator slowerright, SrcAccessor sa,
+                          DestIterator dupperleft, DestAccessor da,
+                          Diff2D window_shape, 
+                          BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        medianFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                     pair<DestIterator, DestAccessor> dest,
+                     Diff2D window_shape, 
+                     BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/medianfilter.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> src(w,h), dest(w,h);
+    ...
+    
+    // apply a median filter with a window size of 5x5
+    medianFilter(src, dest, Diff2D(5,5));
+    \endcode
+    
+    <b> Preconditions:</b>
+
+    The image must be larger than the window size of the filter.
+*/
+
+doxygen_overloaded_function(template <...> void medianFilter)
+
+template<class VALUETYPE>
+class MedianFunctor
+{
+public:
+    MedianFunctor(Diff2D window_shape)
+    : m_window_shape(window_shape),
+      m_buffer(window_shape.x*window_shape.y)
+    {
+    }
+
+    template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+    void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)
+    {
+        SrcIterator s_ul = s - m_window_shape/2,
+                    s_lr = s_ul + m_window_shape;
+        
+        std::fill(m_buffer.begin(), m_buffer.end(), VALUETYPE());
+        
+        SrcIterator ys = s_ul;
+        SrcIterator xs = ys;
+        
+        typename std::vector<VALUETYPE>::iterator iter = m_buffer.begin(),
+                                                  median_iter = m_buffer.begin()+m_buffer.size()/2;
+        
+        for( ; ys.y != s_lr.y; ys.y++)
+        {   
+            for(xs = ys; xs.x != s_lr.x; xs.x++, iter++)
+            {
+                *iter = s_acc(xs);
+            }       
+        }
+        
+        std::nth_element(m_buffer.begin(), median_iter, m_buffer.end());
+        d_acc.set(*median_iter,d);
+    }
+    
+    Diff2D windowShape() const
+    {
+        return m_window_shape;
+    }
+    
+private:
+    Diff2D m_window_shape;
+    std::vector<VALUETYPE> m_buffer;    
+};
+
+
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+inline void medianFilter(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+                         DestIterator d_ul, DestAccessor d_acc, 
+                         Diff2D window_shape,
+                         BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    MedianFunctor<typename SrcIterator::value_type> func(window_shape);
+    applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
+}
+
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+inline void medianFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+                         pair<DestIterator, DestAccessor> d, 
+                         Diff2D window_shape,
+                         BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    medianFilter(s.first, s.second, s.third,
+                 d.first, d.second, 
+                 window_shape,
+                 border);
+}
+
+template <class T1, class S1, 
+          class T2, class S2>
+inline void medianFilter(MultiArrayView<2, T1, S1> const & src,
+                         MultiArrayView<2, T2, S2> dest, 
+                         Diff2D window_shape,
+                         BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    vigra_precondition(src.shape() == dest.shape(),
+                        "vigra::medianFilter(): shape mismatch between input and output.");
+    medianFilter(srcImageRange(src),
+                 destImage(dest), 
+                 window_shape, 
+                 border);
+}
+
+//@}
+
+} //end of namespace vigra
+
+#endif //VIGRA_MEDIANFILTER_HXX
diff --git a/include/vigra/memory.hxx b/include/vigra/memory.hxx
index 3d3b9fa..2ead777 100644
--- a/include/vigra/memory.hxx
+++ b/include/vigra/memory.hxx
@@ -36,6 +36,16 @@
 #ifndef VIGRA_MEMORY_HXX
 #define VIGRA_MEMORY_HXX
 
+
+#include "config.hxx"
+
+#ifdef VIGRA_SHARED_PTR_IN_TR1
+#  include <tr1/memory>
+#else
+#  include <memory>
+#endif 
+
+#include <cstring>
 #include "metaprogramming.hxx"
 
 namespace vigra { 
@@ -62,31 +72,139 @@ Dest uninitializedCopy(Src s, Src end, Dest d)
 }
 
 template <class T>
-inline void destroy_n(T * /* p */, std::ptrdiff_t /* n */, VigraTrueType /* isPOD */)
+struct PlacementNewAllocator
 {
-}
+    T * allocate(std::size_t n)
+    {
+        return (T*)::operator new(n*sizeof(T));
+    }
+
+    void deallocate(T * p, std::size_t)
+    {
+        return ::operator delete(p);
+    }
+
+    void construct(T * p, T const & initial)
+    {
+        new(p) T(initial);
+    }
+    
+    void destroy(T * p)
+    {
+        p->~T();
+    }
+};
+
+template <class T>
+inline void 
+destroy_n(T * /* p */, std::size_t /* n */, VigraTrueType /* isPOD */)
+{}
 
 template <class T>
-inline void destroy_n(T * p, std::ptrdiff_t n, VigraFalseType /* isPOD */)
+inline void 
+destroy_n(T * p, std::size_t n, VigraFalseType /* isPOD */)
 {
-    T * end = p + n;
-    for(; p != end; ++p)
+    for(std::size_t i=0; i < n; ++i, ++p)
         p->~T();
 }
 
 template <class T>
-inline void destroy_n(T * p, std::ptrdiff_t n)
+inline void
+destroy_n(T * p, std::size_t n)
 {
     destroy_n(p, n, typename TypeTraits<T>::isPOD());
 }
 
+template <class T, class Alloc>
+inline T * 
+alloc_initialize_n(std::size_t n, T const & initial, Alloc & alloc)
+{
+    T * p = alloc.allocate(n);
+    bool useMemset = TypeTraits<T>::isPOD::value &&
+                     (initial == T());
+    if(useMemset)
+    {
+        std::memset(p, 0, n*sizeof(T));
+    }
+    else
+    {
+        std::size_t i=0;
+        try 
+        {
+            for (; i < n; ++i)
+                alloc.construct(p+i, initial);
+        }
+        catch (...) 
+        {
+            for (std::size_t j=0; j < i; ++j)
+                alloc.destroy(p+j);
+            alloc.deallocate(p, n);
+            throw;
+        }
+    }
+    return p;
+}
+
+template <class T>
+inline T * 
+alloc_initialize_n(std::size_t n, T const & initial)
+{
+    PlacementNewAllocator<T> alloc;
+    return alloc_initialize_n<T>(n, initial, alloc);
+}
+
+template <class T>
+inline T * 
+alloc_initialize_n(std::size_t n)
+{
+    PlacementNewAllocator<T> alloc;
+    return alloc_initialize_n<T>(n, T(), alloc);
+}
+
+template <class T, class Alloc>
+inline void 
+destroy_dealloc_impl(T * p, std::size_t n, Alloc & alloc, VigraTrueType /* isPOD */)
+{
+    alloc.deallocate(p, n);
+}
+
+template <class T, class Alloc>
+inline void 
+destroy_dealloc_impl(T * p, std::size_t n, Alloc & alloc, VigraFalseType /* isPOD */)
+{
+    for (std::size_t i=0; i < n; ++i)
+        alloc.destroy(p + i);
+    alloc.deallocate(p, n);
+}
+
+template <class T, class Alloc>
+inline T * 
+destroy_dealloc_n(T * p, std::size_t n, Alloc & alloc)
+{
+    if(p != 0)
+        destroy_dealloc_impl(p, n, alloc, typename TypeTraits<T>::isPOD());
+    return 0;
+}
+
+template <class T>
+inline T * 
+destroy_dealloc_n(T * p, std::size_t n)
+{
+    if(p != 0)
+    {
+        PlacementNewAllocator<T> alloc;
+        destroy_dealloc_impl(p, n, alloc, typename TypeTraits<T>::isPOD());
+    }
+    return 0;
+}
+
 /********************************************************************/
 
 // g++ 2.95 has std::destroy() in the STL
 #if !defined(__GNUC__) ||  __GNUC__ >= 3
 
 template <class T>
-inline void destroy(T * p, VigraTrueType /* isPOD */)
+inline void destroy(T * /* p */, VigraTrueType /* isPOD */)
 {
 }
 
diff --git a/include/vigra/merge_graph_adaptor.hxx b/include/vigra/merge_graph_adaptor.hxx
new file mode 100644
index 0000000..69c9ebc
--- /dev/null
+++ b/include/vigra/merge_graph_adaptor.hxx
@@ -0,0 +1,1454 @@
+    
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2014 by Thorsten Beier and Ullrich Koethe              */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+
+#ifndef VIGRA_NEW_MERGE_GRAPH_HXX
+#define VIGRA_NEW_MERGE_GRAPH_HXX
+
+
+/* delegates / callbacks */
+#include "delegate/delegate.hxx"
+
+/* std library */
+#include <vector>
+#include <algorithm>
+#include <cmath>
+#include <stdexcept>
+#include <map>
+
+/* vigra */
+#include "multi_array.hxx"
+#include "tinyvector.hxx"
+#include "multi_array.hxx"
+#include "graphs.hxx"
+#include "graph_maps.hxx"
+#include "graph_item_impl.hxx"
+#include "random_access_set.hxx"
+#include "iteratorfacade.hxx"
+
+
+namespace vigra {
+
+namespace merge_graph_detail {
+
+// ufd  data structure structure for merge graph
+// only useful for merge graphs internal usage
+template<class T>
+class IterablePartition;
+
+// representative element iterator
+// for IterablePartition
+// only useful for merge graphs internal usage
+template<class T>
+struct  ConstRepIter
+:  public ForwardIteratorFacade<
+      ConstRepIter<T>,T,true
+   >
+
+{
+   typedef IterablePartition<T> IterablePartitionType;
+   ConstRepIter(const IterablePartitionType & p,const T cr)
+   :  partition_(&p),
+      currentRep_(cr){
+   }
+
+
+   ConstRepIter()
+   :  partition_(NULL),
+      currentRep_()
+   {
+   }
+
+private:
+  friend class vigra::IteratorFacadeCoreAccess;
+
+
+   bool isBegin()const{
+      return partition_!=NULL  && currentRep_==partition_->firstRep();
+   }
+   bool isEnd()const{
+      return  partition_==NULL || currentRep_>partition_->lastRep();
+   }
+
+   bool equal(const ConstRepIter & other)const{
+      return   (this->isEnd() && other.isEnd() )  || ((this->isEnd()==other.isEnd() ) && this->currentRep_==other.currentRep_);
+   }
+
+   void increment(){
+      if(partition_->jumpVec_[currentRep_].second==0){
+         currentRep_+=1;
+      }
+      else{
+         currentRep_+=partition_->jumpVec_[currentRep_].second;
+      }
+   }
+
+   void decrement(){
+      if(partition_->jumpVec_[currentRep_].first==0){
+         //VIGRA_ASSERT_OP(currentRep_,==,partition_->firstRep());
+         //currentRep_+=1;
+      }
+      else{
+         currentRep_-=partition_->jumpVec_[currentRep_].first;
+      }
+   }
+
+   const T & dereference()const{
+      return currentRep_;
+   }
+
+
+
+   const IterablePartitionType * partition_;
+   T currentRep_;
+   
+};
+
+
+
+// ufd  data structure structure for merge graph
+// only useful for merge graphs internal usage
+/// Disjoint set data structure with path compression.
+/// \ingroup datastructures
+template<class T>
+class IterablePartition {
+public:
+   friend struct ConstRepIter<T>;
+   typedef T value_type;
+   typedef std::size_t SizeTType;
+   IterablePartition();
+   IterablePartition(const value_type&);
+
+   // query
+   value_type find(const value_type&) const; // without path compression
+   value_type find(value_type); // with path compression
+   value_type numberOfElements() const;
+   value_type numberOfSets() const;
+   template<class Iterator> void elementLabeling(Iterator) const;
+   template<class Iterator> void representatives(Iterator) const;
+   void representativeLabeling(std::map<value_type, value_type>&) const;
+
+   // manipulation
+   void reset(const value_type&);
+   void merge(value_type, value_type);
+
+   value_type firstRep()const{
+      return firstRep_;
+   }
+   value_type lastRep()const{
+      return lastRep_;
+   }
+   typedef ConstRepIter<T> const_iterator;
+
+   const_iterator begin()const{
+      if(numberOfSets_!=0)
+         return ConstRepIter<T>(*this,firstRep_);
+      else
+         return ConstRepIter<T>(*this,lastRep_+1);
+   }
+   const_iterator end()const{
+      return ConstRepIter<T>(*this,lastRep_+1);
+   }
+
+
+   const_iterator iteratorAt(const value_type & rep)const{
+      if(numberOfSets_!=0)
+         return ConstRepIter<T>(*this,rep);
+      else
+         return ConstRepIter<T>(*this,lastRep_+1);
+   }
+
+   bool isErased(const value_type & value)const{
+      return jumpVec_[value].first == -1 && jumpVec_[value].second == -1;
+   }
+
+   void eraseElement(const value_type & value,const bool reduceSize=true){
+      const T notRep=value;
+      const T jumpMinus = jumpVec_[notRep].first;
+      const T jumpPlus  = jumpVec_[notRep].second;
+
+      if(jumpMinus==0){
+         const T nextRep = notRep+jumpPlus;
+         firstRep_=nextRep;
+         jumpVec_[nextRep].first=0;
+      }
+      else if(jumpPlus==0){
+         //VIGRA_ASSERT_OP(lastRep_,==,notRep);
+         const T prevRep = notRep-jumpMinus;
+         lastRep_=prevRep;
+         jumpVec_[prevRep].second=0;
+
+      }
+      else{
+         const T nextRep = notRep+jumpPlus;
+         const T prevRep = notRep-jumpMinus;
+         jumpVec_[nextRep].first+=jumpVec_[notRep].first;
+         jumpVec_[prevRep].second+=jumpVec_[notRep].second;
+      }   
+      if(reduceSize){
+         --numberOfSets_;
+      }
+      jumpVec_[notRep].first  =-1;
+      jumpVec_[notRep].second =-1;
+   }
+
+private:
+   std::vector<value_type> parents_;
+   std::vector<value_type> ranks_;
+   std::vector< std::pair< vigra::Int64, vigra::Int64> > jumpVec_;
+   value_type firstRep_;
+   value_type lastRep_;
+   value_type numberOfElements_;
+   value_type numberOfSets_;
+};
+
+
+} // end namespa merge graph detail 
+
+
+
+// helper classes to generalize
+// some functionality for 
+// nodes,edges and arcs 
+template<class GRAPH,class ITEM>
+struct MergeGraphItemHelper;
+
+template<class MG>
+struct MergeGraphItemHelper<MG,typename MG::Edge>{
+    typedef typename MG::Graph Graph;
+    typedef typename MG::index_type index_type ;
+    typedef typename MG::Edge Item;
+    typedef typename Graph::Edge GraphItem;
+    typedef typename MG::EdgeIt ItemIt;
+
+
+    static index_type maxItemId(const MG & g){
+        return g.maxEdgeId();
+    }
+    static index_type itemNum(const MG & g){
+        return g.edgeNum();
+    }
+
+    static GraphItem itemToGraphItem(const MG & g,const Item & item){
+        const index_type id = g.id(item);
+        return g.graph().edgeFromId(id);
+    }
+};
+
+template<class MG>
+struct MergeGraphItemHelper<MG,typename MG::Node>{
+    typedef typename MG::Graph Graph;
+    typedef typename MG::index_type index_type ;
+    typedef typename MG::Node Item;
+    typedef typename Graph::Node GraphItem;
+    typedef typename MG::NodeIt ItemIt;
+
+
+    static index_type maxItemId(const MG & g){
+        return g.maxNodeId();
+    }
+    static index_type itemNum(const MG & g){
+        return g.nodeNum();
+    }
+    static GraphItem itemToGraphItem(const MG & g,const Item & item){
+        const index_type id = g.id(item);
+        return g.graph().nodeFromId(id);
+    }
+};
+
+// merge graphs LEMON compatible iterator
+template<class MERGE_GRAPH>
+class MergeGraphNodeIt
+:   public ForwardIteratorFacade<MergeGraphNodeIt<MERGE_GRAPH>,typename MERGE_GRAPH::Node,true>{
+public:
+    typedef MERGE_GRAPH Graph;
+    typedef typename Graph::Node Node;
+    // Invalid constructor & conversion. 
+    MergeGraphNodeIt(const lemon::Invalid & invalid = lemon::INVALID)
+    :   graph_(NULL),
+        nodeIdIt_(),
+        node_(){
+
+    }
+    MergeGraphNodeIt(const Graph & g)
+    :   graph_(&g),
+        nodeIdIt_(g.nodeUfd_.begin()),
+        node_(){
+    }
+    MergeGraphNodeIt(const Graph & g,const Node & node)
+    :   graph_(&g),
+        nodeIdIt_(g.nodeUfd_.iteratorAt(g.id(node))),
+        node_(){
+
+    }
+    bool isEnd()const{ 
+        return graph_==NULL || nodeIdIt_==graph_->nodeUfd_.end();
+    }
+    bool isBegin()const{
+        return graph_!=NULL && nodeIdIt_==graph_->nodeUfd_.begin();
+    }
+private:
+   friend class vigra::IteratorFacadeCoreAccess;
+    
+    
+    bool equal(const MergeGraphNodeIt<MERGE_GRAPH> & other)const{
+        return (isEnd()&&other.isEnd()) || nodeIdIt_==other.nodeIdIt_;
+    }
+    void increment(){++nodeIdIt_;}
+    const Node & dereference()const{
+        node_=Node(*nodeIdIt_);
+        return node_;
+    }
+    // members
+    const Graph * graph_;
+    typename Graph::NodeIdIt nodeIdIt_;
+    mutable Node  node_;
+};
+
+// merge graphs LEMON compatible iterator
+template<class MERGE_GRAPH>
+class MergeGraphEdgeIt
+:   public ForwardIteratorFacade<MergeGraphEdgeIt<MERGE_GRAPH>,typename MERGE_GRAPH::Edge,true>{
+public:
+    typedef MERGE_GRAPH Graph;
+    typedef typename Graph::Edge Edge;
+    // Invalid constructor & conversion. 
+    MergeGraphEdgeIt(const lemon::Invalid & invalid = lemon::INVALID)
+    :   graph_(NULL),
+        edgeIdIt_(),
+        edge_(){
+    }
+    MergeGraphEdgeIt(const Graph & g)
+    :   graph_(&g),
+        edgeIdIt_(g.edgeUfd_.begin()),
+        edge_(){
+
+    }
+    MergeGraphEdgeIt(const Graph & g,const Edge & node)
+    :   graph_(&g),
+        edgeIdIt_(g.edgeUfd_.iteratorAt(g.id(node))),
+        edge_(){
+    }
+    bool isEnd()const{ 
+        return graph_==NULL || edgeIdIt_==graph_->edgeUfd_.end();
+    }
+    bool isBegin()const{
+        return graph_!=NULL && edgeIdIt_==graph_->edgeUfd_.begin();
+    }
+private:
+    friend class vigra::IteratorFacadeCoreAccess;
+    
+    
+    bool equal(const MergeGraphEdgeIt<MERGE_GRAPH> & other)const{
+        return (isEnd()&&other.isEnd()) || edgeIdIt_==other.edgeIdIt_;
+    }
+    void increment(){
+        ++edgeIdIt_;
+    }
+    const Edge & dereference()const{
+        edge_=Edge(*edgeIdIt_);
+        return edge_;
+    }
+    // members
+    const Graph * graph_;
+    typename Graph::EdgeIdIt edgeIdIt_;
+    mutable Edge  edge_;
+};
+
+// merge graphs LEMON compatible iterator
+template<class GRAPH>
+class MergeGraphArcIt
+: public ForwardIteratorFacade<
+    MergeGraphArcIt<GRAPH>,typename GRAPH::Arc,true
+>
+{
+public:
+    typedef GRAPH Graph;
+    typedef typename  Graph::Arc Arc;
+    typedef typename  Graph::Edge Edge;
+    typedef typename  Graph::EdgeIt EdgeIt;
+    MergeGraphArcIt(const lemon::Invalid invalid = lemon::INVALID )
+    :   graph_(NULL),
+        pos_(),
+        inFirstHalf_(false),
+        veryEnd_(true),
+        arc_(){
+    }
+    MergeGraphArcIt(const GRAPH & g )
+    :   graph_(&g),
+        pos_(g),
+        inFirstHalf_(true),
+        veryEnd_( g.edgeNum()==0 ? true : false),
+        arc_(){
+    }
+
+    MergeGraphArcIt(const GRAPH & g , const Arc & arc )
+    :   graph_(&g),
+        pos_(g,arc.edgeId()),
+        inFirstHalf_(g.id(arc)<=g.maxEdgeId()),
+        veryEnd_(false),
+        arc_(){
+    }
+private:
+    friend class vigra::IteratorFacadeCoreAccess;
+    bool isEnd()const{
+        return veryEnd_ || graph_==NULL;
+    }
+
+    bool isBegin()const{
+        return graph_!=NULL &&  veryEnd_==false && pos_ == EdgeIt(*graph_);         
+    }
+
+    void increment() {
+        if(inFirstHalf_){
+            ++pos_;
+            if(pos_ == lemon::INVALID  ) {
+                pos_ = EdgeIt(*graph_);
+                inFirstHalf_=false;
+            }
+            return;
+        }
+        else{
+            ++pos_;
+            if(pos_ == lemon::INVALID){
+                veryEnd_=true;
+            }
+            return;
+        }
+    
+       
+    }
+    bool equal(MergeGraphArcIt const& other) const{
+        return (
+            (
+                isEnd()==other.isEnd()                  &&
+                inFirstHalf_==other.inFirstHalf_ 
+            ) &&
+            (isEnd() || graph_==NULL || pos_==other.pos_ )
+            );
+            
+    }
+
+    const Arc & dereference() const { 
+        //std::cout<<graph_->id(*pos_)<<"\n";
+        arc_ = graph_->direct(*pos_,inFirstHalf_);
+        return arc_;
+    }
+
+
+    const GRAPH * graph_;
+    EdgeIt pos_;
+    bool inFirstHalf_;
+    bool veryEnd_;
+    mutable Arc arc_;
+};
+
+
+// callbacks of merge graph 
+// to update node and edge maps w.r.t. edge contractions
+template<class NODE,class EDGE>
+class MergeGraphCallbacks{
+    public:
+
+        typedef delegate2<void ,const NODE & ,const NODE &>        MergeNodeCallBackType;
+        typedef delegate2<void ,const EDGE & ,const EDGE &>        MergeEdgeCallBackType;
+        typedef delegate1<void ,const EDGE &>                      EraseEdgeCallBackType;
+
+        MergeGraphCallbacks(){}
+
+        void registerMergeNodeCallBack(MergeNodeCallBackType  f){
+            mergeNodeCallbacks_.push_back(f);
+        }
+        void registerMergeEdgeCallBack(MergeEdgeCallBackType  f){
+            mergeEdgeCallbacks_.push_back(f);
+        }
+        void registerEraseEdgeCallBack(EraseEdgeCallBackType  f){
+            eraseEdgeCallbacks_.push_back(f);
+        }
+
+    protected:
+        void callMergeNodeCallbacks(const NODE & a,const NODE & b){
+            for(size_t i=0;i<mergeNodeCallbacks_.size();++i)
+                mergeNodeCallbacks_[i](a,b);
+        }
+        void callMergeEdgeCallbacks(const EDGE & a,const EDGE & b){
+            for(size_t i=0;i<mergeEdgeCallbacks_.size();++i)
+                mergeEdgeCallbacks_[i](a,b);
+        }
+        void callEraseEdgeCallbacks(const EDGE & a){
+            for(size_t i=0;i<eraseEdgeCallbacks_.size();++i)
+                eraseEdgeCallbacks_[i](a);
+        }
+        void clearCallbacks(){
+            mergeNodeCallbacks_.clear();
+            mergeEdgeCallbacks_.clear();
+            eraseEdgeCallbacks_.clear();
+        }
+    private:
+        std::vector<MergeNodeCallBackType> mergeNodeCallbacks_;
+        std::vector<MergeEdgeCallBackType> mergeEdgeCallbacks_;
+        std::vector<EraseEdgeCallBackType> eraseEdgeCallbacks_;
+};
+
+
+
+/** \brief undirected graph adaptor 
+      for edge contraction and feature merging
+    */
+template<class GRAPH>
+class MergeGraphAdaptor 
+:   public MergeGraphCallbacks<
+        detail::GenericNode<vigra::Int64> ,
+        detail::GenericEdge<vigra::Int64> 
+    > 
+
+{
+
+    public:
+    typedef vigra::Int64             IdType;
+    typedef IdType                   index_type;
+    typedef MergeGraphAdaptor<GRAPH> MergeGraphType;
+
+
+    typedef detail::GenericNode<index_type>  Node;
+    typedef detail::GenericEdge<index_type>  Edge;
+    typedef detail::GenericArc<index_type>   Arc;
+
+    typedef GRAPH Graph;
+    typedef typename Graph::Node GraphNode;
+    typedef typename Graph::Edge GraphEdge;
+    typedef typename Graph::Node GraphArc;
+
+
+
+    
+
+    //typedef  std::set<index_type>   NodeStorageEdgeSet;
+    typedef detail::GenericNodeImpl<index_type,false >  NodeStorage;
+    typedef detail::GenericEdgeImpl<index_type >        EdgeStorage;
+
+
+
+    private:
+        
+        typedef std::map<vigra::UInt64 , std::vector<IdType>  > DoubleMap;
+        typedef merge_graph_detail::IterablePartition<IdType> UfdType;
+        typedef typename UfdType::const_iterator ConstUdfIter;
+        typedef ConstUdfIter                                                EdgeIdIt;
+        typedef ConstUdfIter                                                NodeIdIt;
+        typedef detail::NeighborNodeFilter<MergeGraphType>                  NnFilter;
+        typedef detail::IncEdgeFilter<MergeGraphType>                       IncFilter;
+        typedef detail::IsInFilter<MergeGraphType>                          InFlter;
+        typedef detail::IsOutFilter<MergeGraphType>                         OutFilter;
+    public:
+        typedef MergeGraphNodeIt<MergeGraphType>                                 NodeIt;
+        typedef MergeGraphEdgeIt<MergeGraphType>                                 EdgeIt;
+        typedef MergeGraphArcIt<MergeGraphType>                                  ArcIt;
+        typedef detail::GenericIncEdgeIt<MergeGraphType,NodeStorage,NnFilter  >  NeighborNodeIt;
+        typedef detail::GenericIncEdgeIt<MergeGraphType,NodeStorage,IncFilter >  IncEdgeIt;
+        typedef detail::GenericIncEdgeIt<MergeGraphType,NodeStorage,InFlter   >  InArcIt;
+        typedef detail::GenericIncEdgeIt<MergeGraphType,NodeStorage,OutFilter >  OutArcIt;
+        
+
+
+        template<class T>
+        struct EdgeMap : DenseEdgeReferenceMap<MergeGraphType,T> {
+            EdgeMap(): DenseEdgeReferenceMap<MergeGraphType,T>(){
+            }
+            EdgeMap(const MergeGraphType & g)
+            : DenseEdgeReferenceMap<MergeGraphType,T>(g){
+            }
+            EdgeMap(const MergeGraphType & g,const T & val)
+            : DenseEdgeReferenceMap<MergeGraphType,T>(g,val){
+            }
+        };
+
+        template<class T>
+        struct NodeMap : DenseNodeReferenceMap<MergeGraphType,T> {
+            NodeMap(): DenseNodeReferenceMap<MergeGraphType,T>(){
+            }
+            NodeMap(const MergeGraphType & g)
+            : DenseNodeReferenceMap<MergeGraphType,T>(g){
+            }
+            NodeMap(const MergeGraphType & g,const T & val)
+            : DenseNodeReferenceMap<MergeGraphType,T>(g,val){
+            }
+        };
+
+        template<class T>
+        struct ArcMap : DenseArcReferenceMap<MergeGraphType,T> {
+            ArcMap(): DenseArcReferenceMap<MergeGraphType,T>(){
+            }
+            ArcMap(const MergeGraphType & g)
+            : DenseArcReferenceMap<MergeGraphType,T>(g){
+            }
+            ArcMap(const MergeGraphType & g,const T & val)
+            : DenseArcReferenceMap<MergeGraphType,T>(g,val){
+            }
+        };
+
+
+        
+    private:
+        MergeGraphAdaptor();                               // non empty-construction
+        MergeGraphAdaptor( const MergeGraphAdaptor& other );      // non construction-copyable
+        MergeGraphAdaptor& operator=( const MergeGraphAdaptor& ); // non copyable
+    public:
+        MergeGraphAdaptor(const Graph &  graph);
+        //void   setInitalEdge(const size_t initEdge,const size_t initNode0,const size_t initNode1);
+
+        // query (sizes) 
+        size_t edgeNum()const;
+        size_t nodeNum()const;
+        size_t arcNum()const;
+
+        IdType maxEdgeId()const;
+        IdType maxNodeId()const;
+        IdType maxArcId()const;
+
+
+        // query (iterators )
+        EdgeIdIt  edgeIdsBegin()const;
+        EdgeIdIt  edgeIdsEnd()const;
+        NodeIdIt  nodeIdsBegin()const;
+        NodeIdIt  nodeIdsEnd()const;
+
+
+
+
+        //  query (get edge / nodes from id)
+        Edge  edgeFromId(const IdType index)const;
+        Node  nodeFromId(const IdType index)const;
+        Arc   arcFromId( const IdType index)const;
+
+
+
+
+
+        // query ( has edge )
+        bool hasEdgeId(const IdType edgeIndex)const;
+        bool hasNodeId(const IdType nodeIndex)const;
+        bool hasArcId(const IdType  arcId)const{
+            return hasEdgeId(arcFromId(arcId).edgeId());
+        }
+
+
+        Edge findEdge(const Node & a,const Node & b)const;
+        Arc  findArc(const Node & u,const Node & v)const;
+
+
+        IdType id(const Edge & edge)const;
+        IdType id(const Node & node)const;
+        IdType id(const Arc & arc)const;
+
+
+        size_t degree(const Node & node)const;
+
+
+
+        Node  u(const Edge & edge)const;
+        Node  v(const Edge & edge)const;
+
+        Node source(const Arc & arc)const{
+            if(arc!=lemon::INVALID)
+                return direction(arc) ? u(Edge(arc)) : v(Edge(arc));
+            else
+                return Node(lemon::INVALID);
+        }
+        Node target(const Arc & arc)const{
+            if(arc!=lemon::INVALID)
+                return direction(arc) ? v(Edge(arc)) : u(Edge(arc));
+            else
+                return Node(lemon::INVALID);
+        }
+
+
+        // query (w.r.t. inital nodesIds/edgesIds)
+        IdType reprEdgeId(const IdType edgeIndex)const;
+        IdType reprNodeId(const IdType nodeIndex)const;
+        bool stateOfInitalEdge(const IdType initalEdge)const;
+        // modification
+        void contractEdge(const Edge & edge);
+
+
+        Node oppositeNode(Node const &n, const Edge &e) const {
+            const Node uNode = u(e);
+            const Node vNode = v(e);
+            if(id(uNode)==id(n)){
+                return vNode;
+            }
+            else if(id(vNode)==id(n)){
+                return uNode;
+            }
+            else{
+                return Node(lemon::INVALID);
+            }
+        }
+
+
+        Arc direct(const Edge & edge,const bool forward)const{
+            if(edge!=lemon::INVALID){
+                if(forward)
+                    return Arc(id(edge),id(edge));
+                else
+                    return Arc(id(edge)+(maxEdgeId()+1),id(edge));
+            }
+            else{
+                return Arc(lemon::INVALID);
+            }
+        }
+        Arc direct(const Edge & edge,const Node & node)const{
+            if(u(edge)==node)
+                return direct(edge,true);
+            else if(v(edge)==node)
+                return direct(edge,false);
+            else
+                return Arc(lemon::INVALID);
+        }
+
+        bool direction(const Arc & arc)const{
+            return arc.id()==arc.edgeId();
+        }
+
+    
+        // special merge graph members 
+        GraphEdge reprGraphEdge(const GraphEdge & edge)const{
+            return  graph_.edgeFromId(reprEdgeId(graph_.id(edge)));
+        }
+        GraphNode reprGraphNode(const GraphNode & node)const{
+            return graph_.nodeFromId(reprNodeId(graph_.id(node)));
+        }
+
+
+        Edge reprEdge(const GraphEdge & edge)const{
+            return  edgeFromId(reprEdgeId(graph_.id(edge)));
+        }
+        Node reprNode(const GraphNode & node)const{
+            return nodeFromId(reprNodeId(graph_.id(node)));
+        }
+
+        const Graph & graph()const{
+            return graph_;
+        }
+        const Graph & graph(){
+            return graph_;
+        }
+
+        // in which node is a "merged inactive" edge
+        Node inactiveEdgesNode(const Edge edge)const{
+            return reprNodeId(graphUId(id(edge)));
+        }
+        size_t maxDegree()const{
+            size_t md=0;
+            for(NodeIt it(*this);it!=lemon::INVALID;++it){
+                std::max(md, size_t( degree(*it) ) );
+            }
+            return md;
+        }
+
+        void reset();
+
+    private:
+        // needs acces to const nodeImpl
+        template<class G,class NIMPL,class FILT>
+        friend class detail::GenericIncEdgeIt;
+
+        template<class G>
+        friend struct detail::NeighborNodeFilter;
+        template<class G>
+        friend struct detail::IncEdgeFilter;
+        template<class G>
+        friend struct detail::BackEdgeFilter;
+        template<class G>
+        friend struct detail::IsOutFilter;
+        template<class G>
+        friend struct detail::IsInFilter;
+        friend class MergeGraphNodeIt<MergeGraphType>;
+        friend class MergeGraphArcIt<MergeGraphType>;
+        friend class MergeGraphEdgeIt<MergeGraphType>;
+
+        Edge  edgeFromIdUnsave(const IdType index)const;
+
+        index_type  uId(const index_type edgeId)const;
+        index_type  vId(const index_type edgeId)const;
+        index_type  graphUId(const index_type edgeId)const;
+        index_type  graphVId(const index_type edgeId)const;
+        //index_type  uId(const Edge & edge)const{return uId(id(edge));}
+        //index_type  vId(const Edge & edge)const{return vId(id(edge));}
+        const NodeStorage & nodeImpl(const Node & node)const{
+            return nodeVector_[id(node)];
+        }
+        NodeStorage & nodeImpl(const Node & node){
+            return nodeVector_[id(node)];
+        }
+
+
+        const GRAPH & graph_;
+        UfdType nodeUfd_;
+        UfdType edgeUfd_;
+
+        std::vector< NodeStorage >  nodeVector_;
+
+        size_t nDoubleEdges_;
+        std::vector<std::pair<index_type,index_type> > doubleEdges_;
+};
+
+
+template<class GRAPH>
+MergeGraphAdaptor<GRAPH>::MergeGraphAdaptor(const GRAPH & graph )
+:   MergeGraphCallbacks<Node,Edge >(),
+    graph_(graph),
+    nodeUfd_(graph.maxNodeId()+1),
+    edgeUfd_(graph.maxEdgeId()+1),
+    nodeVector_(graph.maxNodeId()+1),
+    nDoubleEdges_(0),
+    doubleEdges_(graph_.edgeNum()/2 +1)
+{
+    for(index_type possibleNodeId = 0 ; possibleNodeId <= graph_.maxNodeId(); ++possibleNodeId){
+        if(graph_.nodeFromId(possibleNodeId)==lemon::INVALID){
+            nodeUfd_.eraseElement(possibleNodeId);
+        }
+        else{
+            nodeVector_[possibleNodeId].id_ = possibleNodeId;
+        }
+    }
+    for(index_type possibleEdgeId = 0 ; possibleEdgeId <= graph_.maxEdgeId(); ++possibleEdgeId){
+        const GraphEdge possibleEdge(graph_.edgeFromId(possibleEdgeId));
+        if(possibleEdge==lemon::INVALID){
+            edgeUfd_.eraseElement(possibleEdgeId);
+        }
+        else{
+            const index_type guid = graphUId(possibleEdgeId);
+            const index_type gvid = graphVId(possibleEdgeId);
+            nodeVector_[ guid ].insert(gvid,possibleEdgeId);
+            nodeVector_[ gvid ].insert(guid,possibleEdgeId);   
+        }
+    }
+    
+}
+
+
+template<class GRAPH>
+void MergeGraphAdaptor<GRAPH>::reset  (){
+
+    nodeUfd_.reset(graph_.maxNodeId()+1),
+    edgeUfd_.reset(graph_.maxEdgeId()+1),
+
+    this->clearCallbacks();
+
+    // clean nodes_
+    for(index_type possibleNodeId = 0 ; possibleNodeId <= graph_.maxNodeId(); ++possibleNodeId){
+
+        nodeVector_[possibleNodeId].clear();
+        if(graph_.nodeFromId(possibleNodeId)==lemon::INVALID){
+            nodeUfd_.eraseElement(possibleNodeId);
+        }
+        else{
+            nodeVector_[possibleNodeId].id_ = possibleNodeId;
+        }
+    }
+
+    for(index_type possibleEdgeId = 0 ; possibleEdgeId <= graph_.maxEdgeId(); ++possibleEdgeId){
+        const GraphEdge possibleEdge(graph_.edgeFromId(possibleEdgeId));
+        if(possibleEdge==lemon::INVALID){
+            edgeUfd_.eraseElement(possibleEdgeId);
+        }
+        else{
+            const index_type guid = graphUId(possibleEdgeId);
+            const index_type gvid = graphVId(possibleEdgeId);
+            nodeVector_[ guid ].insert(gvid,possibleEdgeId);
+            nodeVector_[ gvid ].insert(guid,possibleEdgeId);   
+        }
+    }
+}
+
+
+template<class GRAPH>
+inline  typename MergeGraphAdaptor<GRAPH>::Edge
+MergeGraphAdaptor<GRAPH>::findEdge  (
+    const typename MergeGraphAdaptor<GRAPH>::Node & a,
+    const typename MergeGraphAdaptor<GRAPH>::Node & b
+)const{
+
+    if(a!=b){
+        std::pair<index_type,bool> res =  nodeVector_[id(a)].findEdge(id(b));
+        if(res.second){
+            return Edge(res.first);
+        }
+    }
+    return Edge(lemon::INVALID);
+}
+
+template<class GRAPH>
+inline  typename MergeGraphAdaptor<GRAPH>::Arc
+MergeGraphAdaptor<GRAPH>::findArc  (
+    const typename MergeGraphAdaptor<GRAPH>::Node & uNode,
+    const typename MergeGraphAdaptor<GRAPH>::Node & vNode
+)const{
+    const Edge edge = findEdge(uNode,vNode);
+    if(edge==lemon::INVALID)
+        return Arc(lemon::INVALID);
+    else
+        return  direct(edge,u(edge)==uNode);
+}
+
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::Node 
+MergeGraphAdaptor<GRAPH>::u(const Edge & edge)const{
+    return nodeFromId(uId(id(edge)));
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::Node 
+MergeGraphAdaptor<GRAPH>::v(const Edge & edge)const{
+    return nodeFromId(vId(id(edge)));
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::index_type 
+MergeGraphAdaptor<GRAPH>::uId(const index_type edgeId)const{
+    return reprNodeId(graphUId(edgeId));
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::index_type 
+MergeGraphAdaptor<GRAPH>::vId(const index_type edgeId)const{
+    return reprNodeId(graphVId(edgeId));
+}
+
+
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::index_type 
+MergeGraphAdaptor<GRAPH>::graphUId(const index_type edgeId)const{
+    return graph_.id(graph_.u(graph_.edgeFromId(edgeId)));
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::index_type 
+MergeGraphAdaptor<GRAPH>::graphVId(const index_type edgeId)const{
+    return graph_.id(graph_.v(graph_.edgeFromId(edgeId)));
+}
+
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::IdType 
+MergeGraphAdaptor<GRAPH>::maxEdgeId()const {
+    return static_cast<index_type>(edgeUfd_.lastRep());
+}
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::IdType 
+MergeGraphAdaptor<GRAPH>::maxNodeId()const {
+    return static_cast<index_type>(nodeUfd_.lastRep());
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::IdType 
+MergeGraphAdaptor<GRAPH>::maxArcId()const {
+    return maxEdgeId()*2 +1 ;
+}
+
+
+#ifndef DOXYGEN  // doxygen doesn't understand this
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::IdType 
+MergeGraphAdaptor<GRAPH>::id(
+    const typename MergeGraphAdaptor<GRAPH>::Edge & edge
+)const{
+    return edge.id();
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::IdType 
+MergeGraphAdaptor<GRAPH>::id(
+    const typename MergeGraphAdaptor<GRAPH>::Node & node
+)const{
+    return node.id();
+}
+   
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::IdType 
+MergeGraphAdaptor<GRAPH>::id(
+    const typename MergeGraphAdaptor<GRAPH>::Arc & arc
+)const{
+    return arc.id();
+}
+
+#endif //DOXYGEN
+
+
+template<class GRAPH>
+inline size_t 
+MergeGraphAdaptor<GRAPH>::degree(
+    typename MergeGraphAdaptor<GRAPH>::Node const & node
+)const{
+    return static_cast<size_t>( nodeVector_[id(node)].edgeNum() );
+}
+
+
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::EdgeIdIt 
+MergeGraphAdaptor<GRAPH>::edgeIdsBegin()const{
+    return edgeUfd_.begin();
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::EdgeIdIt 
+MergeGraphAdaptor<GRAPH>::edgeIdsEnd()const{
+    return edgeUfd_.end();
+}
+
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::NodeIdIt 
+MergeGraphAdaptor<GRAPH>::nodeIdsBegin()const{
+    return nodeUfd_.begin();
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::NodeIdIt 
+MergeGraphAdaptor<GRAPH>::nodeIdsEnd()const{
+    return nodeUfd_.end();
+}
+
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::Edge 
+MergeGraphAdaptor<GRAPH>::edgeFromIdUnsave(
+    const typename MergeGraphAdaptor<GRAPH>::IdType index
+)const{
+    return Edge(index);
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::Edge 
+MergeGraphAdaptor<GRAPH>::edgeFromId(
+    const typename MergeGraphAdaptor<GRAPH>::IdType index
+)const{
+    if (hasEdgeId(index))
+        return Edge(index);
+    else
+        return Edge(lemon::INVALID);
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::Node 
+MergeGraphAdaptor<GRAPH>::nodeFromId(
+    const typename MergeGraphAdaptor<GRAPH>::IdType index
+)const{
+    if(hasNodeId(index))
+        return Node(index);
+    else
+        return Node(lemon::INVALID);
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::Arc 
+MergeGraphAdaptor<GRAPH>::arcFromId(
+    const typename MergeGraphAdaptor<GRAPH>::IdType index
+)const{
+    if(index<=maxEdgeId( ))
+        return  Arc(index,index);
+    else
+        return Arc(index, index-maxEdgeId() -1);
+}
+
+template<class GRAPH>
+inline bool 
+MergeGraphAdaptor<GRAPH>::hasEdgeId(
+    const typename MergeGraphAdaptor<GRAPH>::IdType edgeIndex
+)const{
+    if(edgeIndex<=maxEdgeId() && !edgeUfd_.isErased(edgeIndex)){
+        const IdType reprEdgeIndex = reprEdgeId(edgeIndex);
+        if(reprEdgeIndex!=edgeIndex){
+            return false;
+        }
+        else{
+            const index_type rnid0=  uId(reprEdgeIndex);
+            const index_type rnid1=  vId(reprEdgeIndex);
+            return rnid0!=rnid1;
+        }
+    }
+    else{
+        return false;
+    }
+}
+
+template<class GRAPH>
+inline bool 
+MergeGraphAdaptor<GRAPH>::hasNodeId(
+    const typename MergeGraphAdaptor<GRAPH>::IdType nodeIndex
+)const{
+
+    return nodeIndex<=maxNodeId() &&  !nodeUfd_.isErased(nodeIndex) && nodeUfd_.find(nodeIndex)==nodeIndex;
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::IdType 
+MergeGraphAdaptor<GRAPH>::reprEdgeId(
+    const typename MergeGraphAdaptor<GRAPH>::IdType edgeIndex
+)const{
+    return edgeUfd_.find(edgeIndex);
+}
+
+template<class GRAPH>
+inline typename MergeGraphAdaptor<GRAPH>::IdType 
+MergeGraphAdaptor<GRAPH>::reprNodeId(
+    const typename MergeGraphAdaptor<GRAPH>::IdType nodeIndex
+)const{
+    return nodeUfd_.find(nodeIndex);
+}
+
+template<class GRAPH>
+inline bool MergeGraphAdaptor<GRAPH>::stateOfInitalEdge(
+    const typename MergeGraphAdaptor<GRAPH>::IdType initalEdge
+)const{
+    const index_type rep = reprEdgeId(initalEdge);
+
+    const index_type rnid0=  reprNodeId( graphUId(initalEdge) );
+    const index_type rnid1=  reprNodeId( graphVId(initalEdge) );
+    return rnid0!=rnid1;
+}
+
+template<class GRAPH>
+inline size_t MergeGraphAdaptor<GRAPH>::nodeNum()const{
+    return nodeUfd_.numberOfSets();
+}
+
+template<class GRAPH>
+inline size_t MergeGraphAdaptor<GRAPH>::arcNum()const{
+    return edgeNum()*2;
+}
+
+template<class GRAPH>
+inline size_t MergeGraphAdaptor<GRAPH>::edgeNum()const{
+    return edgeUfd_.numberOfSets();
+}
+
+template<class GRAPH>
+void MergeGraphAdaptor<GRAPH>::contractEdge(
+    const typename MergeGraphAdaptor<GRAPH>::Edge & toDeleteEdge
+){
+    //std::cout<<"node num "<<nodeNum()<<"\n";
+    const index_type toDeleteEdgeIndex = id(toDeleteEdge);
+    const index_type nodesIds[2]={id(u(toDeleteEdge)),id(v(toDeleteEdge))};
+
+    // merge the two nodes
+    nodeUfd_.merge(nodesIds[0],nodesIds[1]);
+    const IdType newNodeRep    = reprNodeId(nodesIds[0]);
+    const IdType notNewNodeRep =  (newNodeRep == nodesIds[0] ? nodesIds[1] : nodesIds[0] );
+
+    typename NodeStorage::AdjIt iter=nodeVector_[notNewNodeRep].adjacencyBegin();
+    typename NodeStorage::AdjIt end =nodeVector_[notNewNodeRep].adjacencyEnd();
+   
+    nDoubleEdges_=0;
+    for(;iter!=end;++iter){
+        const size_t adjToDeadNodeId = iter->nodeId(); 
+        if(adjToDeadNodeId!=newNodeRep){
+
+            // REFACTOR ME,  we can make that faster if
+            // we do that in set intersect style
+            std::pair<index_type,bool> found=nodeVector_[adjToDeadNodeId].findEdge(newNodeRep);
+
+
+            if(found.second){
+                edgeUfd_.merge(iter->edgeId(),found.first);
+                
+                const index_type edgeA = iter->edgeId();
+                const index_type edgeB = found.first;
+                const index_type edgeR  = edgeUfd_.find(edgeA);
+                const index_type edgeNR = edgeR==edgeA ? edgeB : edgeA; 
+
+                nodeVector_[adjToDeadNodeId].eraseFromAdjacency(notNewNodeRep);
+
+                // refactor me ... this DOES NOT change the key
+                nodeVector_[adjToDeadNodeId].eraseFromAdjacency(newNodeRep);
+                nodeVector_[adjToDeadNodeId].insert(newNodeRep,edgeR);
+
+                // refactor me .. this DOES NOT change the key
+                nodeVector_[newNodeRep].eraseFromAdjacency(adjToDeadNodeId);
+                nodeVector_[newNodeRep].insert(adjToDeadNodeId,edgeR);
+
+                doubleEdges_[nDoubleEdges_]=std::pair<index_type,index_type>(edgeR,edgeNR );
+                ++nDoubleEdges_;
+            }
+            else{
+                nodeVector_[adjToDeadNodeId].eraseFromAdjacency(notNewNodeRep);
+                //nodeVector_[adjToDeadNodeId].eraseFromAdjacency(newNodeRep);
+                nodeVector_[adjToDeadNodeId].insert(newNodeRep,iter->edgeId());
+
+                // symetric
+                //nodeVector_[newNodeRep].eraseFromAdjacency(adjToDeadNodeId);
+                nodeVector_[newNodeRep].insert(adjToDeadNodeId,iter->edgeId());
+
+            }
+        }
+    }
+
+    //nodeVector_[newNodeRep].merge(nodeVector_[notNewNodeRep]);
+    nodeVector_[newNodeRep].eraseFromAdjacency(notNewNodeRep);
+    //nodeVector_[newNodeRep].eraseFromAdjacency(newNodeRep); // no self adjacecy
+    nodeVector_[notNewNodeRep].clear();
+    
+    edgeUfd_.eraseElement(toDeleteEdgeIndex);
+
+    //std::cout<<"merge nodes callbacks\n";
+    
+    this->callMergeNodeCallbacks(Node(newNodeRep),Node(notNewNodeRep));
+
+    //std::cout<<"merge double edge callbacks\n";
+    for(size_t de=0;de<nDoubleEdges_;++de){
+        this->callMergeEdgeCallbacks(Edge(doubleEdges_[de].first),Edge(doubleEdges_[de].second));
+    }
+    //std::cout<<"erase edge callbacks\n";
+    this->callEraseEdgeCallbacks(Edge(toDeleteEdgeIndex));
+
+    //std::cout<<"and done\n";
+}
+
+
+
+namespace merge_graph_detail {
+/// Construct a partition.
+template<class T>
+IterablePartition<T>::IterablePartition()
+: parents_(),
+  ranks_(),
+  jumpVec_(),
+  firstRep_(0),
+  lastRep_(0),
+  numberOfElements_(0),
+  numberOfSets_(0)
+{}
+
+/// Construct a partition.
+///
+/// \param size Number of distinct sets.
+///
+template<class T>
+inline
+IterablePartition<T>::IterablePartition
+(
+   const value_type& size
+)
+: parents_(static_cast<SizeTType>(size)),
+  ranks_(static_cast<SizeTType>(size)),
+  jumpVec_(static_cast<SizeTType>(size)),
+  firstRep_(0),
+  lastRep_(static_cast<SizeTType>(size)-1),
+  numberOfElements_(size),
+  numberOfSets_(size)
+{
+   for(T j=0; j<size; ++j) {
+      parents_[static_cast<SizeTType>(j)] = j;
+   }
+
+   jumpVec_.front().first=0;
+   jumpVec_.front().second=1;
+   for(T j=1; j<size-1;++j){
+      jumpVec_[j].first =1;
+      jumpVec_[j].second=1;
+   }
+   jumpVec_.back().first=1;
+   jumpVec_.back().second=0;
+}
+
+/// Reset a partition such that each set contains precisely one element
+///
+/// \param size Number of distinct sets.
+///
+template<class T>
+inline void
+IterablePartition<T>::reset
+(
+   const value_type& size
+)
+{
+   numberOfElements_ = size;
+   numberOfSets_ = size;
+   ranks_.resize(static_cast<SizeTType>(size));
+   parents_.resize(static_cast<SizeTType>(size));
+   jumpVec_.resize(static_cast<SizeTType>(size));
+   firstRep_=0;
+   lastRep_=static_cast<SizeTType>(size)-1;
+   for(T j=0; j<size; ++j) {
+      ranks_[static_cast<SizeTType>(j)] = 0;
+      parents_[static_cast<SizeTType>(j)] = j;
+   }
+
+   jumpVec_.front().first=0;
+   jumpVec_.front().second=1;
+   for(T j=1; j<size-1;++j){
+      jumpVec_[j].first =1;
+      jumpVec_[j].second=1;
+   }
+   jumpVec_.back().first=1;
+   jumpVec_.back().second=0;
+}
+
+/// Find the representative element of the set that contains the given element.
+///
+/// This constant function does not compress the search path.
+///
+/// \param element Element.
+///
+template<class T>
+inline typename IterablePartition<T>::value_type
+IterablePartition<T>::find
+(
+   const value_type& element
+) const
+{
+   // find the root
+   value_type root = element;
+   while(parents_[static_cast<SizeTType>(root)] != root) {
+      root = parents_[static_cast<SizeTType>(root)];
+   }
+   return root;
+}
+
+/// Find the representative element of the set that contains the given element.
+///
+/// This mutable function compresses the search path.
+///
+/// \param element Element.
+///
+template<class T>
+inline typename IterablePartition<T>::value_type
+IterablePartition<T>::find
+(
+   value_type element // copy to work with
+)
+{
+   // find the root
+   value_type root = element;
+   while(parents_[static_cast<SizeTType>(root)] != root) {
+      root = parents_[static_cast<SizeTType>(root)];
+   }
+   // path compression
+   while(element != root) {
+      value_type tmp = parents_[static_cast<SizeTType>(element)];
+      parents_[static_cast<SizeTType>(element)] = root;
+      element = tmp;
+   }
+   return root;
+}
+
+/// Merge two sets.
+///
+/// \param element1 Element in the first set.
+/// \param element2 Element in the second set.
+///
+template<class T>
+inline void
+IterablePartition<T>::merge
+(
+   value_type element1,
+   value_type element2
+)
+{
+   // merge by rank
+   element1 = find(element1);
+   element2 = find(element2);
+   if(element1!=element2){
+      T notRep;
+      if(ranks_[static_cast<SizeTType>(element1)] < ranks_[static_cast<SizeTType>(element2)]) {
+         parents_[static_cast<SizeTType>(element1)] = element2;
+         --numberOfSets_;
+         //rep=element2;
+         notRep=element1;
+      }
+      else if(ranks_[static_cast<SizeTType>(element1)] > ranks_[static_cast<SizeTType>(element2)]) {
+         parents_[static_cast<SizeTType>(element2)] = element1;
+         --numberOfSets_;
+         //rep=element1;
+         notRep=element2;
+      }
+      else if(element1 != element2) {
+         parents_[static_cast<SizeTType>(element2)] = element1;
+         ++ranks_[static_cast<SizeTType>(element1)];
+         --numberOfSets_;
+         //rep=element1;
+         notRep=element2;
+      }
+      this->eraseElement(notRep,false);
+   }
+}  
+
+template<class T>
+inline typename IterablePartition<T>::value_type
+IterablePartition<T>::numberOfElements() const
+{
+   return numberOfElements_;
+}
+
+template<class T>
+inline typename IterablePartition<T>::value_type
+IterablePartition<T>::numberOfSets() const
+{
+   return numberOfSets_;
+}
+
+template<class T>
+inline bool operator == (const ConstRepIter<T> & iter,const lemon::Invalid & iv){
+    return iter.isEnd();
+}
+template<class T>
+inline bool operator == (const lemon::Invalid & iv , const ConstRepIter<T> & iter){
+    return iter.isEnd();
+}
+
+template<class T>
+inline bool operator != (const ConstRepIter<T> & iter,const lemon::Invalid & iv){
+    return !iter.isEnd();
+}
+template<class T>
+inline bool operator != (const lemon::Invalid & iv , const ConstRepIter<T> & iter){
+    return !iter.isEnd();
+}
+
+
+} // end namespace merge_graph_detail
+
+
+} // end namespace vigra
+
+
+
+#endif //VIGRA_NEW_MERGE_GRAPH_HXX
diff --git a/include/vigra/metaprogramming.hxx b/include/vigra/metaprogramming.hxx
index e02a977..aadbc85 100644
--- a/include/vigra/metaprogramming.hxx
+++ b/include/vigra/metaprogramming.hxx
@@ -49,6 +49,11 @@ namespace vigra {
 #pragma warning( disable : 4503 )
 #endif
 
+#ifdef __APPLE__
+#include <AssertMacros.h>
+#undef check
+#endif
+
 template <int N>
 class MetaInt
 {
@@ -88,30 +93,37 @@ struct VigraFalseType
 
 /********************************************************/
 /*                                                      */
-/*                   StridedArrayTag                    */
+/*          tags for MultiArray memory layout           */
 /*                                                      */
 /********************************************************/
 
 /** tag for marking a MultiArray strided.
 
-    <b>\#include</b> \<vigra/multi_array.hxx\> <br/>
+    <b>\#include</b> \<vigra/metaprogramming.hxx\> <br/>
     Namespace: vigra
 */
 struct StridedArrayTag {};
 
-/********************************************************/
-/*                                                      */
-/*                  UnstridedArrayTag                   */
-/*                                                      */
-/********************************************************/
-
 /** tag for marking a MultiArray unstrided.
 
-    <b>\#include</b> \<vigra/multi_array.hxx\> <br/>
+    <b>\#include</b> \<vigra/metaprogramming.hxx\> <br/>
     Namespace: vigra
 */
 struct UnstridedArrayTag {};
 
+/** tag for marking a MultiArray chunked.
+
+    <b>\#include</b> \<vigra/metaprogramming.hxx\> <br/>
+    Namespace: vigra
+*/
+struct ChunkedArrayTag {};
+
+/********************************************************/
+/*                                                      */
+/*                      TypeTraits                      */
+/*                                                      */
+/********************************************************/
+
 template<class T>
 class TypeTraits
 {
@@ -393,7 +405,7 @@ struct IsDerivedFrom
     static falseResult * testIsDerivedFrom(...);
     static trueResult * testIsDerivedFrom(BASE const *);
     
-    enum { resultSize = sizeof(*testIsDerivedFrom((DERIVED const *)0)) };
+    enum { resultSize = sizeof(*testIsDerivedFrom(static_cast<DERIVED const *>(0))) };
     
     static const bool value = (resultSize == 2);
     typedef typename 
@@ -408,33 +420,47 @@ template <class T>
 struct UnqualifiedType
 {
     typedef T type;
+    static const bool isConst = false;
+    static const bool isReference = false;
+    static const bool isPointer = false;
 };
 
 template <class T>
 struct UnqualifiedType<T const>
 {
     typedef T type;
+    static const bool isConst = true;
+    static const bool isReference = false;
+    static const bool isPointer = false;
 };
 
 template <class T>
 struct UnqualifiedType<T &>
 : public UnqualifiedType<T>
-{};
+{
+    static const bool isReference = true;
+};
 
 template <class T>
 struct UnqualifiedType<T const &>
-: public UnqualifiedType<T>
-{};
+: public UnqualifiedType<T const>
+{
+    static const bool isReference = true;
+};
 
 template <class T>
 struct UnqualifiedType<T *>
 : public UnqualifiedType<T>
-{};
+{
+    static const bool isPointer = true;
+};
 
 template <class T>
 struct UnqualifiedType<T const *>
-: public UnqualifiedType<T>
-{};
+: public UnqualifiedType<T const>
+{
+    static const bool isPointer = true;
+};
 
 template <bool, class T = void>
 struct enable_if {};
@@ -452,7 +478,7 @@ struct sfinae_test
     static falseResult * test(...);
     static trueResult * test(USER<sfinae_void>);
     
-    enum { resultSize = sizeof(*test((T*)0)) };
+    enum { resultSize = sizeof(*test(static_cast<T*>(0))) };
     
     static const bool value = (resultSize == 2);
     typedef typename
@@ -526,7 +552,7 @@ struct IsArray
     template <class U, unsigned n>
     static trueResult * test(U (*)[n]);
     
-    enum { resultSize = sizeof(*test((T*)0)) };
+    enum { resultSize = sizeof(*test(static_cast<T*>(0))) };
     
     static const bool value = (resultSize == 2);
     typedef typename
@@ -659,7 +685,7 @@ struct MetaPow<X, 0>
 template<class HEAD, class TAIL=void>
 struct TypeList
 {
-	typedef TypeList<HEAD, TAIL> type;
+    typedef TypeList<HEAD, TAIL> type;
     typedef HEAD Head;
     typedef TAIL Tail;
 };
diff --git a/include/vigra/metrics.hxx b/include/vigra/metrics.hxx
new file mode 100644
index 0000000..08748e7
--- /dev/null
+++ b/include/vigra/metrics.hxx
@@ -0,0 +1,277 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2014 by Thorsten Beier and Ullrich Koethe              */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+#ifndef VIGRA_METRIC_HXX
+#define VIGRA_METRIC_HXX
+
+#include <vigra/numerictraits.hxx>
+#include <vigra/multi_array.hxx>
+
+#include <cmath>
+
+namespace vigra{
+namespace metrics{
+
+
+    template<class T>
+    class ChiSquared{
+    public:
+        ChiSquared(){}
+        T operator()(const T & a,const T & b)const{
+            return opImpl(&a,&a+1,&b);
+        }
+        template<class A, class B>
+        T operator()(const A & a,const B & b)const{
+            return opImpl(a.begin(),a.end(),b.begin());
+        } 
+    private:
+        template<class ITER_A,class ITER_B>
+        T opImpl(
+            ITER_A  iterA  ,ITER_A  endA   ,ITER_B  iterB 
+        )const{   
+            T res = 0.0;
+            while(iterA!=endA){
+                const T aa=static_cast<T>(*iterA);
+                const T bb=static_cast<T>(*iterB);
+                const T sum  = aa + bb;
+                const T diff = aa - bb; 
+                if(sum> static_cast<T>(0.0000001))
+                    res+=(diff*diff)/sum;
+                ++iterA;
+                ++iterB;
+            }
+            return res*T(0.5);
+        }
+    };
+
+    template<class T>
+    class HellingerDistance{
+    public:
+        HellingerDistance(){}
+        T operator()(const T & a,const T & b)const{
+            return opImpl(&a,&a+1,&b);
+        }
+        template<class A, class B>
+        T operator()(const A & a,const B & b)const{
+            return opImpl(a.begin(),a.end(),b.begin());
+        } 
+    private:
+        template<class ITER_A,class ITER_B>
+        T opImpl(
+            ITER_A  iterA  ,ITER_A  endA   ,ITER_B  iterB 
+        )const{   
+            T res = 0.0;
+            while(iterA!=endA){
+                const T aa=std::sqrt(static_cast<T>(*iterA));
+                const T bb=std::sqrt(static_cast<T>(*iterB));
+                const T diff = aa - bb; 
+                res+=diff*diff;
+                ++iterA;
+                ++iterB;
+            }
+            return std::sqrt(res)/std::sqrt(2.0);
+        }
+    };
+    
+    template<class T,unsigned int NORM,bool TAKE_ROOT=true>
+    class PNorm{
+    public:
+        PNorm(){}
+        T operator()(const T & a,const T & b)const{
+            return opImpl(&a,&a+1,&b);
+        }
+        template<class A, class B>
+        T operator()(const A & a,const B & b)const{
+            return opImpl(a.begin(),a.end(),b.begin());
+        } 
+    private:
+        template<class ITER_A,class ITER_B>
+        T opImpl(
+            ITER_A  iterA  ,ITER_A  endA   ,ITER_B  iterB 
+        )const{
+            T res = static_cast<T>(0.0);
+            while(iterA!=endA){
+                const T aa=static_cast<T>(*iterA);
+                const T bb=static_cast<T>(*iterB);
+                const T diff = aa-bb;
+                res+= std::abs(std::pow((double)diff,(int)NORM));
+                ++iterA;
+                ++iterB;
+            }
+            return TAKE_ROOT ? std::pow(res,static_cast<T>(1)/static_cast<T>(NORM)) : res;
+        }
+    };
+
+    template<class T>
+    class SquaredNorm
+    :  public PNorm<T,2,false>{
+    public:
+        SquaredNorm()
+        :   PNorm<T,2,false>(){
+        }
+    };
+
+    template<class T>
+    class Norm
+    :  public PNorm<T,2,true>{
+    public:
+        Norm()
+        :   PNorm<T,2,true>(){
+        }
+    };
+
+    template<class T>
+    class Manhattan
+    :  public PNorm<T,1,false>{
+    public:
+        Manhattan()
+        :   PNorm<T,1,false>(){
+        }
+    };
+
+    template<class T>
+    class SymetricKlDivergenz{
+    public:
+        SymetricKlDivergenz(){}
+        T operator()(const T & a,const T & b)const{
+            return opImpl(&a,&a+1,&b);
+        }
+        template<class A, class B>
+        T operator()(const A & a,const B & b)const{
+            return opImpl(a.begin(),a.end(),b.begin());
+        } 
+    private:
+        template<class ITER_A,class ITER_B>
+        T opImpl(
+            ITER_A  iterA  ,ITER_A  endA   ,ITER_B  iterB 
+        )const{
+            T res = static_cast<T>(0.0);
+            while(iterA!=endA){
+                const T aa=static_cast<T>(*iterA);
+                const T bb=static_cast<T>(*iterB);
+                const T val = std::log(aa/bb)*(aa - bb);
+                if(!isinf(val) && !isnan(val))
+                    res+=val;
+                ++iterA;
+                ++iterB;
+            }
+            return res/static_cast<T>(2.0);
+        }
+    };
+
+    template<class T>
+    class BhattacharyaDistance{
+    public:
+        BhattacharyaDistance(){}
+        T operator()(const T & a,const T & b)const{
+            return opImpl(&a,&a+1,&b);
+        }
+        template<class A, class B>
+        T operator()(const A & a,const B & b)const{
+            return opImpl(a.begin(),a.end(),b.begin());
+        } 
+    private:
+        template<class ITER_A,class ITER_B>
+        T opImpl(
+            ITER_A  iterA  ,ITER_A  endA   ,ITER_B  iterB 
+        )const{
+            T res = static_cast<T>(0.0);
+            while(iterA!=endA){
+                const T aa=static_cast<T>(*iterA);
+                const T bb=static_cast<T>(*iterB);
+                res+=std::sqrt(aa*bb);
+                ++iterA;
+                ++iterB;
+            }
+            return std::sqrt( static_cast<T>(1.0)-res);
+        }
+    };
+
+    enum MetricType{
+        ChiSquaredMetric=0,
+        HellingerMetric=1,
+        SquaredNormMetric=2,
+        NormMetric=3,
+        ManhattanMetric=4,
+        SymetricKlMetric=5,
+        BhattacharyaMetric=6
+    };
+
+
+    template<class T>
+    class Metric{
+    public:
+
+        Metric(const MetricType metricType = ManhattanMetric)
+        : metricType_(metricType){
+
+        }
+
+        template<class A, class B>
+        T operator()(const A & a,const B & b)const{
+            switch(static_cast<unsigned int>(metricType_)){
+                case 0:
+                    return chiSquared_(a,b);
+                case 1:
+                    return hellingerDistance_(a,b);
+                case 2:
+                    return squaredNorm_(a,b);
+                case 3:
+                    return norm_(a,b);
+                case 4:
+                    return manhattan_(a,b);
+                case 5:
+                    return symetricKlDivergenz_(a,b); 
+                case 6 :
+                    return bhattacharyaDistance_(a,b); 
+                default :
+                    return 0;
+            }
+        } 
+    private:
+        MetricType metricType_;
+        ChiSquared<T> chiSquared_;
+        HellingerDistance<T> hellingerDistance_;
+        SquaredNorm<T> squaredNorm_;
+        Norm<T> norm_;
+        Manhattan<T> manhattan_;
+        SymetricKlDivergenz<T> symetricKlDivergenz_;
+        BhattacharyaDistance<T> bhattacharyaDistance_;
+    };
+
+} // end namespace metric
+} // end namepsace vigra
+
+
+#endif //VIGRA_METRIC_HXX
diff --git a/include/vigra/multi_array.hxx b/include/vigra/multi_array.hxx
index bcf8597..195dff9 100644
--- a/include/vigra/multi_array.hxx
+++ b/include/vigra/multi_array.hxx
@@ -49,6 +49,7 @@
 #include "multi_pointoperators.hxx"
 #include "metaprogramming.hxx"
 #include "mathutil.hxx"
+#include "algorithm.hxx"
 
 // Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined.
 #ifdef VIGRA_CHECK_BOUNDS
@@ -204,8 +205,7 @@ template <class SrcIterator, class Shape, class DestIterator> \
 inline void \
 name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>) \
 {     \
-    SrcIterator send = s + shape[0]; \
-    for(; s < send; ++s, ++d) \
+    for(MultiArrayIndex i=0; i < shape[0]; ++i, ++s, ++d) \
     { \
         *d op detail::RequiresExplicitCast<typename DestIterator::value_type>::cast(*s); \
     } \
@@ -215,8 +215,8 @@ template <class Ref, class Ptr, class Shape, class DestIterator> \
 inline void \
 name##MultiArrayData(MultiIterator<1, UInt8, Ref, Ptr> si, Shape const & shape, DestIterator d, MetaInt<0>) \
 { \
-    Ptr s = &(*si), send = s + shape[0]; \
-    for(; s < send; ++s, ++d) \
+    Ptr s = &(*si); \
+    for(MultiArrayIndex i=0; i < shape[0]; ++i, ++s, ++d) \
     { \
         *d op detail::RequiresExplicitCast<typename DestIterator::value_type>::cast(*s); \
     } \
@@ -226,8 +226,7 @@ template <class SrcIterator, class Shape, class DestIterator, int N> \
 void \
 name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>) \
 { \
-    SrcIterator send = s + shape[N]; \
-    for(; s < send; ++s, ++d) \
+    for(MultiArrayIndex i=0; i < shape[N]; ++i, ++s, ++d) \
     { \
         name##MultiArrayData(s.begin(), shape, d.begin(), MetaInt<N-1>()); \
     } \
@@ -237,8 +236,7 @@ template <class DestIterator, class Shape, class T> \
 inline void \
 name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<0>) \
 {     \
-    DestIterator dend = d + shape[0]; \
-    for(; d < dend; ++d) \
+    for(MultiArrayIndex i=0; i < shape[0]; ++i, ++d) \
     { \
         *d op detail::RequiresExplicitCast<typename DestIterator::value_type>::cast(init); \
     } \
@@ -248,8 +246,7 @@ template <class DestIterator, class Shape, class T, int N> \
 void \
 name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<N>) \
 {     \
-    DestIterator dend = d + shape[N]; \
-    for(; d < dend; ++d) \
+    for(MultiArrayIndex i=0; i < shape[N]; ++i, ++d) \
     { \
         name##ScalarMultiArrayData(d.begin(), shape, init, MetaInt<N-1>()); \
     } \
@@ -819,10 +816,7 @@ public:
             "MultiArrayView<..., UnstridedArrayTag>::MultiArrayView(): First dimension of given array is not unstrided.");
     }
     
-        /** Construct from shape, strides (offset of a sample to the
-            next) for every dimension, and pointer.  (Note that
-            strides are not given in bytes, but in offset steps of the
-            respective pointer type.)
+        /** Construct from an old-style BasicImage.
          */
     template <class ALLOC>
     MultiArrayView (BasicImage<T, ALLOC> const & image)
@@ -838,6 +832,16 @@ public:
         return MultiArrayView<N, T, StridedArrayTag>(m_shape, m_stride, m_ptr);
     }
 
+	/** Reset this <tt>MultiArrayView</tt> to an invalid state (as after default construction).
+		Can e.g. be used prior to assignment to make a view object point to new data.
+         */
+    void reset() {
+	m_shape = diff_zero_t(0);
+	m_stride = diff_zero_t(0);
+	m_ptr = 0;
+    }
+
+
         /** Assignment. There are 3 cases:
 
             <ul>
@@ -1172,6 +1176,35 @@ public:
         this->copyImpl(rhs);
     }
 
+        /** Swap the pointers, shaes and strides between two array views.
+        
+            This function must be used with care. Never swap a MultiArray
+            (which owns data) with a MultiArrayView:
+            \code
+                MultiArray<2, int> a(3,2), b(3,2);
+                MultiArrayView<2, int> va(a);
+                
+                va.swap(b);   // danger!
+            \endcode
+            Now, <tt>a</tt> and <tt>b</tt> refer to the same memory. This may lead
+            to a crash in their destructor, and in any case leaks <tt>b</tt>'s original 
+            memory. Only use swap() on copied MultiArrayViews:
+            \code
+                MultiArray<2, int> a(3,2), b(3,2);
+                MultiArrayView<2, int> va(a), vb(b);
+                
+                va.swap(vb);   // OK
+            \endcode
+         */
+    void swap(MultiArrayView & other)
+    {
+        if (this == &other)
+            return;
+        std::swap(this->m_shape,  other.m_shape);
+        std::swap(this->m_stride, other.m_stride);
+        std::swap(this->m_ptr,    other.m_ptr);
+    }
+
         /** swap the data between two MultiArrayView objects.
 
             The shapes of the two array must match.
@@ -1311,7 +1344,6 @@ public:
     MultiArrayView <N-1, T, StridedArrayTag>
     bindAt (difference_type_1 m, difference_type_1 d) const;
     
-    
         /** Create a view to channel 'i' of a vector-like value type. Possible value types
             (of the original array) are: \ref TinyVector, \ref RGBValue, \ref FFTWComplex, 
             and <tt>std::complex</tt>. The list can be extended to any type whose memory
@@ -1387,6 +1419,19 @@ public:
          */
     MultiArrayView <N+1, T, StrideTag>
     insertSingletonDimension (difference_type_1 i) const;
+    
+        /** create a multiband view for this array.
+
+            The type <tt>MultiArrayView<N, Multiband<T> ></tt> tells VIGRA
+            algorithms which recognize the <tt>Multiband</tt> modifier to
+            interpret the outermost (last) dimension as a channel dimension. 
+            In effect, these algorithms will treat the data as a set of 
+            (N-1)-dimensional arrays instead of a single N-dimensional array.
+        */
+    MultiArrayView<N, Multiband<value_type>, StrideTag> multiband() const
+    {
+        return MultiArrayView<N, Multiband<value_type>, StrideTag>(*this);
+    }
 
         /** Create a view to the diagonal elements of the array.
         
@@ -1447,7 +1492,7 @@ public:
     {
         difference_type shape = m_shape;
         for (unsigned int i = 0; i < actual_dimension; ++i)
-            shape [i] /= s [i];
+            shape[i] = (shape[i] + s[i] - 1) / s[i];
         return MultiArrayView <N, T, StridedArrayTag>(shape, m_stride * s, m_ptr);
     }
 
@@ -1459,7 +1504,7 @@ public:
             typedef MultiArray<2, double>::difference_type Shape;
             MultiArray<2, double> array(10, 20);
 
-            MultiArray<2, double, StridedArrayTag> transposed = array.transpose();
+            MultiArrayView<2, double, StridedArrayTag> transposed = array.transpose();
 
             for(int i=0; i<array.shape(0), ++i)
                 for(int j=0; j<array.shape(1); ++j)
@@ -1469,8 +1514,8 @@ public:
     MultiArrayView <N, T, StridedArrayTag>
     transpose () const
     {
-        difference_type shape(m_shape.begin(), difference_type::ReverseCopy),
-                        stride(m_stride.begin(), difference_type::ReverseCopy);
+        difference_type shape(m_shape.begin(),   ReverseCopy),
+                        stride(m_stride.begin(), ReverseCopy);
         return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr);
     }
 
@@ -1485,7 +1530,7 @@ public:
             typedef MultiArray<2, double>::difference_type Shape;
             MultiArray<2, double> array(10, 20);
 
-            MultiArray<2, double, StridedArrayTag> transposed = array.transpose(Shape(1,0));
+            MultiArrayView<2, double, StridedArrayTag> transposed = array.transpose(Shape(1,0));
 
             for(int i=0; i<array.shape(0), ++i)
                 for(int j=0; j<array.shape(1); ++j)
@@ -1624,6 +1669,15 @@ public:
                 return false;
         return true;
     }
+        /** check whether the given point is not in the array range.
+         */
+    bool isOutside (difference_type const & p) const
+    {
+        for(int d=0; d<actual_dimension; ++d)
+            if(p[d] < 0 || p[d] >= shape(d))
+                return true;
+        return false;
+    }
 
         /** Check if the array contains only non-zero elements (or if all elements
             are 'true' if the value type is 'bool').
@@ -1881,12 +1935,23 @@ public:
         return ret;
     }
 
-    view_type view ()
+    view_type view () const
     {
         return *this;
     }
 };
 
+template <unsigned int N, class T, class StrideTag>
+class MultiArrayView<N, Multiband<T>, StrideTag>
+: public MultiArrayView<N, T, StrideTag>
+{
+  public:
+    MultiArrayView(MultiArrayView<N, T, StrideTag> const & v)
+    : MultiArrayView<N, T, StrideTag>(v)
+    {}
+};
+
+
 template <unsigned int N, class T, class Stride1>
 template <class Stride2>
 void
@@ -2506,6 +2571,12 @@ public:
     MultiArray (const difference_type &shape, const_reference init,
                 allocator_type const & alloc = allocator_type());
 
+        /** construct from shape and initialize with a linear sequence in scan order 
+            (i.e. first pixel gets value 0, second on gets value 1 and so on).
+         */
+    MultiArray (const difference_type &shape, MultiArrayInitializationTag init,
+                allocator_type const & alloc = allocator_type());
+
         /** construct from shape and copy values from the given array
          */
     MultiArray (const difference_type &shape, const_pointer init,
@@ -2850,6 +2921,31 @@ MultiArray <N, T, A>::MultiArray (const difference_type &shape, const_reference
 }
 
 template <unsigned int N, class T, class A>
+MultiArray <N, T, A>::MultiArray (const difference_type &shape, MultiArrayInitializationTag init,
+                                  allocator_type const & alloc)
+: view_type(shape,
+            defaultStride(shape),
+            0),
+  m_alloc(alloc)
+{
+    if (N == 0)
+    {
+        this->m_shape [0] = 1;
+        this->m_stride [0] = 1;
+    }
+    allocate (this->m_ptr, this->elementCount (), value_type());
+    switch(init)
+    {
+      case LinearSequence:
+        linearSequence(this->begin(), this->end());
+        break;
+      default:
+        vigra_precondition(false,
+            "MultiArray(): invalid MultiArrayInitializationTag.");
+    }
+}
+
+template <unsigned int N, class T, class A>
 MultiArray <N, T, A>::MultiArray (const difference_type &shape, const_pointer init,
                                   allocator_type const & alloc)
 : view_type(shape,
@@ -2923,9 +3019,7 @@ MultiArray <N, T, A>::swap (MultiArray & other)
 {
     if (this == &other)
         return;
-    std::swap(this->m_shape,  other.m_shape);
-    std::swap(this->m_stride, other.m_stride);
-    std::swap(this->m_ptr,    other.m_ptr);
+    this->view_type::swap(other);
     std::swap(this->m_alloc,  other.m_alloc);
 }
 
@@ -2939,9 +3033,9 @@ void MultiArray <N, T, A>::allocate (pointer & ptr, difference_type_1 s,
         return;
     }
     ptr = m_alloc.allocate ((typename A::size_type)s);
-    difference_type_1 i;
+    difference_type_1 i = 0;
     try {
-        for (i = 0; i < s; ++i)
+        for (; i < s; ++i)
             m_alloc.construct (ptr + i, init);
     }
     catch (...) {
@@ -2963,9 +3057,9 @@ void MultiArray <N, T, A>::allocate (pointer & ptr, difference_type_1 s,
         return;
     }
     ptr = m_alloc.allocate ((typename A::size_type)s);
-    difference_type_1 i;
+    difference_type_1 i = 0;
     try {
-        for (i = 0; i < s; ++i, ++init)
+        for (; i < s; ++i, ++init)
             m_alloc.construct (ptr + i, *init);
     }
     catch (...) {
diff --git a/include/vigra/multi_array_chunked.hxx b/include/vigra/multi_array_chunked.hxx
new file mode 100644
index 0000000..28a0179
--- /dev/null
+++ b/include/vigra/multi_array_chunked.hxx
@@ -0,0 +1,3477 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2012-2014 by Ullrich Koethe and Thorben Kroeger        */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+/* benchmark results for a simple loop 'if(iter.get<1>() != count++)'
+
+    ********************
+    image size: 200^3, chunk size: 64^3, i.e. chunk count: 4^3
+    times in msec, excluding time to store file on disk
+
+    win64/vs2012 (koethe-laptop):            uint8     float    double
+    plain array                                 18        18        18
+    chunked array (all in cache)                25        26        26
+    thread-safe chunked (all in cache)          27        28        29
+    thread-safe chunked (1 slice in cache)      29        33        39
+    thread-safe chunked (1 row in cache)        45        48        52
+    chunked (initial creation, all in cache)    33        43        57
+
+    linux/gcc 4.7.3 (birdofprey):            uint8     float    double
+    plain array                                 16        20        21
+    chunked array (all in cache)                17        23        24
+    thread-safe chunked (all in cache)          19        24        25
+    thread-safe chunked (1 slice in cache)      20        29        34
+    thread-safe chunked (1 row in cache)        24        33        39
+    chunked (initial creation, all in cache)    22        34        48
+
+    OS X 10.7:                               uint8     float    double
+    plain array                                 11        22        24
+    chunked array (all in cache)                --        --        --
+    thread-safe chunked (all in cache)          20        25        26
+    thread-safe chunked (1 slice in cache)      23        37        46
+    thread-safe chunked (1 row in cache)        32        50        56
+    chunked (initial creation, all in cache)    34        56        77
+    (These numbers refer to nested loop iteration. Scan-order iteration
+     is unfortunately 3.5 times slower on the Mac. On the other hand,
+     two-level indexing as faster on a Mac than on Linux and Windows --
+     the speed penalty is only a factor of 2 rather than 3.)
+
+    **********************
+    image size: 400^3, chunk size: 127^3, i.e. chunk count: 4^3
+    times in msec, excluding time to store file on disk
+
+    win64/vs2012 (koethe-laptop):            uint8     float    double
+    plain array                                130       130       130
+    chunked array (all in cache)               190       190       200
+    thread-safe chunked (all in cache)         190       200       210
+    thread-safe chunked (1 slice in cache)     210       235       280
+    thread-safe chunked (1 row in cache)       240       270       300
+    chunked (initial creation, all in cache)   230       300       400
+
+    linux/gcc 4.7.3 (birdofprey):            uint8     float    double
+    plain array                                130       162       165
+    chunked array (all in cache)               131       180       184
+    thread-safe chunked (all in cache)         135       183       188
+    thread-safe chunked (1 slice in cache)     146       218       258
+    thread-safe chunked (1 row in cache)       154       229       270
+    chunked (initial creation, all in cache)   173       269       372
+
+    ***********************
+    Compression:
+    * I tried ZLIB, LZO, SNAPPY, LZ4, LZFX and FASTLZ (with compression levels 1 -- faster
+      and level 2 -- higher compression). There are also QuickLZ and LZMAT which claim
+      to be fast, but they are under a GPL license.
+    * ZLIB compresses best, but is quite slow even at compression level 1
+      (times are in ms and include compression and decompression).
+                 byte   float   double
+        ZLIB      121    3100     5800
+        ZLIB1      79    1110     1190
+        LZO        43     104      280
+        SNAPPY     46      71      305
+        LZ4        42      70      283
+        LZFX       76     278      330
+        FASTLZ1    52     280      309
+        FASTLZ1    53     286      339
+    * The fast compression algorithms are unable to compress the float array
+      and achieve ~50% for the double array, whereas ZLIB achieves 32% and 16%
+      respectively (at the fastest compression level 1, it is still 33% and 17%
+      respectively). LZFX cannot even compress the byte data (probably a bug?).
+      Average compression ratios for the byte array are
+        ZLIB:    2.3%
+        ZLIB1:   4.6%
+        LZO:     5.6%
+        SNAPPY:  9.8%
+        LZ4:     9.7%
+        FASTLZ1: 7.6%
+        FASTLZ2: 7.9%
+    * LZO is under GPL (but there is a Java implementation under Apache license at
+      http://svn.apache.org/repos/asf/hadoop/common/tags/release-0.19.2/src/core/org/apache/hadoop/io/compress/lzo/)
+      The others are BSD and MIT (FASTLZ).
+    * Snappy doesn't support Windows natively, but porting is simple (see my github repo)
+    * The source code for LZO, LZ4, LZFX, and FASTLZ can simply be copied to VIGRA,
+      but LZO's GPL license is unsuitable.
+    * HDF5 compression is already sufficient at level 1 (4-15%,
+      higher levels don't lead to big gains) and only a factor 3-10 slower
+      than without compression.
+*/
+
+#ifndef VIGRA_MULTI_ARRAY_CHUNKED_HXX
+#define VIGRA_MULTI_ARRAY_CHUNKED_HXX
+
+#include <queue>
+#include <string>
+
+#include "multi_fwd.hxx"
+#include "multi_handle.hxx"
+#include "multi_array.hxx"
+#include "memory.hxx"
+#include "metaprogramming.hxx"
+#include "threading.hxx"
+#include "compression.hxx"
+
+// // FIXME: why is this needed when compiling the Python bindng,
+// //        but not when compiling test_multiarray_chunked?
+// #if defined(__GNUC__)
+// #  define memory_order_release memory_order_seq_cst
+// #  define memory_order_acquire memory_order_seq_cst
+// #endif
+
+#ifdef _WIN32
+# include "windows.h"
+#else
+# include <fcntl.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <sys/stat.h>
+# include <sys/mman.h>
+# include <cstdio>
+#endif
+
+// Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined.
+#ifdef VIGRA_CHECK_BOUNDS
+#define VIGRA_ASSERT_INSIDE(diff) \
+  vigra_precondition(this->isInside(diff), "Index out of bounds")
+#else
+#define VIGRA_ASSERT_INSIDE(diff)
+#endif
+
+namespace vigra {
+
+#ifdef __APPLE__
+    #define VIGRA_NO_SPARSE_FILE
+#endif
+
+#ifdef _WIN32
+
+inline
+void winErrorToException(std::string message = "")
+{
+    LPVOID lpMsgBuf;
+    DWORD dw = GetLastError();
+
+    FormatMessage(
+        FORMAT_MESSAGE_ALLOCATE_BUFFER |
+        FORMAT_MESSAGE_FROM_SYSTEM |
+        FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL,
+        dw,
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+        (LPTSTR) &lpMsgBuf,
+        0, NULL );
+
+    message += (char*)lpMsgBuf;
+    LocalFree(lpMsgBuf);
+
+    throw std::runtime_error(message);
+}
+
+inline
+std::string winTempFileName(std::string path = "")
+{
+    if(path == "")
+    {
+        TCHAR default_path[MAX_PATH];
+        if(!GetTempPath(MAX_PATH, default_path))
+            winErrorToException("winTempFileName(): ");
+        path = default_path;
+    }
+
+    TCHAR name[MAX_PATH];
+    if(!GetTempFileName(path.c_str(), TEXT("vigra"), 0, name))
+        winErrorToException("winTempFileName(): ");
+
+    return std::string(name);
+}
+
+inline
+std::size_t winClusterSize()
+{
+    SYSTEM_INFO info;
+    ::GetSystemInfo(&info);
+    return info.dwAllocationGranularity;
+}
+
+#endif
+
+namespace {
+
+#ifdef _WIN32
+std::size_t mmap_alignment = winClusterSize();
+#else
+std::size_t mmap_alignment = sysconf(_SC_PAGE_SIZE);
+#endif
+
+} // anonymous namespace
+
+template <unsigned int N, class T>
+class IteratorChunkHandle;
+
+namespace detail {
+
+template <unsigned int N>
+struct ChunkIndexing
+{
+    template <class T, int M>
+    static void chunkIndex(TinyVector<T, M> const & p,
+                           TinyVector<T, M> const & bits,
+                           TinyVector<T, M> & index)
+    {
+        typedef std::size_t UI;
+        ChunkIndexing<N-1>::chunkIndex(p, bits, index);
+        index[N-1] = (UI)p[N-1] >> bits[N-1];
+    }
+
+    template <class T, int M>
+    static std::size_t chunkOffset(TinyVector<T, M> const & p,
+                                   TinyVector<T, M> const & bits,
+                                   TinyVector<T, M> const & strides)
+    {
+        typedef std::size_t UI;
+        return ChunkIndexing<N-1>::chunkOffset(p, bits, strides) +
+               ((UI)p[N-1] >> bits[N-1]) * strides[N-1];
+    }
+
+    template <class T, int M>
+    static std::size_t offsetInChunk(TinyVector<T, M> const & p,
+                                     TinyVector<T, M> const & mask,
+                                     TinyVector<T, M> const & strides)
+    {
+        typedef std::size_t UI;
+        return ChunkIndexing<N-1>::offsetInChunk(p, mask, strides) +
+               ((UI)p[N-1] & (UI)mask[N-1]) * strides[N-1];
+    }
+};
+
+template <>
+struct ChunkIndexing<1>
+{
+    template <class T, int M>
+    static void chunkIndex(TinyVector<T, M> const & p,
+                           TinyVector<T, M> const & bits,
+                           TinyVector<T, M> & index)
+    {
+        typedef std::size_t UI;
+        index[0] = (UI)p[0] >> bits[0];
+    }
+
+    template <class T, int M>
+    static std::size_t chunkOffset(TinyVector<T, M> const & p,
+                                   TinyVector<T, M> const & bits,
+                                   TinyVector<T, M> const & strides)
+    {
+        typedef std::size_t UI;
+        return ((UI)p[0] >> bits[0]) * strides[0];
+    }
+
+    template <class T, int M>
+    static std::size_t offsetInChunk(TinyVector<T, M> const & p,
+                                     TinyVector<T, M> const & mask,
+                                     TinyVector<T, M> const & strides)
+    {
+        typedef std::size_t UI;
+        return ((UI)p[0] & (UI)mask[0]) * strides[0];
+    }
+};
+
+template <class T, int M>
+inline TinyVector<T, M>
+computeChunkArrayShape(TinyVector<T, M> shape,
+                       TinyVector<T, M> const & bits,
+                       TinyVector<T, M> const & mask)
+{
+    for(int k=0; k<M; ++k)
+        shape[k] = (shape[k] + mask[k]) >> bits[k];
+    return shape;
+}
+
+template <class T, int M>
+inline T
+defaultCacheSize(TinyVector<T, M> const & shape)
+{
+    T res = max(shape);
+    for(int k=0; k<M-1; ++k)
+        for(int j=k+1; j<M; ++j)
+            res = std::max(res, shape[k]*shape[j]);
+    return res + 1;
+}
+
+} // namespace detail
+
+template <unsigned int N, class T>
+class ChunkBase
+{
+  public:
+    typedef typename MultiArrayShape<N>::type shape_type;
+    typedef T value_type;
+    typedef T* pointer;
+
+    ChunkBase()
+    : strides_()
+    , pointer_()
+    {}
+
+    ChunkBase(shape_type const & strides, pointer p = 0)
+    : strides_(strides)
+    , pointer_(p)
+    {}
+
+    typename MultiArrayShape<N>::type strides_;
+    T * pointer_;
+};
+
+template <unsigned int N, class T>
+class SharedChunkHandle
+{
+  public:
+    typedef typename MultiArrayShape<N>::type shape_type;
+
+    static const long chunk_asleep = -2;
+    static const long chunk_uninitialized = -3;
+    static const long chunk_locked = -4;
+    static const long chunk_failed = -5;
+
+    SharedChunkHandle()
+    : pointer_(0)
+    , chunk_state_()
+    {
+        chunk_state_ = chunk_uninitialized;
+    }
+
+    SharedChunkHandle(SharedChunkHandle const & rhs)
+    : pointer_(rhs.pointer_)
+    , chunk_state_()
+    {
+        chunk_state_ = chunk_uninitialized;
+    }
+
+    shape_type const & strides() const
+    {
+        return pointer_->strides_;
+    }
+
+    ChunkBase<N, T> * pointer_;
+    mutable threading::atomic_long chunk_state_;
+
+  private:
+    SharedChunkHandle & operator=(SharedChunkHandle const & rhs);
+};
+
+template <unsigned int N, class T>
+class ChunkedArrayBase
+{
+  public:
+    enum ActualDimension{ actual_dimension = (N == 0) ? 1 : N };
+    typedef typename MultiArrayShape<N>::type  shape_type;
+    typedef T value_type;
+    typedef value_type * pointer;
+    typedef value_type & reference;
+    typedef ChunkBase<N, T> Chunk;
+
+    ChunkedArrayBase()
+    : shape_()
+    , chunk_shape_()
+    {}
+
+    ChunkedArrayBase(shape_type const & shape, shape_type const & chunk_shape)
+    : shape_(shape)
+    , chunk_shape_(prod(chunk_shape) > 0 ? chunk_shape : detail::ChunkShape<N, T>::defaultShape())
+    {}
+
+    virtual ~ChunkedArrayBase()
+    {}
+
+    virtual void unrefChunk(IteratorChunkHandle<N, T> * h) const = 0;
+
+    virtual pointer chunkForIterator(shape_type const & point,
+                                     shape_type & strides, shape_type & upper_bound,
+                                     IteratorChunkHandle<N, T> * h) = 0;
+
+    virtual pointer chunkForIterator(shape_type const & point,
+                                     shape_type & strides, shape_type & upper_bound,
+                                     IteratorChunkHandle<N, T> * h) const = 0;
+
+    virtual std::string backend() const = 0;
+
+    virtual shape_type chunkArrayShape() const = 0;
+
+    virtual bool isReadOnly() const
+    {
+        return false;
+    }
+
+    MultiArrayIndex size() const
+    {
+        return prod(shape_);
+    }
+
+    shape_type const & shape() const
+    {
+        return shape_;
+    }
+
+    MultiArrayIndex shape(MultiArrayIndex d) const
+    {
+        return shape_[d];
+    }
+
+    shape_type const & chunkShape() const
+    {
+        return chunk_shape_;
+    }
+
+    MultiArrayIndex chunkShape(MultiArrayIndex d) const
+    {
+        return chunk_shape_[d];
+    }
+
+    bool isInside(shape_type const & p) const
+    {
+        for(int d=0; d<N; ++d)
+            if(p[d] < 0 || p[d] >= shape_[d])
+                return false;
+        return true;
+    }
+
+    shape_type shape_, chunk_shape_;
+};
+
+template <unsigned int N, class T>
+class ChunkedArray;
+
+struct ChunkUnrefProxyBase
+{
+    virtual ~ChunkUnrefProxyBase() {}
+};
+
+template <unsigned int N, class T_MaybeConst>
+class MultiArrayView<N, T_MaybeConst, ChunkedArrayTag>
+: public ChunkedArrayBase<N, typename UnqualifiedType<T_MaybeConst>::type>
+{
+  public:
+    enum ActualDimension { actual_dimension = (N==0) ? 1 : N };
+    typedef typename UnqualifiedType<T_MaybeConst>::type     T;
+    typedef T value_type;   // FIXME: allow Multiband<T> ???
+    typedef T_MaybeConst & reference;
+    typedef const value_type &const_reference;
+    typedef T_MaybeConst * pointer;
+    typedef const value_type *const_pointer;
+    typedef typename MultiArrayShape<actual_dimension>::type difference_type;
+    typedef difference_type key_type;
+    typedef difference_type size_type;
+    typedef difference_type shape_type;
+    typedef MultiArrayIndex difference_type_1;
+    typedef ChunkIterator<actual_dimension, T_MaybeConst>         chunk_iterator;
+    typedef ChunkIterator<actual_dimension, T const>   chunk_const_iterator;
+    typedef StridedScanOrderIterator<actual_dimension, ChunkedMemory<T_MaybeConst>, T_MaybeConst&, T_MaybeConst*> iterator;
+    typedef StridedScanOrderIterator<actual_dimension, ChunkedMemory<T const>, T const &, T const *> const_iterator;
+    typedef MultiArrayView<N, T_MaybeConst, ChunkedArrayTag> view_type;
+    typedef MultiArrayView<N, T const, ChunkedArrayTag> const_view_type;
+    typedef ChunkedArrayTag StrideTag;
+    typedef ChunkBase<N, T> Chunk;
+
+    typedef MultiArray<N, Chunk> ChunkHolder;
+
+    struct UnrefProxy
+    : public ChunkUnrefProxyBase
+    {
+        UnrefProxy(int size, ChunkedArray<N, T> * array)
+        : chunks_(size)
+        , array_(array)
+        {}
+
+        ~UnrefProxy()
+        {
+            if(array_)
+                array_->unrefChunks(chunks_);
+        }
+
+        ArrayVector<SharedChunkHandle<N, T> *> chunks_;
+        ChunkedArray<N, T> * array_;
+    };
+
+    virtual shape_type chunkArrayShape() const
+    {
+        return chunks_.shape();
+    }
+
+    shape_type chunkStart(shape_type const & global_start) const
+    {
+        shape_type chunk_start(SkipInitialization);
+        detail::ChunkIndexing<N>::chunkIndex(global_start, bits_, chunk_start);
+        return chunk_start;
+    }
+
+    shape_type chunkStop(shape_type global_stop) const
+    {
+        global_stop -= shape_type(1);
+        shape_type chunk_stop(SkipInitialization);
+        detail::ChunkIndexing<N>::chunkIndex(global_stop, bits_, chunk_stop);
+        chunk_stop += shape_type(1);
+        return chunk_stop;
+    }
+
+    virtual void unrefChunk(IteratorChunkHandle<N, T> *) const {}
+
+    virtual T* chunkForIterator(shape_type const & point,
+                                shape_type & strides, shape_type & upper_bound,
+                                IteratorChunkHandle<N, T> * h)
+    {
+        return const_cast<MultiArrayView const *>(this)->chunkForIterator(point, strides, upper_bound, h);
+    }
+
+    virtual T* chunkForIterator(shape_type const & point,
+                                shape_type & strides, shape_type & upper_bound,
+                                IteratorChunkHandle<N, T> * h) const
+    {
+        shape_type global_point = point + h->offset_;
+
+        if(!this->isInside(global_point))
+        {
+            upper_bound = point + this->chunk_shape_;
+            return 0;
+        }
+
+        global_point += offset_;
+        shape_type coffset = offset_ + h->offset_;
+
+        shape_type chunkIndex = chunkStart(global_point);
+        Chunk const * chunk = &chunks_[chunkIndex];
+        strides = chunk->strides_;
+        upper_bound = (chunkIndex + shape_type(1)) * this->chunk_shape_ - coffset;
+        std::size_t offset = detail::ChunkIndexing<N>::offsetInChunk(global_point, mask_, strides);
+        return const_cast<T*>(chunk->pointer_ + offset);
+    }
+
+    virtual std::string backend() const
+    {
+        return "MultiArrayView<ChunkedArrayTag>";
+    }
+
+    MultiArrayView()
+    : ChunkedArrayBase<N, T>()
+    {}
+
+    MultiArrayView(shape_type const & shape, shape_type const & chunk_shape)
+    : ChunkedArrayBase<N, T>(shape, chunk_shape)
+    {}
+
+    MultiArrayView & operator=(MultiArrayView const & rhs)
+    {
+        if(this != &rhs)
+        {
+            if(!hasData())
+            {
+                ChunkedArrayBase<N, T>::operator=(rhs);
+                chunks_ = rhs.chunks_;
+                offset_ = rhs.offset_;
+                bits_ = rhs.bits_;
+                mask_ = rhs.mask_;
+                unref_ = rhs.unref_;
+            }
+            else
+            {
+                vigra_precondition(this->shape() == rhs.shape(),
+                                   "MultiArrayView::operator=(): shape mismatch.");
+                iterator i = begin(), ie = end();
+                const_iterator j = rhs.begin();
+                for(; i != ie; ++i, ++j)
+                    *i = *j;
+            }
+        }
+        return *this;
+    }
+
+    #define VIGRA_CHUNKED_ARRAY_VIEW_ASSIGN(op) \
+    template<class U, class C1> \
+    MultiArrayView & operator op(MultiArrayView<N, U, C1> const & rhs) \
+    { \
+        vigra_precondition(this->shape() == rhs.shape(), \
+                           "MultiArrayView::operator" #op "(): shape mismatch."); \
+        iterator i = begin(), ie = end(); \
+        typename MultiArrayView<N, U, C1>::const_iterator j = rhs.begin(); \
+        for(; i != ie; ++i, ++j) \
+            *i op detail::RequiresExplicitCast<value_type>::cast(*j); \
+        return *this; \
+    } \
+     \
+    MultiArrayView & operator op(value_type const & v) \
+    { \
+        if(hasData()) \
+        { \
+            iterator i = begin(), ie = end(); \
+            for(; i != ie; ++i) \
+                *i op v; \
+        } \
+        return *this; \
+    }
+
+    VIGRA_CHUNKED_ARRAY_VIEW_ASSIGN(=)
+    VIGRA_CHUNKED_ARRAY_VIEW_ASSIGN(+=)
+    VIGRA_CHUNKED_ARRAY_VIEW_ASSIGN(-=)
+    VIGRA_CHUNKED_ARRAY_VIEW_ASSIGN(*=)
+    VIGRA_CHUNKED_ARRAY_VIEW_ASSIGN(/=)
+
+    #undef VIGRA_CHUNKED_ARRAY_VIEW_ASSIGN
+
+    // template<class Expression>
+    // MultiArrayView & operator=(multi_math::MultiMathOperand<Expression> const & rhs)
+    // {
+        // multi_math::math_detail::assign(*this, rhs);
+        // return *this;
+    // }
+
+        // /** Add-assignment of an array expression. Fails with
+            // <tt>PreconditionViolation</tt> exception when the shapes do not match.
+         // */
+    // template<class Expression>
+    // MultiArrayView & operator+=(multi_math::MultiMathOperand<Expression> const & rhs)
+    // {
+        // multi_math::math_detail::plusAssign(*this, rhs);
+        // return *this;
+    // }
+
+        // /** Subtract-assignment of an array expression. Fails with
+            // <tt>PreconditionViolation</tt> exception when the shapes do not match.
+         // */
+    // template<class Expression>
+    // MultiArrayView & operator-=(multi_math::MultiMathOperand<Expression> const & rhs)
+    // {
+        // multi_math::math_detail::minusAssign(*this, rhs);
+        // return *this;
+    // }
+
+        // /** Multiply-assignment of an array expression. Fails with
+            // <tt>PreconditionViolation</tt> exception when the shapes do not match.
+         // */
+    // template<class Expression>
+    // MultiArrayView & operator*=(multi_math::MultiMathOperand<Expression> const & rhs)
+    // {
+        // multi_math::math_detail::multiplyAssign(*this, rhs);
+        // return *this;
+    // }
+
+        // /** Divide-assignment of an array expression. Fails with
+            // <tt>PreconditionViolation</tt> exception when the shapes do not match.
+         // */
+    // template<class Expression>
+    // MultiArrayView & operator/=(multi_math::MultiMathOperand<Expression> const & rhs)
+    // {
+        // multi_math::math_detail::divideAssign(*this, rhs);
+        // return *this;
+    // }
+
+    reference operator[](shape_type point)
+    {
+        VIGRA_ASSERT_INSIDE(point);
+        point += offset_;
+        Chunk * chunk = chunks_.data() +
+                        detail::ChunkIndexing<N>::chunkOffset(point, bits_, chunks_.stride());
+        return *(chunk->pointer_ +
+                 detail::ChunkIndexing<N>::offsetInChunk(point, mask_, chunk->strides_));
+    }
+
+    const_reference operator[](shape_type const & point) const
+    {
+        return const_cast<MultiArrayView *>(this)->operator[](point);
+    }
+
+    template <int M>
+    MultiArrayView <N-M, T, ChunkedArrayTag>
+    operator[](const TinyVector<MultiArrayIndex, M> &d) const
+    {
+        return bindInner(d);
+    }
+
+    reference operator[](difference_type_1 d)
+    {
+        return operator[](scanOrderIndexToCoordinate(d));
+    }
+
+    const_reference operator[](difference_type_1 d) const
+    {
+        return operator[](scanOrderIndexToCoordinate(d));
+    }
+
+    difference_type scanOrderIndexToCoordinate(difference_type_1 d) const
+    {
+        difference_type coord(SkipInitialization);
+        detail::ScanOrderToCoordinate<actual_dimension>::exec(d, this->shape_, coord);
+        return coord;
+    }
+
+        /** convert coordinate to scan-order index.
+         */
+    difference_type_1 coordinateToScanOrderIndex(const difference_type &d) const
+    {
+        return detail::CoordinateToScanOrder<actual_dimension>::exec(this->shape_, d);
+    }
+
+        // /** 1D array access. Use only if N == 1.
+         // */
+    // reference operator() (difference_type_1 x)
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x));
+        // return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x)];
+    // }
+
+        // /** 2D array access. Use only if N == 2.
+         // */
+    // reference operator() (difference_type_1 x, difference_type_1 y)
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x, y));
+        // return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x, y)];
+    // }
+
+        // /** 3D array access. Use only if N == 3.
+         // */
+    // reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z)
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x, y, z));
+        // return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
+    // }
+
+        // /** 4D array access. Use only if N == 4.
+         // */
+    // reference operator() (difference_type_1 x, difference_type_1 y,
+                          // difference_type_1 z, difference_type_1 u)
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x, y, z, u));
+        // return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u];
+    // }
+
+        // /** 5D array access. Use only if N == 5.
+         // */
+    // reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z,
+                          // difference_type_1 u, difference_type_1 v)
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x, y,z, u,v));
+        // return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v];
+    // }
+
+        // /** 1D const array access. Use only if N == 1.
+         // */
+    // const_reference operator() (difference_type_1 x) const
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x));
+        // return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x)];
+    // }
+
+        // /** 2D const array access. Use only if N == 2.
+         // */
+    // const_reference operator() (difference_type_1 x, difference_type_1 y) const
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x, y));
+        // return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x, y)];
+    // }
+
+        // /** 3D const array access. Use only if N == 3.
+         // */
+    // const_reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z) const
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x,y,z));
+        // return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
+    // }
+
+        // /** 4D const array access. Use only if N == 4.
+         // */
+    // const_reference operator() (difference_type_1 x, difference_type_1 y,
+                                // difference_type_1 z, difference_type_1 u) const
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x,y,z,u));
+        // return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u];
+    // }
+
+        // /** 5D const array access. Use only if N == 5.
+         // */
+    // const_reference operator() (difference_type_1 x, difference_type_1 y, difference_type_1 z,
+                                // difference_type_1 u, difference_type_1 v) const
+    // {
+        // VIGRA_ASSERT_INSIDE(difference_type(x,y,z,u,v));
+        // return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v];
+    // }
+
+    template <class U>
+    MultiArrayView & init(const U & init)
+    {
+        return operator=(init);
+    }
+
+    template <class U, class CN>
+    void copy(const MultiArrayView <N, U, CN>& rhs)
+    {
+        operator=(rhs);
+    }
+
+    template <class T2, class C2>
+    void swapData(MultiArrayView <N, T2, C2> rhs)
+    {
+        if(this == &rhs)
+            return;
+        vigra_precondition(this->shape() == rhs.shape(),
+                           "MultiArrayView::swapData(): shape mismatch.");
+        iterator i = begin(), ie = end();
+        typename MultiArrayView<N, T2, C2>::iterator j = rhs.begin();
+        for(; i != ie; ++i, ++j)
+            std::swap(*i, *j);
+    }
+
+    bool isUnstrided(unsigned int dimension = N-1) const
+    {
+        if(chunks_.size() > 1)
+            return false;
+        difference_type s = vigra::detail::defaultStride<actual_dimension>(this->shape());
+        for(unsigned int k = 0; k <= dimension; ++k)
+            if(chunks_.data()->strides_[k] != s[k])
+                return false;
+        return true;
+    }
+
+    MultiArrayView<N-1, value_type, ChunkedArrayTag>
+    bindAt(MultiArrayIndex m, MultiArrayIndex d) const
+    {
+        MultiArrayView<N-1, value_type, ChunkedArrayTag> res(this->shape_.dropIndex(m), this->chunk_shape_.dropIndex(m));
+        res.offset_ = offset_.dropIndex(m);
+        res.bits_   = bits_.dropIndex(m);
+        res.mask_   = mask_.dropIndex(m);
+        res.chunks_.reshape(chunks_.shape().dropIndex(m));
+        res.unref_ = unref_;
+
+        typedef std::size_t UI;
+        UI start = offset_[m] + d;
+        UI chunk_start = start >> bits_[m];
+        UI startInChunk = start - chunk_start * this->chunk_shape_[m];
+
+        MultiArrayView<N-1, Chunk> view(chunks_.bindAt(m, chunk_start));
+        MultiCoordinateIterator<N-1> i(view.shape()),
+                                     end(i.getEndIterator());
+        for(; i != end; ++i)
+        {
+            res.chunks_[*i].pointer_ = view[*i].pointer_ + startInChunk*view[*i].strides_[m];
+            res.chunks_[*i].strides_ = view[*i].strides_.dropIndex(m);
+        }
+
+        return res;
+    }
+
+    template <unsigned int M>
+    MultiArrayView <N-1, value_type, ChunkedArrayTag>
+    bind (difference_type_1 d) const
+    {
+        return bindAt(M, d);
+    }
+
+    MultiArrayView <N-1, value_type, ChunkedArrayTag>
+    bindOuter (difference_type_1 d) const
+    {
+        return bindAt(N-1, d);
+    }
+
+    template <int M, class Index>
+    MultiArrayView <N-M, value_type, ChunkedArrayTag>
+    bindOuter(const TinyVector <Index, M> &d) const
+    {
+        return bindAt(N-1, d[M-1]).bindOuter(d.dropIndex(M-1));
+    }
+
+    template <class Index>
+    MultiArrayView <N-1, value_type, ChunkedArrayTag>
+    bindOuter(const TinyVector <Index, 1> &d) const
+    {
+        return bindAt(N-1, d[0]);
+    }
+
+    MultiArrayView <N-1, value_type, ChunkedArrayTag>
+    bindInner (difference_type_1 d) const
+    {
+        return bindAt(0, d);
+    }
+
+    template <int M, class Index>
+    MultiArrayView <N-M, value_type, ChunkedArrayTag>
+    bindInner(const TinyVector <Index, M> &d) const
+    {
+        return bindAt(0, d[0]).bindInner(d.dropIndex(0));
+    }
+
+    template <class Index>
+    MultiArrayView <N-1, value_type, ChunkedArrayTag>
+    bindInner(const TinyVector <Index, 1> &d) const
+    {
+        return bindAt(0, d[0]);
+    }
+
+    // MultiArrayView <N, typename ExpandElementResult<T>::type, StridedArrayTag>
+    // bindElementChannel(difference_type_1 i) const
+    // {
+        // vigra_precondition(0 <= i && i < ExpandElementResult<T>::size,
+              // "MultiArrayView::bindElementChannel(i): 'i' out of range.");
+        // return expandElements(0).bindInner(i);
+    // }
+
+    // MultiArrayView <N+1, typename ExpandElementResult<T>::type, StridedArrayTag>
+    // expandElements(difference_type_1 d) const;
+
+    // MultiArrayView <N+1, T, StrideTag>
+    // insertSingletonDimension (difference_type_1 i) const;
+
+    // MultiArrayView<N, Multiband<value_type>, StrideTag> multiband() const
+    // {
+        // return MultiArrayView<N, Multiband<value_type>, StrideTag>(*this);
+    // }
+
+    // MultiArrayView<1, T, StridedArrayTag> diagonal() const
+    // {
+        // return MultiArrayView<1, T, StridedArrayTag>(Shape1(vigra::min(m_shape)),
+                                                     // Shape1(vigra::sum(m_stride)), m_ptr);
+    // }
+
+    inline void
+    checkSubarrayBounds(shape_type const & start, shape_type const & stop,
+                        std::string message) const
+    {
+        message += ": subarray out of bounds.";
+        vigra_precondition(allLessEqual(shape_type(), start) &&
+                           allLess(start, stop) &&
+                           allLessEqual(stop, this->shape_),
+                           message);
+    }
+
+    MultiArrayView<N, value_type, ChunkedArrayTag>
+    subarray(shape_type start, shape_type stop)
+    {
+        checkSubarrayBounds(start, stop, "MultiArrayView<N-1, T, ChunkedArrayTag>::subarray()");
+        start += offset_;
+        stop  += offset_;
+        shape_type chunk_start(chunkStart(start));
+
+        MultiArrayView<N, value_type, ChunkedArrayTag> view(stop-start, this->chunk_shape_);
+        view.chunks_ = chunks_.subarray(chunk_start, chunkStop(stop));
+        view.offset_ = start - chunk_start * this->chunk_shape_;
+        view.bits_   = bits_;
+        view.mask_   = mask_;
+        view.unref_ = unref_;
+        return view;
+    }
+
+        // /** apply an additional striding to the image, thereby reducing
+            // the shape of the array.
+            // for example, multiplying the stride of dimension one by three
+            // turns an appropriately laid out (interleaved) rgb image into
+            // a single band image.
+        // */
+    // MultiArrayView <N, T, StridedArrayTag>
+    // stridearray (const difference_type &s) const
+    // {
+        // difference_type shape = m_shape;
+        // for (unsigned int i = 0; i < actual_dimension; ++i)
+            // shape [i] /= s [i];
+        // return MultiArrayView <N, T, StridedArrayTag>(shape, m_stride * s, m_ptr);
+    // }
+
+    MultiArrayView <N, value_type, ChunkedArrayTag>
+    transpose () const
+    {
+        return transpose(difference_type::linearSequence(N-1, -1));
+    }
+
+    MultiArrayView <N, value_type, ChunkedArrayTag>
+    transpose(const difference_type &permutation) const
+    {
+        MultiArrayView<N, value_type, ChunkedArrayTag>
+            view(vigra::transpose(this->shape_, permutation), vigra::transpose(this->chunk_shape_, permutation));
+        view.chunks_        = chunks_.transpose(permutation); // also checks if permutation is valid
+        view.offset_        = vigra::transpose(offset_, permutation);
+        view.bits_          = vigra::transpose(bits_, permutation);
+        view.mask_          = vigra::transpose(mask_, permutation);
+        view.unref_         = unref_;
+        typename MultiArray<N, Chunk>::iterator i = view.chunks_.begin(),
+                                                iend = view.chunks_.end();
+        for(; i != iend; ++i)
+            i->strides_ = vigra::transpose(i->strides_, permutation);
+        return view;
+    }
+
+    // MultiArrayView <N, T, StridedArrayTag>
+    // permuteDimensions (const difference_type &s) const;
+
+        // /** Permute the dimensions of the array so that the strides are in ascending order.
+            // Determines the appropriate permutation and then calls permuteDimensions().
+        // */
+    // MultiArrayView <N, T, StridedArrayTag>
+    // permuteStridesAscending() const;
+
+        // /** Permute the dimensions of the array so that the strides are in descending order.
+            // Determines the appropriate permutation and then calls permuteDimensions().
+        // */
+    // MultiArrayView <N, T, StridedArrayTag>
+    // permuteStridesDescending() const;
+
+        // /** Compute the ordering of the strides in this array.
+            // The result is describes the current permutation of the axes relative
+            // to the standard ascending stride order.
+        // */
+    // difference_type strideOrdering() const
+    // {
+        // return strideOrdering(m_stride);
+    // }
+
+        // /** Compute the ordering of the given strides.
+            // The result is describes the current permutation of the axes relative
+            // to the standard ascending stride order.
+        // */
+    // static difference_type strideOrdering(difference_type strides);
+
+    template <class U, class C1>
+    bool operator==(MultiArrayView<N, U, C1> const & rhs) const
+    {
+        if(this->shape() != rhs.shape())
+            return false;
+        const_iterator i = begin(), ie = end();
+        typename MultiArrayView<N, U, C1>::const_iterator j = rhs.begin();
+        for(; i != ie; ++i, ++j)
+            if(*i != *j)
+                return false;
+        return true;
+    }
+
+    template <class U, class C1>
+    bool operator!=(MultiArrayView<N, U, C1> const & rhs) const
+    {
+        return !operator==(rhs);
+    }
+
+    // bool all() const
+    // {
+        // bool res = true;
+        // detail::reduceOverMultiArray(traverser_begin(), shape(),
+                                     // res,
+                                     // detail::AllTrueReduceFunctor(),
+                                     // MetaInt<actual_dimension-1>());
+        // return res;
+    // }
+
+    // bool any() const
+    // {
+        // bool res = false;
+        // detail::reduceOverMultiArray(traverser_begin(), shape(),
+                                     // res,
+                                     // detail::AnyTrueReduceFunctor(),
+                                     // MetaInt<actual_dimension-1>());
+        // return res;
+    // }
+
+    // void minmax(T * minimum, T * maximum) const
+    // {
+        // std::pair<T, T> res(NumericTraits<T>::max(), NumericTraits<T>::min());
+        // detail::reduceOverMultiArray(traverser_begin(), shape(),
+                                     // res,
+                                     // detail::MinmaxReduceFunctor(),
+                                     // MetaInt<actual_dimension-1>());
+        // *minimum = res.first;
+        // *maximum = res.second;
+    // }
+
+    // template <class U>
+    // void meanVariance(U * mean, U * variance) const
+    // {
+        // typedef typename NumericTraits<U>::RealPromote R;
+        // R zero = R();
+        // triple<double, R, R> res(0.0, zero, zero);
+        // detail::reduceOverMultiArray(traverser_begin(), shape(),
+                                     // res,
+                                     // detail::MeanVarianceReduceFunctor(),
+                                     // MetaInt<actual_dimension-1>());
+        // *mean     = res.second;
+        // *variance = res.third / res.first;
+    // }
+
+    // template <class U>
+    // U sum() const
+    // {
+        // U res = NumericTraits<U>::zero();
+        // detail::reduceOverMultiArray(traverser_begin(), shape(),
+                                     // res,
+                                     // detail::SumReduceFunctor(),
+                                     // MetaInt<actual_dimension-1>());
+        // return res;
+    // }
+
+    // template <class U, class S>
+    // void sum(MultiArrayView<N, U, S> sums) const
+    // {
+        // transformMultiArray(srcMultiArrayRange(*this),
+                            // destMultiArrayRange(sums),
+                            // FindSum<U>());
+    // }
+
+    // template <class U>
+    // U product() const
+    // {
+        // U res = NumericTraits<U>::one();
+        // detail::reduceOverMultiArray(traverser_begin(), shape(),
+                                     // res,
+                                     // detail::ProdReduceFunctor(),
+                                     // MetaInt<actual_dimension-1>());
+        // return res;
+    // }
+
+    // typename NormTraits<MultiArrayView>::SquaredNormType
+    // squaredNorm() const
+    // {
+        // typedef typename NormTraits<MultiArrayView>::SquaredNormType SquaredNormType;
+        // SquaredNormType res = NumericTraits<SquaredNormType>::zero();
+        // detail::reduceOverMultiArray(traverser_begin(), shape(),
+                                     // res,
+                                     // detail::SquaredL2NormReduceFunctor(),
+                                     // MetaInt<actual_dimension-1>());
+        // return res;
+    // }
+
+    // typename NormTraits<MultiArrayView>::NormType
+    // norm(int type = 2, bool useSquaredNorm = true) const;
+
+    bool hasData () const
+    {
+        return chunks_.hasData();
+    }
+
+    iterator begin()
+    {
+        return createCoupledIterator(*this);
+    }
+
+    iterator end()
+    {
+        return begin().getEndIterator();
+    }
+
+    const_iterator cbegin() const
+    {
+        return createCoupledIterator(const_cast<MultiArrayView const &>(*this));
+    }
+
+    const_iterator cend() const
+    {
+        return cbegin().getEndIterator();
+    }
+
+    const_iterator begin() const
+    {
+        return createCoupledIterator(*this);
+    }
+
+    const_iterator end() const
+    {
+        return begin().getEndIterator();
+    }
+
+    chunk_iterator chunk_begin(shape_type const & start, shape_type const & stop)
+    {
+        checkSubarrayBounds(start, stop, "MultiArrayView<N-1, T, ChunkedArrayTag>::chunk_begin()");
+        return chunk_iterator(this, start, stop, chunkStart(start), chunkStop(stop), this->chunk_shape_);
+    }
+
+    chunk_iterator chunk_end(shape_type const & start, shape_type const & stop)
+    {
+        return chunk_begin(start, stop).getEndIterator();
+    }
+
+    chunk_const_iterator chunk_begin(shape_type const & start, shape_type const & stop) const
+    {
+        checkSubarrayBounds(start, stop, "MultiArrayView<N-1, T, ChunkedArrayTag>::chunk_begin()");
+        return chunk_const_iterator(this, start, stop, chunkStart(start), chunkStop(stop), this->chunk_shape_);
+    }
+
+    chunk_const_iterator chunk_end(shape_type const & start, shape_type const & stop) const
+    {
+        return chunk_begin(start, stop).getEndIterator();
+    }
+
+    chunk_const_iterator chunk_cbegin(shape_type const & start, shape_type const & stop) const
+    {
+        checkSubarrayBounds(start, stop, "MultiArrayView<N-1, T, ChunkedArrayTag>::chunk_cbegin()");
+        return chunk_const_iterator(this, start, stop, chunkStart(start), chunkStop(stop), this->chunk_shape_);
+    }
+
+    chunk_const_iterator chunk_cend(shape_type const & start, shape_type const & stop) const
+    {
+        return chunk_cbegin(start, stop).getEndIterator();
+    }
+
+    view_type view ()
+    {
+        return *this;
+    }
+
+    MultiArray<N, Chunk> chunks_;
+    shape_type offset_, bits_, mask_;
+    VIGRA_SHARED_PTR<ChunkUnrefProxyBase> unref_;
+};
+
+template <unsigned int N, class T>
+typename MultiArrayView<N, T, ChunkedArrayTag>::iterator
+createCoupledIterator(MultiArrayView<N, T, ChunkedArrayTag> & m)
+{
+    typedef typename MultiArrayView<N, T, ChunkedArrayTag>::iterator    IteratorType;
+    typedef typename IteratorType::handle_type           P1;
+    typedef typename P1::base_type                       P0;
+
+    return IteratorType(P1(m,
+                        P0(m.shape())));
+}
+
+template <unsigned int N, class T>
+typename MultiArrayView<N, T, ChunkedArrayTag>::const_iterator
+createCoupledIterator(MultiArrayView<N, T, ChunkedArrayTag> const & m)
+{
+    typedef typename MultiArrayView<N, T, ChunkedArrayTag>::const_iterator    IteratorType;
+    typedef typename IteratorType::handle_type           P1;
+    typedef typename P1::base_type                       P0;
+
+    return IteratorType(P1(m,
+                        P0(m.shape())));
+}
+
+/** \addtogroup ChunkedArrayClasses Chunked arrays
+
+    Store big data (potentially larger than RAM) as a collection of rectangular blocks.
+*/
+//@{
+
+/** \brief Option object for \ref ChunkedArray construction.
+*/
+class ChunkedArrayOptions
+{
+  public:
+    /** \brief Initialize options with defaults.
+    */
+    ChunkedArrayOptions()
+    : fill_value(0.0)
+    , cache_max(-1)
+    , compression_method(DEFAULT_COMPRESSION)
+    {}
+
+    /** \brief Element value for read-only access of uninitialized chunks.
+
+        Default: 0
+    */
+    ChunkedArrayOptions & fillValue(double v)
+    {
+        fill_value = v;
+        return *this;
+    }
+
+    ChunkedArrayOptions fillValue(double v) const
+    {
+        return ChunkedArrayOptions(*this).fillValue(v);
+    }
+
+    /** \brief Maximum number of chunks in the cache.
+
+        Default: -1 ( = use a heuristic depending on array shape)
+    */
+    ChunkedArrayOptions & cacheMax(int v)
+    {
+        cache_max = v;
+        return *this;
+    }
+
+    ChunkedArrayOptions cacheMax(int v) const
+    {
+        return ChunkedArrayOptions(*this).cacheMax(v);
+    }
+
+    /** \brief Compress inactive chunks with the given method.
+
+        Default: DEFAULT_COMPRESSION (depends on backend)
+    */
+    ChunkedArrayOptions & compression(CompressionMethod v)
+    {
+        compression_method = v;
+        return *this;
+    }
+
+    ChunkedArrayOptions compression(CompressionMethod v) const
+    {
+        return ChunkedArrayOptions(*this).compression(v);
+    }
+
+    double fill_value;
+    int cache_max;
+    CompressionMethod compression_method;
+};
+
+/** \brief Interface and base class for chunked arrays.
+
+Very big data arrays (possibly bigger than the available RAM) can
+only be processed in smaller pieces. To support quick access to
+these pieces, it is advantegeous to store big arrays in chunks,
+i.e. as a collection of small rectagular subarrays. The class
+ChunkedArray encapsulates storage and handling of these chunks and
+provides various APIs to easily access the data.
+
+<b>\#include</b> \<vigra/multi_array_chunked.hxx\> <br/>
+Namespace: vigra
+
+ at tparam N the array dimension
+ at tparam T the type of the array elements
+
+(these are the same as in \ref MultiArrayView). The actual way of chunk storage is determined by the derived class the program uses:
+
+<ul>
+    <li>ChunkedArrayFull: Provides the chunked array API for a standard
+    \ref MultiArray (i.e. there is only one chunk for the entire array).
+
+    <li>ChunkedArrayLazy: All chunks reside in memory, but are only
+    allocated upon first access.
+
+    <li>ChunkedArrayCompressed: Like ChunkedArrayLazy, but temporarily
+    unused chunks are compressed in memory to save space.
+
+    <li>ChunkedArrayTmpFile: Chunks are stored in a memory-mapped file.
+    Temporarily unused chunks are written to the hard-drive and deleted from
+    memory.
+
+    <li>ChunkedArrayHDF5: Chunks are stored in a HDF5 dataset by means of
+    HDF5's native chunked storage capabilities. Temporarily unused chunks are
+    written to the hard-drive in compressed form and deleted from memory.
+</ul>
+You must use these derived classes to construct a chunked array because
+ChunkedArray itself is an abstract class.
+
+Chunks can be in one of the following states:
+<ul>
+    <li>uninitialized: Chunks are only initialized (i.e. allocated) upon the first
+    write access. If an uninitialized chunk is accessed in a read-only manner, the
+    system returns a pseudo-chunk whose elements have a user-provided fill value.
+
+    <li>asleep: The chunk is currently unused and has been compressed and/or
+    swapped out to the hard drive.
+
+    <li>inactive: The chunk is currently unused, but still resides in memory.
+
+    <li>active: The chunk resides in memory and is currently in use.
+
+    <li>locked: Chunks are briefly in this state during transitions
+    between the other states (e.g. while loading and/or decompression is
+    in progress).
+
+    <li>failed: An unexpected error occured, e.g. the system is out of memory
+    or a write to the hard drive failed.
+</ul>
+In-memory chunks (active and inactive) are placed in a cache. If a chunk
+transitions from the 'asleep' to the 'active' state, it is added to the cache,
+and an 'inactive' chunk is removed and sent 'asleep'. If there is no 'inactive'
+chunk in the cache, the cache size is temporarily increased. All state
+transitions are thread-safe.
+
+In order to optimize performance, the user should adjust the cache size (via
+\ref setCacheMaxSize() or \ref ChunkedArrayOptions) so that it can hold all
+chunks that are frequently needed (e.g. all chunks forming a row of the full
+array).
+
+Another performance critical parameter is the chunk shape. While the system
+uses sensible defaults (512<sup>2</sup> for 2D arrays, 64<sup>3</sup> for 3D,
+64x64x16x4 for 4D, and 64x64x16x4x4 for 5D), the shape may need to be adjusted
+via the array's constructor to match the access patterns of the algorithms to
+be used. For speed reasons, chunk shapes must be powers of 2.
+
+The data in the array can be accessed in several ways. The simplest is
+via calls to <tt>checkoutSubarray()</tt> and <tt>commitSubarray()</tt>: These
+functions copy an arbitrary subregion of a chunked array (possibly straddling
+many chunks) into a standard \ref MultiArrayView for processing, and write
+results back into the chunked array:
+\code
+    ChunkedArray<3, float> & chunked_array = ...;
+
+    Shape3 roi_start(1000, 500, 500);
+    MultiArray<3, float> work_array(Shape3(100, 100, 100));
+
+    // copy data from region (1000,500,500)...(1100,600,600)
+    chunked_array.checkoutSubarray(roi_start, work_array);
+
+    ... // work phase: process data in work_array as usual
+
+    // write results back into chunked_array
+    chunked_array.commitSubarray(roi_start, work_array);
+\endcode
+The required chunks in <tt>chunked_array</tt> will only be active while the
+checkout and commit calls are executing. During the work phase, other threads
+can use the chunked array's cache to checkout or commit different subregions.
+
+Alternatively, one can work directly on the chunk storage. This is most easily
+achieved by means of chunk iterators:
+\code
+    ChunkedArray<3, float> & chunked_array = ...;
+
+    // define the ROI to be processed
+    Shape3 roi_start(100, 200, 300), roi_end(1000, 2000, 600);
+
+    // get a pair of chunk iterators ( = iterators over chunks)
+    auto chunk = chunked_array.chunk_begin(roi_start, roi_end),
+         end   = chunked_array.chunk_end(roi_start, roi_end);
+
+    // iterate over the chunks in the ROI
+    for(; chunk != end; ++chunk)
+    {
+        // get a view to the current chunk's data
+        // Note: The view actually refers to the intersection of the
+        //       current chunk with the ROI. Thus, chunks which are
+        //       partially outside the ROI are appropriately trimmed.
+        MultiArrayView<3, float> chunk_view = *chunk;
+
+        ... // work phase: process data in chunk_view as usual
+    }
+\endcode
+No memory is duplicated in this approach, and only the current chunk needs
+to be active, so that a small chunk cache is sufficient. The iteration
+over chunks can be distributed over several threads that process the array
+data in parallel. The programmer must make sure that write operations to
+individual elements are synchronized between threads. This is usually
+achieved by ensuring that the threads are responsible for non-overlapping
+regions of the output array.
+
+An even simpler method is direct element access via indexing. However, the
+chunked array has no control over the access order in this case, so it must
+potentially activate the present chunk upon each access. This is rather
+expensive and should only be used for debugging:
+\code
+    ChunkedArray<3, float> & chunked_array = ...;
+
+    Shape3 index(100, 200, 300);
+    // access data at coordinate 'index'
+    chunked_array.setItem(index, chunked_array.getItem(index) + 2.0);
+\endcode
+
+Two additional APIs provide access in a way compatible with an ordinary
+\ref MultiArrayView. These APIs should be used in functions that are
+supposed to work unchanged on both ordinary and chunked arrays. The first
+possibility is the chunked scan-order iterator:
+\code
+    ChunkedArray<3, float> & chunked_array = ...;
+
+    // get a pair of scan-order iterators ( = iterators over elements)
+    auto iter = chunked_array.begin(),
+         end  = chunked_array.end();
+
+    // iterate over all array elements
+    for(; iter != end; ++iter)
+    {
+        // access current element
+        *iter = *iter + 2.0;
+    }
+\endcode
+A new chunk must potentially be activated whenever the iterator crosses
+a chunk boundary. Since the overhead of the activation operation can be
+amortized over many within-chunk steps, the iteration (excluding the
+workload within the loop) takes only twice as long as the iteration over an
+unstrided array using an ordinary \ref StridedScanOrderIterator.
+
+The final possibility is the creation of a MultiArrayView that accesses
+an arbitrary ROI directly:
+\code
+    ChunkedArray<3, float> & chunked_array = ...;
+
+    // define the ROI to be processed
+    Shape3 roi_start(100, 200, 300), roi_end(1000, 2000, 600);
+
+    // create view for ROI
+    MultiArrayView<3, float, ChunkedArrayTag> view =
+                    chunked_array.subarray(roi_start, roi_stop);
+
+    ... // work phase: process view like any ordinary MultiArrayView
+\endcode
+Similarly, a lower-dimensional view can be created with one of the
+<tt>bind</tt> functions. This approach has the advantage that 'view'
+can be passed to any function which is implemented in terms of
+MultiArrayViews. However, there are two disadvantages: First, data access
+in the view requires two steps (first find the chunk, then find the
+appropriate element in the chunk), which causes the chunked view to
+be slower than an ordinary MultiArrayView. Second, all chunks intersected
+by the view must remain active throughout the view's lifetime, which
+may require a big chunk cache and thus keeps many chunks in memory.
+*/
+template <unsigned int N, class T>
+class ChunkedArray
+: public ChunkedArrayBase<N, T>
+{
+    /*
+    FIXME:
+    * backends:
+       * allocators are not used
+       * HDF5 only works for scalar types so far
+       * HDF5 must support read-only and read/write mode
+       * temp file arrays in swap (just an API addition to the constructor)
+       * support TIFF chunked reading
+    * the array implementations should go into cxx files in src/impex
+      * this requires implementation of the low-level functions independently of dtype
+        (use 'char *' and multiply shape and stride with sizeof(T))
+      * don't forget to increment the soversion after the change
+      * alternative: provide 'config_local.hxx' with flags for available packages
+    * decide on chunk locking policies for array views (in particular, for index access)
+      * array view has functions fetch()/release() (better names?) to lock/unlock
+        _all_ chunks in the view
+      * release() is automatically called in the destructor
+      * it should be possible to call fetch in the constructor via a flag,
+        but should the constructor fetch by default?
+      * how should fetch() handle the case when the cache is too small
+        * throw an exception?
+        * silently enlarge the cache?
+        * temporarily enlarge the cache?
+        * provide an option to control the behavior?
+      * also provide copySubarray() with ReadOnly and ReadWrite flags, where
+        ReadWrite copies the subarray back in the destructor or on demand
+        * locking is only required while each slice is copied
+        * the copy functions can use normal array views and iterators
+        * the ReadWrite version can store a checksum for each chunk (or part
+          of a chunk) to detect collisions on write
+        * use shared pointers to support memory management of the subarrays?
+    * find efficient ways to support slicing and transposition in the indexing
+      functions of a view.
+      1. possibility: each view contains
+          * an index object 'bound_index_' with original dimension whose values denote
+            coordinates of bound axes and offsets for unbound coordinates
+          * a permutation object 'permutation_' with dimension of the view that maps
+            view coordinates to original coordinates
+          * that is:
+            operator[](index)
+            {
+                shape_type full_index(bound_index_);
+                for(int k=0; k<N_view; ++k)
+                    full_index[permutation_[k]] += index[k];
+                split full_index into chunk part and local part
+                look up chunk
+                return pixel
+            }
+          * maybe this is faster if it is combined with the stride computation?
+          * an optimization for unsliced arrays is desirable
+      2. possibility:
+          * add the point offset to the low-dimensional index
+          * split low-dimensional index into chunk part and local part
+          * look up chunk
+          * determine scalar pointer offset from local part and strides plus a
+            chunk-specific correction that can be stored in a 3^N array
+            - but can we efficiently determine where to look in that offset array?
+      3. possibility:
+          * don't care about speed - require copySubarray() if indexing should
+            be fast
+    * provide a ChunkIterator that iterates over all chunks in a given ROI and returns a
+      MultiArrayView for the present chunk (which remains locked in cache until the
+      iterator is advanced).
+    * implement proper copy constructors and assignment for all backends
+    * test HDF5 constructor from existing dataset
+    * put HDF5 into header of its own
+    * is the full chunkForIterator() function slow? Check this with a simplified one
+      in a ChunkedArrayLazy where all chunlks are already implemented, so that
+      we can simply can skip the check
+    * add support for Multiband and TinyVector pixels
+
+    */
+
+  public:
+    typedef ChunkedArrayBase<N, T> base_type;
+    typedef typename MultiArrayShape<N>::type  shape_type;
+    typedef typename shape_type::value_type  difference_type_1;
+    typedef T value_type;
+    typedef value_type * pointer;
+    typedef value_type const * const_pointer;
+    typedef value_type & reference;
+    typedef value_type const & const_reference;
+    typedef ChunkIterator<N, T>         chunk_iterator;
+    typedef ChunkIterator<N, T const>   chunk_const_iterator;
+    typedef StridedScanOrderIterator<N, ChunkedMemory<T>, reference, pointer>   iterator;
+    typedef StridedScanOrderIterator<N, ChunkedMemory<T const>, const_reference, const_pointer>   const_iterator;
+    typedef SharedChunkHandle<N, T> Handle;
+    typedef ChunkBase<N, T> Chunk;
+    typedef MultiArrayView<N, T, ChunkedArrayTag>                   view_type;
+    typedef MultiArrayView<N, T const, ChunkedArrayTag>             const_view_type;
+    typedef std::queue<Handle*> CacheType;
+
+    static const long chunk_asleep = Handle::chunk_asleep;
+    static const long chunk_uninitialized = Handle::chunk_uninitialized;
+    static const long chunk_locked = Handle::chunk_locked;
+    static const long chunk_failed = Handle::chunk_failed;
+
+    // constructor only called by derived classes (ChunkedArray is abstract)
+    explicit ChunkedArray(shape_type const & shape,
+                          shape_type const & chunk_shape = shape_type(),
+                          ChunkedArrayOptions const & options = ChunkedArrayOptions())
+    : ChunkedArrayBase<N, T>(shape, chunk_shape)
+    , bits_(initBitMask(this->chunk_shape_))
+    , mask_(this->chunk_shape_ -shape_type(1))
+    , cache_max_size_(options.cache_max)
+    , chunk_lock_(new threading::mutex())
+    , fill_value_(T(options.fill_value))
+    , fill_scalar_(options.fill_value)
+    , handle_array_(detail::computeChunkArrayShape(shape, bits_, mask_))
+    , data_bytes_()
+    , overhead_bytes_(handle_array_.size()*sizeof(Handle))
+    {
+        fill_value_chunk_.pointer_ = &fill_value_;
+        fill_value_handle_.pointer_ = &fill_value_chunk_;
+        fill_value_handle_.chunk_state_.store(1);
+    }
+
+    // compute masks needed for fast index access
+    static shape_type initBitMask(shape_type const & chunk_shape)
+    {
+        shape_type res;
+        for(unsigned int k=0; k<N; ++k)
+        {
+            UInt32 bits = log2i(chunk_shape[k]);
+            vigra_precondition(chunk_shape[k] == MultiArrayIndex(1 << bits),
+                               "ChunkedArray: chunk_shape elements must be powers of 2.");
+            res[k] = bits;
+         }
+         return res;
+    }
+
+    virtual ~ChunkedArray()
+    {
+        // std::cerr << "    final cache size: " << cacheSize() << " (max: " << cacheMaxSize() << ")\n";
+    }
+
+    /** \brief Number of chunks currently fitting into the cache.
+    */
+    int cacheSize() const
+    {
+        return cache_.size();
+    }
+
+    /** \brief Bytes of main memory occupied by the array's data.
+
+        Compressed chunks are only counted with their compressed size.
+        Chunks swapped out to the hard drive are not counted.
+    */
+    std::size_t dataBytes() const
+    {
+        return data_bytes_;
+    }
+
+    /** \brief Bytes of main memory needed to manage the chunked storage.
+    */
+    std::size_t overheadBytes() const
+    {
+        return overhead_bytes_;
+    }
+
+    /** \brief Number of chunks along each coordinate direction.
+    */
+    virtual shape_type chunkArrayShape() const
+    {
+        return handle_array_.shape();
+    }
+
+    virtual std::size_t dataBytes(Chunk * c) const = 0;
+
+    /** \brief Number of data bytes in an uncompressed chunk.
+    */
+    std::size_t dataBytesPerChunk() const
+    {
+        return prod(this->chunk_shape_)*sizeof(T);
+    }
+
+    /** \brief Bytes of main memory needed to manage a single chunk.
+    */
+    virtual std::size_t overheadBytesPerChunk() const = 0;
+
+    /** \brief Find the chunk that contains array element 'global_start'.
+    */
+    shape_type chunkStart(shape_type const & global_start) const
+    {
+        shape_type chunk_start(SkipInitialization);
+        detail::ChunkIndexing<N>::chunkIndex(global_start, bits_, chunk_start);
+        return chunk_start;
+    }
+
+    /** \brief Find the chunk that is beyond array element 'global_stop'.
+
+        Specifically, this computes
+        \code
+        chunkStart(global_stop - shape_type(1)) + shape_type(1)
+        \endcode
+    */
+    shape_type chunkStop(shape_type global_stop) const
+    {
+        global_stop -= shape_type(1);
+        shape_type chunk_stop(SkipInitialization);
+        detail::ChunkIndexing<N>::chunkIndex(global_stop, bits_, chunk_stop);
+        chunk_stop += shape_type(1);
+        return chunk_stop;
+    }
+
+    /** \brief Find the shape of the chunk indexed by 'chunk_index'.
+
+         This may differ from the global chunk shape because chunks at the
+         right/lower border of the array may be smaller than usual.
+    */
+    shape_type chunkShape(shape_type const & chunk_index) const
+    {
+        return min(this->chunk_shape_,
+                   this->shape_ - chunk_index*this->chunk_shape_);
+    }
+
+    using base_type::chunkShape;
+
+#ifdef DOXYGEN
+    /** \brief Return the global chunk shape.
+
+        This is the shape of all chunks that are completely contained
+        in the array's domain.
+    */
+    shape_type const & chunkShape() const;
+
+    /** \brief Return the shape in this array.
+    */
+    shape_type const & shape() const;
+
+    /** \brief Return the number of elements in this array.
+    */
+    MultiArrayIndex size() const;
+
+    /** \brief Check if the given point is in the array domain.
+    */
+    bool isInside(shape_type const & p) const;
+
+    /** \brief Return the class that implements this ChunkedArray.
+    */
+    std::string backend() const;
+
+#endif
+
+    inline void
+    checkSubarrayBounds(shape_type const & start, shape_type const & stop,
+                        std::string message) const
+    {
+        message += ": subarray out of bounds.";
+        vigra_precondition(allLessEqual(shape_type(), start) &&
+                           allLess(start, stop) &&
+                           allLessEqual(stop, this->shape_),
+                           message);
+    }
+
+    /** \brief Check if two arrays are elementwise equal.
+    */
+    template <class U, class C1>
+    bool operator==(MultiArrayView<N, U, C1> const & rhs) const
+    {
+        if(this->shape() != rhs.shape())
+            return false;
+        const_iterator i = begin(), ie = end();
+        typename MultiArrayView<N, U, C1>::const_iterator j = rhs.begin();
+        for(; i != ie; ++i, ++j)
+            if(*i != *j)
+                return false;
+        return true;
+    }
+
+    /** \brief Check if two arrays differ in at least one element.
+    */
+    template <class U, class C1>
+    bool operator!=(MultiArrayView<N, U, C1> const & rhs) const
+    {
+        return !operator==(rhs);
+    }
+
+    // internal function to activate a chunk
+    virtual pointer loadChunk(Chunk ** chunk, shape_type const & chunk_index) = 0;
+
+    // internal function to send a chunk asleep or delete it
+    // entirely (when destroy = true).
+    // returns true if the chunk was deleted, false otherwise
+    virtual bool unloadHandle(Handle * handle, bool destroy = false)
+    {
+        if(handle == &fill_value_handle_)
+            return false;
+        return unloadChunk(handle->pointer_, destroy);
+    }
+
+    virtual bool unloadChunk(Chunk * chunk, bool destroy = false) = 0;
+
+    Handle * lookupHandle(shape_type const & index)
+    {
+        return &handle_array_[index];
+    }
+
+    // Decrease the reference counter of the given chunk.
+    // Will inactivate the chunk when reference counter reaches zero.
+    virtual void unrefChunk(IteratorChunkHandle<N, T> * h) const
+    {
+        unrefChunk(h->chunk_);
+        h->chunk_ = 0;
+    }
+
+    // Likewise
+    void unrefChunk(Handle * chunk) const
+    {
+        if(chunk)
+        {
+            long rc = chunk->chunk_state_.fetch_sub(1);
+          #ifdef VIGRA_CHECK_BOUNDS
+            vigra_invariant(rc >= 0,
+                            "ChunkedArray::unrefChunk(): chunk refcount got negative!");
+          #endif
+        }
+    }
+
+    // Decrease the reference counter of several chunks simultaneously.
+    void unrefChunks(ArrayVector<Handle*> const & chunks)
+    {
+        for(unsigned int k=0; k<chunks.size(); ++k)
+            unrefChunk(chunks[k]);
+
+        if(cacheMaxSize() > 0)
+        {
+            threading::lock_guard<threading::mutex> guard(*chunk_lock_);
+            cleanCache(cache_.size());
+        }
+    }
+
+    // Increase the reference counter of the given chunk.
+    // If the chunk was asleep, the function first awakens it.
+    long acquireRef(Handle * handle) const
+    {
+        // Obtain a reference to the current chunk handle.
+        // We use a simple spin-lock here because it is very fast in case of success,
+        // and failures (i.e. collisions with another thread) are presumably
+        // very rare.
+        //
+        // the function returns the old value of chunk_state_
+        long rc = handle->chunk_state_.load(threading::memory_order_acquire);
+        while(true)
+        {
+            if(rc >= 0)
+            {
+                if(handle->chunk_state_.compare_exchange_weak(rc, rc+1, threading::memory_order_seq_cst))
+                {
+                    return rc;
+                }
+            }
+            else
+            {
+                if(rc == chunk_failed)
+                {
+                    vigra_precondition(false,
+                     "ChunkedArray::acquireRef() attempt to access failed chunk.");
+                }
+                else if(rc == chunk_locked)
+                {
+                    // cache management in progress => try again later
+                    threading::this_thread::yield();
+                    rc = handle->chunk_state_.load(threading::memory_order_acquire);
+                }
+                else if(handle->chunk_state_.compare_exchange_weak(rc, chunk_locked, threading::memory_order_seq_cst))
+                {
+                    return rc;
+                }
+            }
+        }
+    }
+
+    pointer
+    getChunk(Handle * handle, bool isConst, bool insertInCache, shape_type const & chunk_index) const
+    {
+        ChunkedArray * self = const_cast<ChunkedArray *>(this);
+
+        long rc = acquireRef(handle);
+        if(rc >= 0)
+            return handle->pointer_->pointer_;
+
+        threading::lock_guard<threading::mutex> guard(*chunk_lock_);
+        try
+        {
+            T * p = self->loadChunk(&handle->pointer_, chunk_index);
+            Chunk * chunk = handle->pointer_;
+            if(!isConst && rc == chunk_uninitialized)
+                std::fill(p, p + prod(chunkShape(chunk_index)), this->fill_value_);
+
+            self->data_bytes_ += dataBytes(chunk);
+
+            if(cacheMaxSize() > 0 && insertInCache)
+            {
+                // insert in queue of mapped chunks
+                self->cache_.push(handle);
+
+                // do cache management if cache is full
+                // (note that we still hold the chunk_lock_)
+                self->cleanCache(2);
+            }
+            handle->chunk_state_.store(1, threading::memory_order_release);
+            return p;
+        }
+        catch(...)
+        {
+            handle->chunk_state_.store(chunk_failed);
+            throw;
+        }
+    }
+
+    // helper function for chunkForIterator()
+    inline pointer
+    chunkForIteratorImpl(shape_type const & point,
+                         shape_type & strides, shape_type & upper_bound,
+                         IteratorChunkHandle<N, T> * h,
+                         bool isConst) const
+    {
+        ChunkedArray * self = const_cast<ChunkedArray *>(this);
+
+        unrefChunk(h->chunk_);
+        h->chunk_ = 0;
+
+        shape_type global_point = point + h->offset_;
+
+        if(!this->isInside(global_point))
+        {
+            upper_bound = point + this->chunk_shape_;
+            return 0;
+        }
+
+        shape_type chunkIndex(chunkStart(global_point));
+
+        bool insertInCache = true;
+        Handle * handle = self->lookupHandle(chunkIndex);
+        if(isConst && handle->chunk_state_.load() == chunk_uninitialized)
+        {
+            handle = &self->fill_value_handle_;
+            insertInCache = false;
+        }
+
+        pointer p = getChunk(handle, isConst, insertInCache, chunkIndex);
+        strides = handle->strides();
+        upper_bound = (chunkIndex + shape_type(1)) * this->chunk_shape_ - h->offset_;
+        std::size_t offset = detail::ChunkIndexing<N>::offsetInChunk(global_point, mask_, strides);
+        h->chunk_ = handle;
+        return p + offset;
+    }
+
+    // called by chunked scan-order iterator to obtain the new data pointer
+    // when the iterator enters a new chunk
+    virtual pointer chunkForIterator(shape_type const & point,
+                                     shape_type & strides, shape_type & upper_bound,
+                                     IteratorChunkHandle<N, T> * h)
+    {
+        return chunkForIteratorImpl(point, strides, upper_bound, h, false);
+    }
+
+    virtual pointer chunkForIterator(shape_type const & point,
+                                     shape_type & strides, shape_type & upper_bound,
+                                     IteratorChunkHandle<N, T> * h) const
+    {
+        return chunkForIteratorImpl(point, strides, upper_bound, h, true);
+    }
+
+    // NOTE: This function must only be called while we hold the chunk_lock_.
+    //       This implies refcount != chunk_locked, so that race conditions are avoided.
+    long releaseChunk(Handle * handle, bool destroy = false)
+    {
+        long rc = 0;
+        bool mayUnload = handle->chunk_state_.compare_exchange_strong(rc, chunk_locked);
+        if(!mayUnload && destroy)
+        {
+            rc = chunk_asleep;
+            mayUnload = handle->chunk_state_.compare_exchange_strong(rc, chunk_locked);
+        }
+        if(mayUnload)
+        {
+            // refcount was zero or chunk_asleep => can unload
+            try
+            {
+                vigra_invariant(handle != &fill_value_handle_,
+                   "ChunkedArray::releaseChunk(): attempt to release fill_value_handle_.");
+                Chunk * chunk = handle->pointer_;
+                this->data_bytes_ -= dataBytes(chunk);
+                int didDestroy = unloadChunk(chunk, destroy);
+                this->data_bytes_ += dataBytes(chunk);
+                if(didDestroy)
+                    handle->chunk_state_.store(chunk_uninitialized);
+                else
+                    handle->chunk_state_.store(chunk_asleep);
+            }
+            catch(...)
+            {
+                handle->chunk_state_.store(chunk_failed);
+                throw;
+            }
+        }
+        return rc;
+    }
+
+    // NOTE: this function must only be called while we hold the chunk_lock_
+    void cleanCache(int how_many = -1)
+    {
+        if(how_many == -1)
+            how_many = cache_.size();
+        for(; cache_.size() > cacheMaxSize() && how_many > 0; --how_many)
+        {
+            Handle * handle = cache_.front();
+            cache_.pop();
+            long rc = releaseChunk(handle);
+            if(rc > 0) // refcount was positive => chunk is still needed
+                cache_.push(handle);
+        }
+    }
+
+    /** Sends all chunks asleep which are completely inside the given ROI.
+        If destroy == true and the backend supports destruction (currently:
+        ChunkedArrayLazy and ChunkedArrayCompressed), chunks will be deleted
+        entirely. The chunk's contents after releaseChunks() are undefined.
+        Currently, chunks retain their values when sent asleep, and assume the
+        array's fill_value when deleted, but applications should not rely on this
+        behavior.
+    */
+    void releaseChunks(shape_type const & start, shape_type const & stop, bool destroy = false)
+    {
+        checkSubarrayBounds(start, stop, "ChunkedArray::releaseChunks()");
+
+        MultiCoordinateIterator<N> i(chunkStart(start), chunkStop(stop)),
+                                   end(i.getEndIterator());
+        for(; i != end; ++i)
+        {
+            shape_type chunkOffset = *i * this->chunk_shape_;
+            if(!allLessEqual(start, chunkOffset) ||
+               !allLessEqual(min(chunkOffset+this->chunk_shape_, this->shape()), stop))
+            {
+                // chunk is only partially covered by the ROI
+                continue;
+            }
+
+            Handle * handle = this->lookupHandle(*i);
+            threading::lock_guard<threading::mutex> guard(*chunk_lock_);
+            releaseChunk(handle, destroy);
+        }
+
+        // remove all chunks from the cache that are asleep or unitialized
+        threading::lock_guard<threading::mutex> guard(*chunk_lock_);
+        int cache_size = cache_.size();
+        for(int k=0; k < cache_size; ++k)
+        {
+            Handle * handle = cache_.front();
+            cache_.pop();
+            if(handle->chunk_state_.load() >= 0)
+                cache_.push(handle);
+        }
+    }
+
+    /** \brief Copy an ROI of the chunked array into an ordinary MultiArrayView.
+
+        The ROI's lower bound is given by 'start', its upper bound (in 'beyond' sense)
+        is 'start + subarray.shape()'. Chunks in the ROI are only activated while
+        the read is in progress.
+    */
+    template <class U, class Stride>
+    void
+    checkoutSubarray(shape_type const & start,
+                     MultiArrayView<N, U, Stride> & subarray) const
+    {
+        shape_type stop   = start + subarray.shape();
+
+        checkSubarrayBounds(start, stop, "ChunkedArray::checkoutSubarray()");
+
+        chunk_const_iterator i = chunk_cbegin(start, stop);
+        for(; i.isValid(); ++i)
+        {
+            subarray.subarray(i.chunkStart()-start, i.chunkStop()-start) = *i;
+        }
+    }
+
+    /** \brief Copy an ordinary MultiArrayView into an ROI of the chunked array.
+
+        The ROI's lower bound is given by 'start', its upper bound (in 'beyond' sense)
+        is 'start + subarray.shape()'. Chunks in the ROI are only activated while
+        the write is in progress.
+    */
+    template <class U, class Stride>
+    void
+    commitSubarray(shape_type const & start,
+                   MultiArrayView<N, U, Stride> const & subarray)
+    {
+        shape_type stop   = start + subarray.shape();
+
+        vigra_precondition(!this->isReadOnly(),
+                           "ChunkedArray::commitSubarray(): array is read-only.");
+        checkSubarrayBounds(start, stop, "ChunkedArray::commitSubarray()");
+
+        chunk_iterator i = chunk_begin(start, stop);
+        for(; i.isValid(); ++i)
+        {
+            *i = subarray.subarray(i.chunkStart()-start, i.chunkStop()-start);
+        }
+    }
+
+    // helper function for subarray()
+    template <class View>
+    void subarrayImpl(shape_type const & start, shape_type const & stop,
+                      View & view,
+                      bool isConst) const
+    {
+        vigra_precondition(isConst || !this->isReadOnly(),
+                           "ChunkedArray::subarray(): array is read-only.");
+        checkSubarrayBounds(start, stop, "ChunkedArray::subarray()");
+        shape_type chunk_start(chunkStart(start)), chunk_stop(chunkStop(stop));
+
+        view.shape_ = stop-start;
+        view.chunk_shape_ = this->chunk_shape_;
+        view.chunks_.reshape(chunk_stop-chunk_start);
+        view.offset_ = start - chunk_start * this->chunk_shape_;
+        view.bits_   = bits_;
+        view.mask_   = mask_;
+
+        typedef typename View::UnrefProxy Unref;
+        ChunkedArray* self = const_cast<ChunkedArray*>(this);
+        Unref * unref = new Unref(view.chunks_.size(), self);
+        view.unref_ = VIGRA_SHARED_PTR<Unref>(unref);
+
+        MultiCoordinateIterator<N> i(chunk_start, chunk_stop),
+                                   end(i.getEndIterator());
+        for(; i != end; ++i)
+        {
+            Handle * handle = self->lookupHandle(*i);
+
+            if(isConst && handle->chunk_state_.load() == chunk_uninitialized)
+                handle = &self->fill_value_handle_;
+
+            // This potentially acquires the chunk_lock_ in each iteration.
+            // Would it be better to acquire it once before the loop?
+            pointer p = getChunk(handle, isConst, true, *i);
+
+            ChunkBase<N, T> * mini_chunk = &view.chunks_[*i - chunk_start];
+            mini_chunk->pointer_ = p;
+            mini_chunk->strides_ = handle->strides();
+            unref->chunks_[i.scanOrderIndex()] = handle;
+        }
+    }
+
+    /** \brief Create a view to the specified ROI.
+
+        The view can be used like an ordinary \ref MultiArrayView, but is
+        a but slower. All chunks intersecting the view remain active
+        throughout the view's lifetime.
+    */
+    view_type
+    subarray(shape_type const & start, shape_type const & stop)
+    {
+        view_type view;
+        subarrayImpl(start, stop, view, false);
+        return view;
+    }
+
+    /** \brief Create a read-only view to the specified ROI.
+
+        The view can be used like an ordinary \ref MultiArrayView, but is
+        a but slower. All chunks intersecting the view remain active
+        throughout the view's lifetime.
+    */
+    const_view_type
+    subarray(shape_type const & start, shape_type const & stop) const
+    {
+        const_view_type view;
+        subarrayImpl(start, stop, view, true);
+        return view;
+    }
+
+    /** \brief Create a read-only view to the specified ROI.
+
+        The view can be used like an ordinary \ref MultiArrayView, but is
+        a but slower. All chunks intersecting the view remain active
+        throughout the view's lifetime.
+    */
+    const_view_type
+    const_subarray(shape_type const & start, shape_type const & stop) const
+    {
+        const_view_type view;
+        subarrayImpl(start, stop, view, true);
+        return view;
+    }
+
+    /** \brief Read the array element at index 'point'.
+
+        Since the corresponding chunk must potentially be activated
+        first, this function may be slow and should mainly be used in
+        debugging.
+    */
+    value_type getItem(shape_type const & point) const
+    {
+        vigra_precondition(this->isInside(point),
+            "ChunkedArray::getItem(): index out of bounds.");
+
+        ChunkedArray * self = const_cast<ChunkedArray*>(this);
+        shape_type chunk_index(chunkStart(point));
+        Handle * handle = self->lookupHandle(chunk_index);
+        if(handle->chunk_state_.load() == chunk_uninitialized)
+            return fill_value_;
+        pointer p = self->getChunk(handle, true, false, chunk_index);
+        value_type res = *(p +
+                           detail::ChunkIndexing<N>::offsetInChunk(point, mask_, handle->strides()));
+        self->unrefChunk(handle);
+        return res;
+    }
+
+    /** \brief Write the array element at index 'point'.
+
+        Since the corresponding chunk must potentially be activated
+        first, this function may be slow and should mainly be used in
+        debugging.
+    */
+    void setItem(shape_type const & point, value_type const & v)
+    {
+        vigra_precondition(!this->isReadOnly(),
+            "ChunkedArray::setItem(): array is read-only.");
+        vigra_precondition(this->isInside(point),
+            "ChunkedArray::setItem(): index out of bounds.");
+
+        shape_type chunk_index(chunkStart(point));
+        Handle * handle = lookupHandle(chunk_index);
+        pointer p = getChunk(handle, false, false, chunk_index);
+        *(p + detail::ChunkIndexing<N>::offsetInChunk(point, mask_, handle->strides())) = v;
+        unrefChunk(handle);
+    }
+
+    /** \brief Create a lower dimensional view to the chunked array.
+
+        Dimension 'dim' is bound at 'index', all other dimensions remain
+        unchanged. All chunks intersecting the view remain active
+        throughout the view's lifetime.
+    */
+    MultiArrayView<N-1, T, ChunkedArrayTag>
+    bindAt(MultiArrayIndex dim, MultiArrayIndex index) const
+    {
+        shape_type start, stop(this->shape());
+        start[dim] = index;
+        stop[dim] = index+1;
+        return subarray(start, stop).bindAt(dim, 0);
+    }
+
+    /** \brief Create a lower dimensional view to the chunked array.
+
+        Dimension 'M' (given as a template parameter) is bound at 'index',
+        all other dimensions remain unchanged. All chunks intersecting the
+        view remain active throughout the view's lifetime.
+    */
+    template <unsigned int M>
+    MultiArrayView <N-1, T, ChunkedArrayTag>
+    bind (difference_type_1 index) const
+    {
+        return bindAt(M, index);
+    }
+
+    /** \brief Create a lower dimensional view to the chunked array.
+
+        Dimension 'N-1' is bound at 'index', all other dimensions remain
+        unchanged. All chunks intersecting the view remain active
+        throughout the view's lifetime.
+    */
+    MultiArrayView <N-1, T, ChunkedArrayTag>
+    bindOuter (difference_type_1 index) const
+    {
+        return bindAt(N-1, index);
+    }
+
+    /** \brief Create a lower dimensional view to the chunked array.
+
+        The M rightmost dimensions are bound to the indices given in 'd'.
+        All chunks intersecting the view remain active throughout the view's lifetime.
+    */
+    template <int M, class Index>
+    MultiArrayView <N-M, T, ChunkedArrayTag>
+    bindOuter(const TinyVector <Index, M> & d) const
+    {
+        return bindAt(N-1, d[M-1]).bindOuter(d.dropIndex(M-1));
+    }
+
+    // terminate the recursion of the above function
+    template <class Index>
+    MultiArrayView <N-1, T, ChunkedArrayTag>
+    bindOuter(const TinyVector <Index, 1> & d) const
+    {
+        return bindAt(N-1, d[0]);
+    }
+
+    /** \brief Create a lower dimensional view to the chunked array.
+
+        Dimension '0' is bound at 'index', all other dimensions remain
+        unchanged. All chunks intersecting the view remain active
+        throughout the view's lifetime.
+    */
+    MultiArrayView <N-1, T, ChunkedArrayTag>
+    bindInner (difference_type_1 index) const
+    {
+        return bindAt(0, index);
+    }
+
+    /** \brief Create a lower dimensional view to the chunked array.
+
+        The M leftmost dimensions are bound to the indices given in 'd'.
+        All chunks intersecting the view remain active throughout the view's lifetime.
+    */
+    template <int M, class Index>
+    MultiArrayView <N-M, T, ChunkedArrayTag>
+    bindInner(const TinyVector <Index, M> & d) const
+    {
+        return bindAt(0, d[0]).bindInner(d.dropIndex(0));
+    }
+
+    // terminate the recursion of the above function
+    template <class Index>
+    MultiArrayView <N-1, T, ChunkedArrayTag>
+    bindInner(const TinyVector <Index, 1> & d) const
+    {
+        return bindAt(0, d[0]);
+    }
+
+    /** \brief Get the number of chunks the cache will hold.
+
+        If there are any inactive chunks in the cache, these will be
+        sent asleep until the max cahce size is reached. The max cache
+        size may be temporarily overridden when more chunks need
+        to be active simultaneously.
+    */
+    std::size_t cacheMaxSize() const
+    {
+        if(cache_max_size_ < 0)
+            const_cast<int &>(cache_max_size_) = detail::defaultCacheSize(this->chunkArrayShape());
+        return cache_max_size_;
+    }
+
+    /** \brief Set the number of chunks the cache will hold.
+
+        This should be big enough to hold all chunks that are frequently needed
+        and must therefore be adopted to the application's access pattern.
+    */
+    void setCacheMaxSize(std::size_t c)
+    {
+        cache_max_size_ = c;
+        if(c < cache_.size())
+        {
+            threading::lock_guard<threading::mutex> guard(*chunk_lock_);
+            cleanCache();
+        }
+    }
+
+    /** \brief Create a scan-order iterator for the entire chunked array.
+    */
+    iterator begin()
+    {
+        return createCoupledIterator(*this);
+    }
+
+    /** \brief Create the end iterator for scan-order iteration over
+        the entire chunked array.
+    */
+    iterator end()
+    {
+        return begin().getEndIterator();
+    }
+
+    /** \brief Create a read-only scan-order iterator for the entire
+         chunked array.
+    */
+    const_iterator cbegin() const
+    {
+        return createCoupledIterator(const_cast<ChunkedArray const &>(*this));
+    }
+
+    /** \brief Create the end iterator for read-only scan-order iteration over
+        the entire chunked array.
+    */
+    const_iterator cend() const
+    {
+        return cbegin().getEndIterator();
+    }
+
+    /** \brief Create a read-only scan-order iterator for the entire
+         chunked array.
+    */
+    const_iterator begin() const
+    {
+        return createCoupledIterator(*this);
+    }
+
+    /** \brief Create the end iterator for read-only scan-order iteration over
+        the entire chunked array.
+    */
+    const_iterator end() const
+    {
+        return begin().getEndIterator();
+    }
+
+    /** \brief Create an iterator over all chunks intersected by the given ROI.
+    */
+    chunk_iterator chunk_begin(shape_type const & start, shape_type const & stop)
+    {
+        checkSubarrayBounds(start, stop, "ChunkedArray::chunk_begin()");
+        return chunk_iterator(this, start, stop, chunkStart(start), chunkStop(stop), this->chunk_shape_);
+    }
+
+    /** \brief Create the end iterator for iteration over all chunks
+        intersected by the given ROI.
+    */
+    chunk_iterator chunk_end(shape_type const & start, shape_type const & stop)
+    {
+        return chunk_begin(start, stop).getEndIterator();
+    }
+
+    /** \brief Create a read-only iterator over all chunks intersected
+        by the given ROI.
+    */
+    chunk_const_iterator chunk_begin(shape_type const & start, shape_type const & stop) const
+    {
+        checkSubarrayBounds(start, stop, "ChunkedArray::chunk_begin()");
+        return chunk_const_iterator(this, start, stop, chunkStart(start), chunkStop(stop), this->chunk_shape_);
+    }
+
+    /** \brief Create the end iterator for read-only iteration over all chunks
+        intersected by the given ROI.
+    */
+    chunk_const_iterator chunk_end(shape_type const & start, shape_type const & stop) const
+    {
+        return chunk_begin(start, stop).getEndIterator();
+    }
+
+    /** \brief Create a read-only iterator over all chunks intersected
+        by the given ROI.
+    */
+    chunk_const_iterator chunk_cbegin(shape_type const & start, shape_type const & stop) const
+    {
+        checkSubarrayBounds(start, stop, "ChunkedArray::chunk_cbegin()");
+        return chunk_const_iterator(this, start, stop, chunkStart(start), chunkStop(stop), this->chunk_shape_);
+    }
+
+    /** \brief Create the end iterator for read-only iteration over all chunks
+        intersected by the given ROI.
+    */
+    chunk_const_iterator chunk_cend(shape_type const & start, shape_type const & stop) const
+    {
+        return chunk_cbegin(start, stop).getEndIterator();
+    }
+
+    shape_type bits_, mask_;
+    int cache_max_size_;
+    VIGRA_SHARED_PTR<threading::mutex> chunk_lock_;
+    CacheType cache_;
+    Chunk fill_value_chunk_;
+    Handle fill_value_handle_;
+    value_type fill_value_;
+    double fill_scalar_;
+    MultiArray<N, Handle> handle_array_;
+    std::size_t data_bytes_, overhead_bytes_;
+};
+
+/** Returns a CoupledScanOrderIterator to simultaneously iterate over image m1 and its coordinates.
+ */
+template <unsigned int N, class T>
+typename ChunkedArray<N, T>::iterator
+createCoupledIterator(ChunkedArray<N, T> & m)
+{
+    typedef typename ChunkedArray<N, T>::iterator    IteratorType;
+    typedef typename IteratorType::handle_type           P1;
+    typedef typename P1::base_type                       P0;
+
+    return IteratorType(P1(m,
+                        P0(m.shape())));
+}
+
+template <unsigned int N, class T>
+typename ChunkedArray<N, T>::const_iterator
+createCoupledIterator(ChunkedArray<N, T> const & m)
+{
+    typedef typename ChunkedArray<N, T>::const_iterator  IteratorType;
+    typedef typename IteratorType::handle_type           P1;
+    typedef typename P1::base_type                       P0;
+
+    return IteratorType(P1(m,
+                        P0(m.shape())));
+}
+
+/** Implement ChunkedArray as an ordinary MultiArray with a single chunk.
+
+    <b>\#include</b> \<vigra/multi_array_chunked.hxx\> <br/>
+    Namespace: vigra
+*/
+template <unsigned int N, class T, class Alloc = std::allocator<T> >
+class ChunkedArrayFull
+: public ChunkedArray<N, T>,
+  public MultiArray<N, T, Alloc>
+{
+  public:
+
+    typedef MultiArray<N, T, Alloc>             Storage;
+    typedef typename Storage::value_type        value_type;
+    typedef typename Storage::pointer           pointer;
+    typedef typename Storage::const_pointer     const_pointer;
+    typedef typename Storage::reference         reference;
+    typedef typename Storage::const_reference   const_reference;
+    typedef typename Storage::difference_type   difference_type;
+    typedef typename Storage::difference_type   shape_type;
+    typedef typename Storage::key_type          key_type;
+    typedef typename Storage::size_type         size_type;
+    typedef typename Storage::difference_type_1 difference_type_1;
+    typedef typename Storage::iterator          iterator;
+    typedef typename Storage::const_iterator    const_iterator;
+    typedef typename Storage::view_type         view_type;
+
+    typedef typename ChunkedArray<N, T>::Chunk       Chunk;
+
+    static shape_type computeChunkShape(shape_type s)
+    {
+        for(int k=0; k<N; ++k)
+            s[k] = ceilPower2(s[k]);
+        return s;
+    }
+
+    using Storage::subarray;
+    using Storage::bindOuter;
+    using Storage::bindInner;
+    using Storage::bind;
+    using Storage::bindAt;
+    using Storage::isInside;
+    using Storage::shape;
+    using Storage::size;
+    using Storage::begin;
+    using Storage::end;
+
+#ifndef DOXYGEN  // doxygen doesn't understand this
+    using Storage::operator==;
+    using Storage::operator!=;
+#endif
+
+    /** \brief Construct with given 'shape' and 'options', using the allocator
+        'alloc' to manage the memory.
+    */
+    explicit ChunkedArrayFull(shape_type const & shape,
+                              ChunkedArrayOptions const & options = ChunkedArrayOptions(),
+                              Alloc const & alloc = Alloc())
+    : ChunkedArray<N, T>(shape, computeChunkShape(shape), options.cacheMax(0)),
+      Storage(shape, this->fill_value_, alloc),
+      upper_bound_(shape),
+      chunk_(detail::defaultStride(shape), this->data())
+    {
+        this->handle_array_[0].pointer_ = &chunk_;
+        this->handle_array_[0].chunk_state_.store(1);
+        this->data_bytes_ = size()*sizeof(T);
+        this->overhead_bytes_ = overheadBytesPerChunk();
+    }
+
+    ChunkedArrayFull(ChunkedArrayFull const & rhs)
+    : ChunkedArray<N, T>(rhs),
+      Storage(rhs),
+      upper_bound_(rhs.upper_bound_),
+      chunk_(detail::defaultStride(shape), this->data())
+    {
+        this->handle_array_[0].pointer_ = &chunk_;
+        this->handle_array_[0].chunk_state_.store(1);
+    }
+
+    ChunkedArrayFull & operator=(ChunkedArrayFull const & rhs)
+    {
+        if(this != &rhs)
+        {
+            ChunkedArray<N, T>::operator=(rhs);
+            Storage::operator=(rhs);
+            upper_bound_ = rhs.upper_bound_;
+        }
+        return *this;
+    }
+
+    ~ChunkedArrayFull()
+    {}
+
+    virtual shape_type chunkArrayShape() const
+    {
+        return shape_type(1);
+    }
+
+    virtual pointer loadChunk(ChunkBase<N, T> **, shape_type const &)
+    {
+        return this->data();
+    }
+
+    virtual bool unloadChunk(ChunkBase<N, T> *, bool /* destroy */)
+    {
+        return false; // never destroys the data
+    }
+
+    virtual std::size_t dataBytes(Chunk * c) const
+    {
+        return prod(this->shape());
+    }
+
+    virtual std::size_t overheadBytesPerChunk() const
+    {
+        return sizeof(Chunk) + sizeof(SharedChunkHandle<N, T>);
+    }
+
+    virtual pointer chunkForIterator(shape_type const & point,
+                                     shape_type & strides, shape_type & upper_bound,
+                                     IteratorChunkHandle<N, T> * h) const
+    {
+        shape_type global_point = point + h->offset_;
+
+        if(!this->isInside(global_point))
+        {
+            upper_bound = point + this->chunk_shape_;
+            return 0;
+        }
+
+        strides = this->stride();
+        upper_bound = upper_bound_;
+        return const_cast<pointer>(&Storage::operator[](global_point));
+    }
+
+    virtual pointer chunkForIterator(shape_type const & point,
+                                     shape_type & strides, shape_type & upper_bound,
+                                     IteratorChunkHandle<N, T> * h)
+    {
+        shape_type global_point = point + h->offset_;
+
+        if(!this->isInside(global_point))
+        {
+            upper_bound = point + this->chunk_shape_;
+            return 0;
+        }
+
+        strides = this->stride();
+        upper_bound = upper_bound_;
+        return &Storage::operator[](global_point);
+    }
+
+    virtual std::string backend() const
+    {
+        return "ChunkedArrayFull";
+    }
+
+    shape_type upper_bound_;
+    Chunk chunk_;    // a dummy chunk to fulfill the API
+};
+
+/** Implement ChunkedArray as a collection of in-memory chunks.
+
+    This optimizes over an ordinary MultiArray by allocating chunks only
+    upon the first write. This is especially useful when only a small
+    part of the entire array is actually needed, e.g. in a data viewer.
+
+    <b>\#include</b> \<vigra/multi_array_chunked.hxx\> <br/>
+    Namespace: vigra
+*/
+template <unsigned int N, class T, class Alloc = std::allocator<T> >
+class ChunkedArrayLazy
+: public ChunkedArray<N, T>
+{
+  public:
+
+    class Chunk
+    : public ChunkBase<N, T>
+    {
+      public:
+        typedef typename MultiArrayShape<N>::type  shape_type;
+        typedef T value_type;
+        typedef value_type * pointer;
+        typedef value_type & reference;
+
+        Chunk(shape_type const & shape, Alloc const & alloc = Alloc())
+        : ChunkBase<N, T>(detail::defaultStride(shape))
+        , size_(prod(shape))
+        , alloc_(alloc)
+        {}
+
+        ~Chunk()
+        {
+            deallocate();
+        }
+
+        pointer allocate()
+        {
+            if(this->pointer_ == 0)
+                this->pointer_ = detail::alloc_initialize_n<T>(size_, T(), alloc_);
+            return this->pointer_;
+        }
+
+        void deallocate()
+        {
+            detail::destroy_dealloc_n(this->pointer_, size_, alloc_);
+            this->pointer_ = 0;
+        }
+
+        MultiArrayIndex size_;
+        Alloc alloc_;
+
+      private:
+        Chunk & operator=(Chunk const &);
+    };
+
+    typedef MultiArray<N, SharedChunkHandle<N, T> > ChunkStorage;
+    typedef typename ChunkStorage::difference_type  shape_type;
+    typedef T value_type;
+    typedef value_type * pointer;
+    typedef value_type & reference;
+
+    /** \brief Construct with given 'shape', 'chunk_shape' and 'options',
+        using the allocator 'alloc' to manage the memory.
+    */
+    explicit ChunkedArrayLazy(shape_type const & shape,
+                              shape_type const & chunk_shape=shape_type(),
+                              ChunkedArrayOptions const & options = ChunkedArrayOptions(),
+                              Alloc const & alloc = Alloc())
+    : ChunkedArray<N, T>(shape, chunk_shape, options.cacheMax(0))
+    , alloc_(alloc)
+    {}
+
+    ~ChunkedArrayLazy()
+    {
+        typename ChunkStorage::iterator i   = this->handle_array_.begin(),
+                                        end = this->handle_array_.end();
+        for(; i != end; ++i)
+        {
+            if(i->pointer_)
+                delete static_cast<Chunk*>(i->pointer_);
+            i->pointer_ = 0;
+        }
+    }
+
+    virtual pointer loadChunk(ChunkBase<N, T> ** p, shape_type const & index)
+    {
+        if(*p == 0)
+        {
+            *p = new Chunk(this->chunkShape(index));
+            this->overhead_bytes_ += sizeof(Chunk);
+        }
+        return static_cast<Chunk *>(*p)->allocate();
+    }
+
+    virtual bool unloadChunk(ChunkBase<N, T> * chunk, bool destroy)
+    {
+        if(destroy)
+            static_cast<Chunk *>(chunk)->deallocate();
+        return destroy;
+    }
+
+    virtual std::string backend() const
+    {
+        return "ChunkedArrayLazy";
+    }
+
+    virtual std::size_t dataBytes(ChunkBase<N,T> * c) const
+    {
+        return c->pointer_ == 0
+                 ? 0
+                 : static_cast<Chunk*>(c)->size_*sizeof(T);
+    }
+
+    virtual std::size_t overheadBytesPerChunk() const
+    {
+        return sizeof(Chunk) + sizeof(SharedChunkHandle<N, T>);
+    }
+
+    Alloc alloc_;
+};
+
+/** Implement ChunkedArray as a collection of potentially compressed
+    in-memory chunks.
+
+    This works like \ref ChunkedArrayLazy, but inactive chunks are compressed
+    when sent asleep. This is especially appropriate for highly compressible
+    data such as label images.
+
+    <b>\#include</b> \<vigra/multi_array_chunked.hxx\> <br/>
+    Namespace: vigra
+*/
+template <unsigned int N, class T, class Alloc = std::allocator<T> >
+class ChunkedArrayCompressed
+: public ChunkedArray<N, T>
+{
+  public:
+
+    class Chunk
+    : public ChunkBase<N, T>
+    {
+      public:
+        typedef typename MultiArrayShape<N>::type  shape_type;
+        typedef T value_type;
+        typedef value_type * pointer;
+        typedef value_type & reference;
+
+        Chunk(shape_type const & shape)
+        : ChunkBase<N, T>(detail::defaultStride(shape))
+        , compressed_()
+        , size_(prod(shape))
+        {}
+
+        ~Chunk()
+        {
+            deallocate();
+        }
+
+        pointer allocate()
+        {
+            if(this->pointer_ == 0)
+                this->pointer_ = detail::alloc_initialize_n<T>(size_, T(), alloc_);
+            return this->pointer_;
+        }
+
+        void deallocate()
+        {
+            detail::destroy_dealloc_n(this->pointer_, size_, alloc_);
+            this->pointer_ = 0;
+            compressed_.clear();
+        }
+
+        void compress(CompressionMethod method)
+        {
+            if(this->pointer_ != 0)
+            {
+                vigra_invariant(compressed_.size() == 0,
+                    "ChunkedArrayCompressed::Chunk::compress(): compressed and uncompressed pointer are both non-zero.");
+
+                ::vigra::compress((char const *)this->pointer_, size_*sizeof(T), compressed_, method);
+
+                // std::cerr << "compression ratio: " << double(compressed_.size())/(this->size()*sizeof(T)) << "\n";
+                detail::destroy_dealloc_n(this->pointer_, size_, alloc_);
+                this->pointer_ = 0;
+            }
+        }
+
+        pointer uncompress(CompressionMethod method)
+        {
+            if(this->pointer_ == 0)
+            {
+                if(compressed_.size())
+                {
+                    this->pointer_ = alloc_.allocate((typename Alloc::size_type)size_);
+
+                    ::vigra::uncompress(compressed_.data(), compressed_.size(),
+                                        (char*)this->pointer_, size_*sizeof(T), method);
+                    compressed_.clear();
+                }
+                else
+                {
+                    this->pointer_ = allocate();
+                }
+            }
+            else
+            {
+                vigra_invariant(compressed_.size() == 0,
+                    "ChunkedArrayCompressed::Chunk::uncompress(): compressed and uncompressed pointer are both non-zero.");
+            }
+            return this->pointer_;
+        }
+
+        ArrayVector<char> compressed_;
+        MultiArrayIndex size_;
+        Alloc alloc_;
+
+      private:
+        Chunk & operator=(Chunk const &);
+    };
+
+    typedef MultiArray<N, SharedChunkHandle<N, T> > ChunkStorage;
+    typedef typename ChunkStorage::difference_type  shape_type;
+    typedef T value_type;
+    typedef value_type * pointer;
+    typedef value_type & reference;
+
+    /** \brief Construct with given 'shape', 'chunk_shape' and 'options'.
+
+        The most important option concerns the compression algorithm. Supported
+        algorithms are:
+        <ul>
+        <li>LZ4: Very fast algorithm that achieves decent compression ratios.
+        <li>ZLIB_FAST: Fast compression using 'zlib' (slower than LZ4, but higher compression).
+        <li>ZLIB_BEST: Best compression using 'zlib', slow.
+        <li>ZLIB_NONE: Use 'zlib' format without compression.
+        <li>DEFAULT_COMPRESSION: Same as LZ4.
+        </ul>
+    */
+    explicit ChunkedArrayCompressed(shape_type const & shape,
+                                    shape_type const & chunk_shape=shape_type(),
+                                    ChunkedArrayOptions const & options = ChunkedArrayOptions())
+    : ChunkedArray<N, T>(shape, chunk_shape, options),
+       compression_method_(options.compression_method)
+    {
+        if(compression_method_ == DEFAULT_COMPRESSION)
+            compression_method_ = LZ4;
+    }
+
+    ~ChunkedArrayCompressed()
+    {
+        typename ChunkStorage::iterator i   = this->handle_array_.begin(),
+                                        end = this->handle_array_.end();
+        for(; i != end; ++i)
+        {
+            if(i->pointer_)
+                delete static_cast<Chunk*>(i->pointer_);
+            i->pointer_ = 0;
+        }
+    }
+
+    virtual pointer loadChunk(ChunkBase<N, T> ** p, shape_type const & index)
+    {
+        if(*p == 0)
+        {
+            *p = new Chunk(this->chunkShape(index));
+            this->overhead_bytes_ += sizeof(Chunk);
+        }
+        return static_cast<Chunk *>(*p)->uncompress(compression_method_);
+    }
+
+    virtual bool unloadChunk(ChunkBase<N, T> * chunk, bool destroy)
+    {
+        if(destroy)
+            static_cast<Chunk *>(chunk)->deallocate();
+        else
+            static_cast<Chunk *>(chunk)->compress(compression_method_);
+        return destroy;
+    }
+
+    virtual std::string backend() const
+    {
+        switch(compression_method_)
+        {
+          case ZLIB:
+            return "ChunkedArrayCompressed<ZLIB>";
+          case ZLIB_NONE:
+            return "ChunkedArrayCompressed<ZLIB_NONE>";
+          case ZLIB_FAST:
+            return "ChunkedArrayCompressed<ZLIB_FAST>";
+          case ZLIB_BEST:
+            return "ChunkedArrayCompressed<ZLIB_BEST>";
+          case LZ4:
+            return "ChunkedArrayCompressed<LZ4>";
+          default:
+            return "unknown";
+        }
+    }
+
+    virtual std::size_t dataBytes(ChunkBase<N,T> * c) const
+    {
+        return c->pointer_ == 0
+                 ? static_cast<Chunk*>(c)->compressed_.size()
+                 : static_cast<Chunk*>(c)->size_*sizeof(T);
+    }
+
+    virtual std::size_t overheadBytesPerChunk() const
+    {
+        return sizeof(Chunk) + sizeof(SharedChunkHandle<N, T>);
+    }
+
+    CompressionMethod compression_method_;
+};
+
+/** Implement ChunkedArray as a collection of chunks that can be
+    swapped out into a temporary file when asleep.
+
+    <b>\#include</b> \<vigra/multi_array_chunked.hxx\> <br/>
+    Namespace: vigra
+
+    The present implementation uses a memory-mapped sparse file to store the chunks.
+    A sparse file is created on Linux using the O_TRUNC flag (this seems to be
+    the default file behavior on Linux anyway), and on Windows by
+    calling DeviceIoControl(file_handle, FSCTL_SET_SPARSE,...) after file creation.
+
+    The file is automatically deleted upon closing. On Windows, this happens
+    because the file was opened with FILE_FLAG_DELETE_ON_CLOSE in combination
+    with the flag FILE_ATTRIBUTE_TEMPORARY, which tells the OS to avoid writing
+    the file to disk if possible. (However, judging from the timings,
+    something is still written, or cleanup takes considerable time.)
+    On Linux, automated deletion is achieved via <tt>fileno(tmpfile())</tt>.
+*/
+template <unsigned int N, class T>
+class ChunkedArrayTmpFile
+: public ChunkedArray<N, T>
+{
+    /* REMARKS
+
+    Alternatives are:
+    * Don't create a file explicitly, but use the swap file instead. This is
+      achieved on Linux by mmap(..., MAP_PRIVATE | MAP_ANONYMOUS, -1, ...),
+      on Windows by calling CreateFileMapping(INVALID_HANDLE_VALUE, ...).
+       * On Linux, the memory must not be unmapped because this
+         looses the data. In fact, anonymous mmap() is very similar to
+         malloc(), and there is probably no good reason to use anonymous mmap().
+       * On Windows, this is much faster, because the OS will never try to
+         actually write something to disk (unless swapping is necessary).
+    */
+  public:
+#ifdef _WIN32
+    typedef HANDLE FileHandle;
+#else
+    typedef int FileHandle;
+#endif
+
+    class Chunk
+    : public ChunkBase<N, T>
+    {
+      public:
+        typedef typename MultiArrayShape<N>::type  shape_type;
+        typedef T value_type;
+        typedef value_type * pointer;
+        typedef value_type & reference;
+
+        Chunk(shape_type const & shape,
+              std::size_t offset, size_t alloc_size,
+              FileHandle file)
+        : ChunkBase<N, T>(detail::defaultStride(shape))
+        , offset_(offset)
+        , alloc_size_(alloc_size)
+        , file_(file)
+        {}
+
+        ~Chunk()
+        {
+            unmap();
+        }
+
+        pointer map()
+        {
+            if(this->pointer_ == 0)
+            {
+            #ifdef _WIN32
+                static const std::size_t bits = sizeof(DWORD)*8,
+                                         mask = (std::size_t(1) << bits) - 1;
+                this->pointer_ = (pointer)MapViewOfFile(file_, FILE_MAP_ALL_ACCESS,
+                                           std::size_t(offset_) >> bits, offset_ & mask, alloc_size_);
+                if(this->pointer_ == 0)
+                    winErrorToException("ChunkedArrayChunk::map(): ");
+            #else
+                this->pointer_ = (pointer)mmap(0, alloc_size_, PROT_READ | PROT_WRITE, MAP_SHARED,
+                                  file_, offset_);
+                if(this->pointer_ == 0)
+                    throw std::runtime_error("ChunkedArrayChunk::map(): mmap() failed.");
+            #endif
+            }
+            return this->pointer_;
+        }
+
+        void unmap()
+        {
+            if(this->pointer_ != 0)
+            {
+        #ifdef _WIN32
+                ::UnmapViewOfFile(this->pointer_);
+        #else
+                munmap(this->pointer_, alloc_size_);
+        #endif
+                this->pointer_ = 0;
+            }
+        }
+
+        std::size_t offset_, alloc_size_;
+        FileHandle file_;
+
+      private:
+        Chunk & operator=(Chunk const &);
+    };
+
+    typedef MultiArray<N, SharedChunkHandle<N, T>  > ChunkStorage;
+    typedef MultiArray<N, std::size_t>               OffsetStorage;
+    typedef typename ChunkStorage::difference_type   shape_type;
+    typedef T value_type;
+    typedef value_type * pointer;
+    typedef value_type & reference;
+
+    static std::size_t computeAllocSize(shape_type const & shape)
+    {
+        std::size_t size = prod(shape)*sizeof(T);
+        std::size_t mask = mmap_alignment - 1;
+        return (size + mask) & ~mask;
+    }
+
+    /** \brief Construct with given 'shape', 'chunk_shape' and 'options'.
+
+        If the optional 'path' is given, the file is created in this directory.
+        Otherwise (default), the path specified by the $TMP or $TEMP environment
+        variables (in that order) is used.
+    */
+    explicit ChunkedArrayTmpFile(shape_type const & shape,
+                                 shape_type const & chunk_shape=shape_type(),
+                                 ChunkedArrayOptions const & options = ChunkedArrayOptions(),
+                                 std::string const & path = "")
+    : ChunkedArray<N, T>(shape, chunk_shape, options)
+    #ifndef VIGRA_NO_SPARSE_FILE
+    , offset_array_(this->chunkArrayShape())
+    #endif
+    , file_size_()
+    , file_capacity_()
+    {
+    #ifdef VIGRA_NO_SPARSE_FILE
+        file_capacity_ = 4*prod(this->chunk_shape_)*sizeof(T);
+    #else
+        // compute offset in file
+        typename OffsetStorage::iterator i = offset_array_.begin(),
+                                         end = offset_array_.end();
+        std::size_t size = 0;
+        for(; i != end; ++i)
+        {
+            *i = size;
+            size += computeAllocSize(this->chunkShape(i.point()));
+        }
+        file_capacity_ = size;
+        this->overhead_bytes_ += offset_array_.size()*sizeof(std::size_t);
+        // std::cerr << "    file size: " << size << "\n";
+    #endif
+
+    #ifdef _WIN32
+        // create a temp file
+        file_ = ::CreateFile(winTempFileName(path).c_str(), GENERIC_READ | GENERIC_WRITE,
+                             0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
+        if (file_ == INVALID_HANDLE_VALUE)
+            winErrorToException("ChunkedArrayTmpFile(): ");
+
+        // make it a sparse file
+        DWORD dwTemp;
+        if(!::DeviceIoControl(file_, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, NULL))
+            winErrorToException("ChunkedArrayTmpFile(): ");
+
+        // place the data in the swap file
+        // file_ = INVALID_HANDLE_VALUE;
+
+        // resize and memory-map the file
+        static const std::size_t bits = sizeof(LONG)*8, mask = (std::size_t(1) << bits) - 1;
+        mappedFile_ = CreateFileMapping(file_, NULL, PAGE_READWRITE,
+                                        file_capacity_ >> bits, file_capacity_ & mask, NULL);
+        if(!mappedFile_)
+            winErrorToException("ChunkedArrayTmpFile(): ");
+    #else
+        mappedFile_ = file_ = fileno(tmpfile());
+        if(file_ == -1)
+            throw std::runtime_error("ChunkedArrayTmpFile(): unable to open file.");
+        lseek(file_, file_capacity_-1, SEEK_SET);
+        if(write(file_, "0", 1) == -1)
+            throw std::runtime_error("ChunkedArrayTmpFile(): unable to resize file.");
+    #endif
+    }
+
+    ~ChunkedArrayTmpFile()
+    {
+        typename ChunkStorage::iterator  i = this->handle_array_.begin(),
+                                         end = this->handle_array_.end();
+        for(; i != end; ++i)
+        {
+            if(i->pointer_)
+                delete static_cast<Chunk*>(i->pointer_);
+            i->pointer_ = 0;
+        }
+    #ifdef _WIN32
+        ::CloseHandle(mappedFile_);
+        ::CloseHandle(file_);
+    #else
+        ::close(file_);
+    #endif
+    }
+
+    virtual pointer loadChunk(ChunkBase<N, T> ** p, shape_type const & index)
+    {
+        if(*p == 0)
+        {
+            shape_type shape = this->chunkShape(index);
+            std::size_t chunk_size = computeAllocSize(shape);
+        #ifdef VIGRA_NO_SPARSE_FILE
+            std::size_t offset = file_size_;
+            if(offset + chunk_size > file_capacity_)
+            {
+                file_capacity_ = max<std::size_t>(offset+chunk_size, file_capacity_ * 120 / 100); // extend file by 20%
+                if(lseek(file_, file_capacity_-1, SEEK_SET) == -1)
+                    throw std::runtime_error("ChunkedArrayTmpFile(): unable to reset file size.");
+                if(write(file_, "0", 1) == -1)
+                    throw std::runtime_error("ChunkedArrayTmpFile(): unable to resize file.");
+            }
+            file_size_ += chunk_size;
+        #else
+            std::size_t offset = offset_array_[index];
+        #endif
+            *p = new Chunk(shape, offset, chunk_size, mappedFile_);
+            this->overhead_bytes_ += sizeof(Chunk);
+        }
+        return static_cast<Chunk*>(*p)->map();
+    }
+
+    virtual bool unloadChunk(ChunkBase<N, T> * chunk, bool /* destroy*/)
+    {
+        static_cast<Chunk *>(chunk)->unmap();
+        return false; // never destroys the data
+    }
+
+    virtual std::string backend() const
+    {
+        return "ChunkedArrayTmpFile";
+    }
+
+    virtual std::size_t dataBytes(ChunkBase<N,T> * c) const
+    {
+        return c->pointer_ == 0
+                 ? 0
+                 : static_cast<Chunk*>(c)->alloc_size_;
+    }
+
+    virtual std::size_t overheadBytesPerChunk() const
+    {
+      #ifdef VIGRA_NO_SPARSE_FILE
+        return sizeof(Chunk) + sizeof(SharedChunkHandle<N, T>);
+      #else
+        return sizeof(Chunk) + sizeof(SharedChunkHandle<N, T>) + sizeof(std::size_t);
+      #endif
+    }
+
+  #ifndef VIGRA_NO_SPARSE_FILE
+    OffsetStorage offset_array_;  // the array of chunks
+  #endif
+    FileHandle file_, mappedFile_;  // the file back-end
+    std::size_t file_size_, file_capacity_;
+};
+
+template<unsigned int N, class U>
+class ChunkIterator
+: public MultiCoordinateIterator<N>
+, private MultiArrayView<N, typename UnqualifiedType<U>::type>
+{
+  public:
+    typedef typename UnqualifiedType<U>::type      T;
+    typedef MultiCoordinateIterator<N>             base_type;
+    typedef MultiArrayView<N, T>                   base_type2;
+
+    typedef typename base_type::shape_type         shape_type;
+    typedef typename base_type::difference_type    difference_type;
+    typedef ChunkIterator                          iterator;
+    typedef std::random_access_iterator_tag        iterator_category;
+
+    typedef MultiArrayView<N, T>                   value_type;
+    typedef MultiArrayView<N, T> &                 reference;
+    typedef MultiArrayView<N, T> const &           const_reference;
+    typedef MultiArrayView<N, T> *                 pointer;
+    typedef MultiArrayView<N, T> const *           const_pointer;
+
+    typedef typename IfBool<UnqualifiedType<U>::isConst,
+                          ChunkedArrayBase<N, T> const,
+                          ChunkedArrayBase<N, T> >::type array_type;
+    typedef IteratorChunkHandle<N, T>        Chunk;
+
+
+    ChunkIterator()
+    : base_type()
+    , base_type2()
+    {}
+
+    ChunkIterator(array_type * array,
+                  shape_type const & start, shape_type const & end,
+                  shape_type const & chunk_start, shape_type const & chunk_end,
+                  shape_type const & chunk_shape)
+    : base_type(chunk_start, chunk_end)
+    , array_(array)
+    , chunk_(chunk_start * chunk_shape)
+    , start_(start - chunk_.offset_)
+    , stop_(end - chunk_.offset_)
+    , chunk_shape_(chunk_shape)
+    {
+        getChunk();
+    }
+
+    ChunkIterator(ChunkIterator const & rhs)
+    : base_type(rhs)
+    , base_type2(rhs)
+    , array_(rhs.array_)
+    , chunk_(rhs.chunk_)
+    , start_(rhs.start_)
+    , stop_(rhs.stop_)
+    , chunk_shape_(rhs.chunk_shape_)
+    {
+        getChunk();
+    }
+
+    ChunkIterator & operator=(ChunkIterator const & rhs)
+    {
+        if(this != &rhs)
+        {
+            base_type::operator=(rhs);
+            array_ = rhs.array_;
+            chunk_ = rhs.chunk_;
+            start_ = rhs.start_;
+            stop_ = rhs.stop_;
+            chunk_shape_ = rhs.chunk_shape_;
+            getChunk();
+        }
+        return *this;
+    }
+
+    reference operator*()
+    {
+        return *this;
+    }
+
+    const_reference operator*() const
+    {
+        return *this;
+    }
+
+    pointer operator->()
+    {
+        return this;
+    }
+
+    const_pointer operator->() const
+    {
+        return this;
+    }
+
+    value_type operator[](MultiArrayIndex i) const
+    {
+        return *(ChunkIterator(*this) += i);
+    }
+
+    value_type operator[](const shape_type &coordOffset) const
+    {
+        return *(ChunkIterator(*this) += coordOffset);
+    }
+
+    void getChunk()
+    {
+        if(array_)
+        {
+            shape_type array_point = max(start_, this->point()*chunk_shape_),
+                       upper_bound(SkipInitialization);
+            this->m_ptr = array_->chunkForIterator(array_point, this->m_stride, upper_bound, &chunk_);
+            this->m_shape = min(upper_bound, stop_) - array_point;
+        }
+    }
+
+    shape_type chunkStart() const
+    {
+        return max(start_, this->point()*chunk_shape_) + chunk_.offset_;
+    }
+
+    shape_type chunkStop() const
+    {
+        return chunkStart() + this->m_shape;
+    }
+
+    ChunkIterator & operator++()
+    {
+        base_type::operator++();
+        getChunk();
+        return *this;
+    }
+
+    ChunkIterator operator++(int)
+    {
+        ChunkIterator res(*this);
+        ++*this;
+        return res;
+    }
+
+    ChunkIterator & operator+=(MultiArrayIndex i)
+    {
+        base_type::operator+=(i);
+        getChunk();
+        return *this;
+    }
+
+    ChunkIterator & operator+=(const shape_type &coordOffset)
+    {
+        base_type::operator+=(coordOffset);
+        getChunk();
+        return *this;
+    }
+
+    ChunkIterator & operator--()
+    {
+        base_type::operator--();
+        getChunk();
+        return *this;
+    }
+
+    ChunkIterator operator--(int)
+    {
+        ChunkIterator res(*this);
+        --*this;
+        return res;
+    }
+
+    ChunkIterator & operator-=(MultiArrayIndex i)
+    {
+        return operator+=(-i);
+    }
+
+    ChunkIterator & operator-=(const shape_type &coordOffset)
+    {
+        return operator+=(-coordOffset);
+    }
+
+    ChunkIterator getEndIterator() const
+    {
+        ChunkIterator res(*this);
+        static_cast<base_type &>(res) = base_type::getEndIterator();
+        res.getChunk();
+        return res;
+    }
+
+    ChunkIterator operator+(MultiArrayIndex d) const
+    {
+        return ChunkIterator(*this) += d;
+    }
+
+    ChunkIterator operator-(MultiArrayIndex d) const
+    {
+        return ChunkIterator(*this) -= d;
+    }
+
+    ChunkIterator operator+(const shape_type &coordOffset) const
+    {
+        return ChunkIterator(*this) += coordOffset;
+    }
+
+    ChunkIterator operator-(const shape_type &coordOffset) const
+    {
+        return ChunkIterator(*this) -= coordOffset;
+    }
+
+    MultiArrayIndex operator-(const ChunkIterator & other) const
+    {
+        return base_type::operator-(other);
+    }
+
+#ifndef DOXYGEN  // doxygen doesn't understand this
+    using base_type::operator==;
+    using base_type::operator!=;
+#endif
+    using base_type::shape;
+
+    array_type * array_;
+    Chunk chunk_;
+    shape_type start_, stop_, chunk_shape_, array_point_;
+};
+
+//@}
+
+} // namespace vigra
+
+#undef VIGRA_ASSERT_INSIDE
+
+#endif /* VIGRA_MULTI_ARRAY_CHUNKED_HXX */
diff --git a/include/vigra/multi_array_chunked_hdf5.hxx b/include/vigra/multi_array_chunked_hdf5.hxx
new file mode 100644
index 0000000..65eefa8
--- /dev/null
+++ b/include/vigra/multi_array_chunked_hdf5.hxx
@@ -0,0 +1,463 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2012-2014 by Ullrich Koethe and Thorben Kroeger        */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_MULTI_ARRAY_CHUNKED_HDF5_HXX
+#define VIGRA_MULTI_ARRAY_CHUNKED_HDF5_HXX
+
+#include <queue>
+
+#include "multi_array_chunked.hxx"
+#include "hdf5impex.hxx"
+
+// Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined.
+#ifdef VIGRA_CHECK_BOUNDS
+#define VIGRA_ASSERT_INSIDE(diff) \
+  vigra_precondition(this->isInside(diff), "Index out of bounds")
+#else
+#define VIGRA_ASSERT_INSIDE(diff)
+#endif
+
+namespace vigra {
+
+/** \addtogroup ChunkedArrayClasses
+*/
+//@{
+
+/** Implement ChunkedArray as a chunked dataset in an HDF5 file.
+
+    <b>\#include</b> \<vigra/multi_array_chunked_hdf5.hxx\> <br/>
+    Namespace: vigra
+
+    This uses the native chunking and compression functionality provided by the
+    HDF5 library. Note: This file must only be included when the HDF5 headers
+    and libraries are installed on the system.
+*/
+template <unsigned int N, class T, class Alloc = std::allocator<T> >
+class ChunkedArrayHDF5
+: public ChunkedArray<N, T>
+{
+    /* REMARKS
+    Alternatives are:
+    * Back chunks by HDF5 chunks, possibly using on-the-fly compression. This
+      is in particular useful for existing HDF5 files.
+    * Back chunks by HDF5 datasets. This can be combined with compression
+      (both explicit and on-the-fly) or with memory mapping (using the
+      function H5Dget_offset() to get the offset from the beginning of the file).
+    */
+
+  public:
+
+    class Chunk
+    : public ChunkBase<N, T>
+    {
+      public:
+        typedef typename MultiArrayShape<N>::type  shape_type;
+        typedef T value_type;
+        typedef value_type * pointer;
+        typedef value_type & reference;
+
+        Chunk(shape_type const & shape, shape_type const & start,
+              ChunkedArrayHDF5 * array, Alloc const & alloc)
+        : ChunkBase<N, T>(detail::defaultStride(shape))
+        , shape_(shape)
+        , start_(start)
+        , array_(array)
+        , alloc_(alloc)
+        {}
+
+        ~Chunk()
+        {
+            write();
+        }
+
+        std::size_t size() const
+        {
+            return prod(shape_);
+        }
+
+        void write(bool deallocate = true)
+        {
+            if(this->pointer_ != 0)
+            {
+                if(!array_->file_.isReadOnly())
+                {
+                    herr_t status = array_->file_.writeBlock(array_->dataset_, start_,
+                                          MultiArrayView<N, T>(shape_, this->strides_, this->pointer_));
+                    vigra_postcondition(status >= 0,
+                        "ChunkedArrayHDF5: write to dataset failed.");
+                }
+                if(deallocate)
+                {
+                    alloc_.deallocate(this->pointer_, this->size());
+                    this->pointer_ = 0;
+                }
+            }
+        }
+
+        pointer read()
+        {
+            if(this->pointer_ == 0)
+            {
+                this->pointer_ = alloc_.allocate(this->size());
+                herr_t status = array_->file_.readBlock(array_->dataset_, start_, shape_,
+                                     MultiArrayView<N, T>(shape_, this->strides_, this->pointer_));
+                vigra_postcondition(status >= 0,
+                    "ChunkedArrayHDF5: read from dataset failed.");
+            }
+            return this->pointer_;
+        }
+
+        shape_type shape_, start_;
+        ChunkedArrayHDF5 * array_;
+        Alloc alloc_;
+
+      private:
+        Chunk & operator=(Chunk const &);
+    };
+
+    typedef ChunkedArray<N, T> base_type;
+    typedef MultiArray<N, SharedChunkHandle<N, T> > ChunkStorage;
+    typedef typename ChunkStorage::difference_type  shape_type;
+    typedef T value_type;
+    typedef value_type * pointer;
+    typedef value_type & reference;
+
+    /** \brief Construct with given 'shape', 'chunk_shape' and 'options',
+        using 'alloc' to manage the in-memory version of the data..
+
+        The data are placed in 'file' at the internal path 'dataset'. Argument
+        'mode' must be one of the following:
+        <ul>
+        <li>HDF5File::New: Create new dataset, possibly deleting any existing content.
+                           It is an error to request this mode when the entire
+                           'file' is read-only.
+        <li>HDF5File::Replace: Same as New.
+        <li>HDF5File::ReadWrite: Open the dataset for reading and writing. Create
+                                 the datset if it doesn't exist. It is an error
+                                 to request this mode when 'file' is read-only.
+        <li>HDF5File::ReadOnly: Open the dataset for reading. It is an error to
+                                request this mode when the dataset doesn't exist.
+        <li>HDF5File::Default: Resolves to ReadOnly when the dataset exists, and
+                               to New otherwise.
+        </ul>
+        The supported compression algorithms are:
+        <ul>
+        <li>ZLIB_FAST: Fast compression using 'zlib' (slower than LZ4, but higher compression).
+        <li>ZLIB_BEST: Best compression using 'zlib', slow.
+        <li>ZLIB_NONE: Use 'zlib' format without compression.
+        <li>DEFAULT_COMPRESSION: Same as ZLIB_FAST.
+        </ul>
+    */
+    ChunkedArrayHDF5(HDF5File const & file, std::string const & dataset,
+                     HDF5File::OpenMode mode,
+                     shape_type const & shape,
+                     shape_type const & chunk_shape=shape_type(),
+                     ChunkedArrayOptions const & options = ChunkedArrayOptions(),
+                     Alloc const & alloc = Alloc())
+    : ChunkedArray<N, T>(shape, chunk_shape, options),
+      file_(file),
+      dataset_name_(dataset),
+      dataset_(),
+      compression_(options.compression_method),
+      alloc_(alloc)
+    {
+        init(mode);
+    }
+
+    /** \brief Construct for an already existing dataset with given 'options',
+        using 'alloc' to manage the in-memory version of the data.
+
+        The data must be located in 'file' at the internal path 'dataset'. The
+        array's shape and chunk_shape are read from the file. It is an error
+        to use this constructor when 'dataset' doesn't exist.
+
+        Argument 'mode' must be one of the following:
+        <ul>
+        <li>HDF5File::ReadWrite: Open the dataset for reading and writing. It is an error
+                                 to request this mode when 'file' is read-only.
+        <li>HDF5File::ReadOnly: Open the dataset for reading (default).
+        <li>HDF5File::Default: Same as ReadOnly.
+        </ul>
+        The supported compression algorithms are:
+        <ul>
+        <li>ZLIB_FAST: Fast compression using 'zlib' (slower than LZ4, but higher compression).
+        <li>ZLIB_BEST: Best compression using 'zlib', slow.
+        <li>ZLIB_NONE: Use 'zlib' format without compression.
+        <li>DEFAULT_COMPRESSION: Same as ZLIB_FAST.
+        </ul>
+    */
+    ChunkedArrayHDF5(HDF5File const & file, std::string const & dataset,
+                     HDF5File::OpenMode mode = HDF5File::ReadOnly,
+                     ChunkedArrayOptions const & options = ChunkedArrayOptions(),
+                     Alloc const & alloc = Alloc())
+    : ChunkedArray<N, T>(shape_type(), shape_type(), options),
+      file_(file),
+      dataset_name_(dataset),
+      dataset_(),
+      compression_(options.compression_method),
+      alloc_(alloc)
+    {
+        init(mode);
+    }
+
+    void init(HDF5File::OpenMode mode)
+    {
+        bool exists = file_.existsDataset(dataset_name_);
+
+        if(mode == HDF5File::Replace)
+        {
+            mode = HDF5File::New;
+        }
+        else if(mode == HDF5File::Default)
+        {
+            if(exists)
+                mode = HDF5File::ReadOnly;
+            else
+                mode = HDF5File::New;
+        }
+
+        if(mode == HDF5File::ReadOnly)
+            file_.setReadOnly();
+        else
+            vigra_precondition(!file_.isReadOnly(),
+                "ChunkedArrayHDF5(): 'mode' is incompatible with read-only file.");
+
+        vigra_precondition(exists || !file_.isReadOnly(),
+            "ChunkedArrayHDF5(): dataset does not exist, but file is read-only.");
+
+        if(!exists || mode == HDF5File::New)
+        {
+            // FIXME: set rdcc_nbytes to 0 (disable cache, because we don't
+            //        need two caches
+            // H5Pset_chunk_cache (dapl, rdcc_nslots, rdcc_nbytes, rdcc_w0);
+            // Chunk cache size (rdcc_nbytes) should be large
+            // enough to hold all the chunks in a selection
+            // • If this is not possible, it may be best to disable chunk
+            // caching altogether (set rdcc_nbytes to 0)
+            // • rdcc_slots should be a prime number that is at
+            // least 10 to 100 times the number of chunks that can fit
+            // into rdcc_nbytes
+            // • rdcc_w0 should be set to 1 if chunks that have been
+            // fully read/written will never be read/written again
+            //
+            // the above may be WRONG in general - it may only apply if the
+            // chunk size in the file matches the chunk size in the CachedArray.
+            // Otherwise, make sure that the file cache can hold at least as many
+            // chunks as are needed for a single array chunk.
+            if(compression_ == DEFAULT_COMPRESSION)
+                compression_ = ZLIB_FAST;
+            vigra_precondition(compression_ != LZ4,
+                "ChunkedArrayHDF5(): HDF5 does not support LZ4 compression.");
+
+            vigra_precondition(this->size() > 0,
+                "ChunkedArrayHDF5(): invalid shape.");
+            typename detail::HDF5TypeTraits<T>::value_type init(this->fill_scalar_);
+            dataset_ = file_.createDataset<N, T>(dataset_name_,
+                                                 this->shape_,
+                                                 init,
+                                                 this->chunk_shape_,
+                                                 compression_);
+        }
+        else
+        {
+            dataset_ = file_.getDatasetHandleShared(dataset_name_);
+
+            // check shape
+            ArrayVector<hsize_t> fileShape(file_.getDatasetShape(dataset_name_));
+            typedef detail::HDF5TypeTraits<T> TypeTraits;
+            if(TypeTraits::numberOfBands() > 1)
+            {
+                vigra_precondition(fileShape.size() == N+1,
+                    "ChunkedArrayHDF5(file, dataset): dataset has wrong dimension.");
+                vigra_precondition(fileShape[0] == TypeTraits::numberOfBands(),
+                    "ChunkedArrayHDF5(file, dataset): dataset has wrong number of bands.");
+                shape_type shape(fileShape.begin()+1);
+                if(this->size() > 0)
+                {
+                    vigra_precondition(shape == this->shape_,
+                        "ChunkedArrayHDF5(file, dataset, shape): shape mismatch between dataset and shape argument.");
+                }
+                else
+                {
+                    this->shape_ = shape;
+                }
+            }
+            else
+            {
+                vigra_precondition(fileShape.size() == N,
+                    "ChunkedArrayHDF5(file, dataset): dataset has wrong dimension.");
+                shape_type shape(fileShape.begin());
+                if(this->size() > 0)
+                {
+                    vigra_precondition(shape == this->shape_,
+                        "ChunkedArrayHDF5(file, dataset, shape): shape mismatch between dataset and shape argument.");
+                }
+                else
+                {
+                    this->shape_ = shape;
+                    ChunkStorage(detail::computeChunkArrayShape(shape, this->bits_, this->mask_)).swap(this->handle_array_);
+                }
+            }
+            typename ChunkStorage::iterator i   = this->handle_array_.begin(),
+                                            end = this->handle_array_.end();
+            for(; i != end; ++i)
+            {
+                i->chunk_state_.store(base_type::chunk_asleep);
+            }
+        }
+    }
+
+    ~ChunkedArrayHDF5()
+    {
+        closeImpl(true);
+    }
+
+    void close()
+    {
+        closeImpl(false);
+    }
+
+    void closeImpl(bool force_destroy)
+    {
+        flushToDiskImpl(true, force_destroy);
+        file_.close();
+    }
+
+    void flushToDisk()
+    {
+        flushToDiskImpl(false, false);
+    }
+
+    void flushToDiskImpl(bool destroy, bool force_destroy)
+    {
+        if(file_.isReadOnly())
+            return;
+
+        threading::lock_guard<threading::mutex> guard(*this->chunk_lock_);
+        typename ChunkStorage::iterator i   = this->handle_array_.begin(),
+                                        end = this->handle_array_.end();
+        if(destroy && !force_destroy)
+        {
+            for(; i != end; ++i)
+            {
+                vigra_precondition(i->chunk_state_.load() <= 0,
+                    "ChunkedArrayHDF5::close(): cannot close file because there are active chunks.");
+            }
+            i   = this->handle_array_.begin();
+        }
+        for(; i != end; ++i)
+        {
+            Chunk * chunk = static_cast<Chunk*>(i->pointer_);
+            if(!chunk)
+                continue;
+            if(destroy)
+            {
+                delete chunk;
+                i->pointer_ = 0;
+            }
+            else
+            {
+                chunk->write(false);
+            }
+        }
+        file_.flushToDisk();
+    }
+
+    virtual bool isReadOnly() const
+    {
+        return file_.isReadOnly();
+    }
+
+    virtual pointer loadChunk(ChunkBase<N, T> ** p, shape_type const & index)
+    {
+        vigra_precondition(file_.isOpen(),
+            "ChunkedArrayHDF5::loadChunk(): file was already closed.");
+        if(*p == 0)
+        {
+            *p = new Chunk(this->chunkShape(index), index*this->chunk_shape_, this, alloc_);
+            this->overhead_bytes_ += sizeof(Chunk);
+        }
+        return static_cast<Chunk *>(*p)->read();
+    }
+
+    virtual bool unloadChunk(ChunkBase<N, T> * chunk, bool /* destroy */)
+    {
+        if(!file_.isOpen())
+            return true;
+        static_cast<Chunk *>(chunk)->write();
+        return false;
+    }
+
+    virtual std::string backend() const
+    {
+        return "ChunkedArrayHDF5<'" + file_.filename() + "/" + dataset_name_ + "'>";
+    }
+
+    virtual std::size_t dataBytes(ChunkBase<N,T> * c) const
+    {
+        return c->pointer_ == 0
+                 ? 0
+                 : static_cast<Chunk*>(c)->size()*sizeof(T);
+    }
+
+    virtual std::size_t overheadBytesPerChunk() const
+    {
+        return sizeof(Chunk) + sizeof(SharedChunkHandle<N, T>);
+    }
+
+    std::string fileName() const
+    {
+        return file_.filename();
+    }
+
+    std::string datasetName() const
+    {
+        return dataset_name_;
+    }
+
+    HDF5File file_;
+    std::string dataset_name_;
+    HDF5HandleShared dataset_;
+    CompressionMethod compression_;
+    Alloc alloc_;
+};
+
+//@}
+
+} // namespace vigra
+
+#undef VIGRA_ASSERT_INSIDE
+
+#endif /* VIGRA_MULTI_ARRAY_CHUNKED_HDF5_HXX */
diff --git a/include/vigra/multi_blocking.hxx b/include/vigra/multi_blocking.hxx
new file mode 100644
index 0000000..6559ceb
--- /dev/null
+++ b/include/vigra/multi_blocking.hxx
@@ -0,0 +1,345 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2015 by Thorsten Beier                       */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_MULTI_BLOCKING_HXX
+#define VIGRA_MULTI_BLOCKING_HXX
+
+#include "vigra/tinyvector.hxx"
+#include "vigra/box.hxx"
+#include "vigra/multi_iterator.hxx"
+#include "vigra/multi_convolution.hxx"
+#include "vigra/transform_iterator.hxx"
+
+namespace vigra{
+
+    // forward declaration
+    template<unsigned int DIM, class C>
+    class MultiBlocking;
+
+    /// \cond
+    namespace detail_multi_blocking{
+
+        template<unsigned int DIM, class C>
+        class BlockWithBorder{
+        public:
+            typedef C  PointValue;
+            typedef TinyVector<PointValue, DIM> Point;
+            typedef Point Shape;
+            typedef Box<PointValue, DIM> Block;
+            typedef MultiCoordinateIterator< DIM> MultiCoordIter;
+
+            BlockWithBorder(const Block & core = Block(), const Block & border = Block())
+            :   core_(core),
+                border_(border){
+            }
+
+            /// get the core block
+            const Block & core()const{
+                return core_;
+            }
+
+            Block  localCore()const{
+                return core_-border_.begin();
+            }
+
+
+            const Block & border()const{
+                return border_;
+            }
+
+            bool operator == (const BlockWithBorder & rhs) const{
+                return core_ == rhs.core_ && border_ == rhs.border_;
+            }
+            bool operator != (const BlockWithBorder & rhs) const{
+                return core_ != rhs.core_ || border_ != rhs.border_;
+            }
+
+        private:
+            Block core_;
+            Block border_;
+        };
+
+        template<class VALUETYPE, unsigned int DIMENSION>
+        std::ostream& operator<< (std::ostream& stream, const BlockWithBorder<DIMENSION,VALUETYPE> & bwb) {
+            stream<<"["<<bwb.core()<<", "<<bwb.border()<<" ]";
+            return stream;
+        }
+
+
+        template<class MB>
+        class MultiCoordToBlockWithBoarder{
+        public:
+            typedef typename MB::Shape Shape;
+            typedef typename MB::BlockDesc BlockDesc;
+            typedef typename MB::BlockWithBorder result_type;
+            MultiCoordToBlockWithBoarder()
+            :   mb_(NULL),
+                width_(){
+            }
+            MultiCoordToBlockWithBoarder(const MB & mb, const Shape & width)
+            :   mb_(&mb),
+                width_(width){
+            }
+
+            result_type operator()(const BlockDesc & blockDesc)const{
+                return mb_->getBlockWithBorder(blockDesc, width_);
+            }
+        private:
+            const MB * mb_;
+            Shape width_;
+        };
+
+        template<class MB>
+        class MultiCoordToBlock{
+        public:
+            typedef typename MB::Shape Shape;
+            typedef typename MB::BlockDesc BlockDesc;
+            typedef typename MB::Block result_type;
+            MultiCoordToBlock()
+            :   mb_(NULL){
+            }
+            MultiCoordToBlock(const MB & mb)
+            :   mb_(&mb){
+            }
+
+            result_type operator()(const BlockDesc & blockDesc)const{
+                return mb_->getBlock(blockDesc);
+            }
+        private:
+            const MB * mb_;
+        };
+    }
+    /// \endcond
+    
+
+    /**
+        MultiBlocking is used to split a image / volume / multiarray
+        into non-overlapping blocks.
+        These non overlapping blocks are called cores.
+        A border can be added to the core boxes.
+        These 'core+border' blocks are just called border.
+        The core block within the coordinate system 
+        of the border block is called local core.
+    */
+    template<unsigned int DIM, class C = MultiArrayIndex>
+    class MultiBlocking{
+    public:
+        typedef MultiBlocking<DIM, C> SelfType;
+        friend class detail_multi_blocking::MultiCoordToBlock<SelfType>;
+        friend class detail_multi_blocking::MultiCoordToBlockWithBoarder<SelfType>;
+        typedef C  PointValue;
+        typedef TinyVector<PointValue, DIM> Point;
+        typedef Point Shape;
+        typedef Point BlockDesc;
+        typedef Box<PointValue, DIM> Block;
+        typedef MultiCoordinateIterator< DIM> MultiCoordIter;
+        typedef detail_multi_blocking::BlockWithBorder<DIM, PointValue> BlockWithBorder;
+
+
+        // iterators 
+        typedef detail_multi_blocking::MultiCoordToBlockWithBoarder<SelfType> CoordToBwb;
+        typedef detail_multi_blocking::MultiCoordToBlock<SelfType> CoordToB;
+        typedef EndAwareTransformIterator<CoordToBwb, MultiCoordIter> BlockWithBorderIter;
+        typedef EndAwareTransformIterator<CoordToB,   MultiCoordIter> BlockIter;
+
+
+        MultiBlocking(const Shape & shape,
+                      const Shape & blockShape,
+                      const Shape & roiBegin = Shape(0),
+                      const Shape & roiEnd = Shape(0)
+        )
+        :   shape_(shape),
+            roiBlock_(roiBegin,roiEnd == Shape(0) ? shape : roiEnd),
+            blockShape_(blockShape),
+            blocksPerAxis_(vigra::SkipInitialization),
+            numBlocks_(1)
+        {
+            const Shape roiShape = roiBlock_.size();
+            blocksPerAxis_ = roiShape / blockShape_;
+
+
+            // blocking
+            for(size_t d=0; d<DIM; ++d){
+                if(blocksPerAxis_[d]*blockShape_[d] < roiShape[d] ){
+                    ++blocksPerAxis_[d];
+                }
+                numBlocks_ *= blocksPerAxis_[d];
+            }
+
+            // total image border blocks
+            Shape beginCA(0),endCB(shape);
+            for(size_t d=0; d<DIM; ++d){
+                {
+                    // fix coordinate d to zero
+                    Shape endCA(shape);
+                    endCA[d] = 1;
+                    volumeBorderBlocks_.push_back(Block(beginCA,endCA));
+                }
+                {
+                    // fix coordinate d to shape[dim]-1
+                    Shape beginCB(shape);
+                    beginCB[d] -= 1;
+                    volumeBorderBlocks_.push_back(Block(beginCB,endCB));
+                }
+            }
+
+            insideVolBlock_.setBegin(Shape(1));
+            Shape insideVolBlockShapeEnd(shape);
+            insideVolBlockShapeEnd -= Shape(1);
+            insideVolBlock_.setEnd(insideVolBlockShapeEnd);
+        }
+
+        /// total number of blocks
+        size_t numBlocks()const{
+            return numBlocks_;
+        }
+
+        BlockWithBorderIter blockWithBorderBegin(const Shape & width)const{
+            return BlockWithBorderIter(MultiCoordIter(blocksPerAxis_),
+                                       CoordToBwb(*this, width));
+        }
+
+        BlockWithBorderIter blockWithBorderEnd(const Shape & width)const{
+            const MultiCoordIter beginIter(blocksPerAxis_);
+            return BlockWithBorderIter(beginIter.getEndIterator(),
+                                       CoordToBwb(*this, width));
+        }
+
+        Block blockDescToBlock(const BlockDesc & desc){
+            MultiCoordIter beginIter(blocksPerAxis_);
+            beginIter+=desc;
+            return *BlockIter(beginIter,CoordToB(*this));
+        }
+        BlockIter blockBegin()const{
+            return BlockIter(MultiCoordIter(blocksPerAxis_),CoordToB(*this));
+        }
+
+
+        BlockIter blockEnd()const{
+            const MultiCoordIter beginIter(blocksPerAxis_);
+            return BlockIter(beginIter.getEndIterator(),CoordToB(*this));
+        }
+
+
+        Block blockDescToBlock(const BlockDesc & blockDesc)const{
+            MultiCoordIter iter(blocksPerAxis_);
+            iter+=blockDesc;
+            return *BlockIter(iter,CoordToB(*this));
+        }
+
+
+        /// does this block intersect with the volume border
+        bool containsVolumeBorder(const Block & block) const {
+            return !insideVolBlock_.contains(block);
+        }
+
+
+        const Shape & roiBegin()const{
+            return roiBlock_.begin();
+        }
+
+        const Shape & roiEnd()const{
+            return roiBlock_.end();
+        }
+
+        const Shape & shape()const{
+            return shape_;
+        }
+
+        const Shape & blockShape()const{
+            return blockShape_;
+        }
+
+        const Shape & blocksPerAxis()const{
+            return blocksPerAxis_;
+        }
+
+        const std::vector<Block> & volumeBorderBlocks()const{
+            return volumeBorderBlocks_;
+        }
+
+
+        std::vector<UInt32> intersectingBlocks(
+            const Shape roiBegin,
+            const Shape roiEnd
+        )const{
+            size_t i=0;
+            std::vector<UInt32> iBlocks;
+            const Block testBlock(roiBegin, roiEnd);
+            for(BlockIter iter=blockBegin(); iter!=blockEnd(); ++iter){
+                if(testBlock.intersects(*iter)){
+                    iBlocks.push_back(i);
+                }
+                ++i;
+            }
+            return std::move(iBlocks);
+        }
+
+
+
+    private:
+
+        /// get a block with border
+        BlockWithBorder getBlockWithBorder(const BlockDesc & blockDesc, const Shape & width )const{
+            const Point blockStart(blockDesc * blockShape_ + roiBlock_.begin());
+            const Point blockEnd(blockStart + blockShape_);
+            const Block core = Block(blockStart, blockEnd) & roiBlock_ ;
+            Block border = core;
+            border.addBorder(width);
+            border &= Block(shape_);
+            return BlockWithBorder( core, border );
+        }
+
+        /// get a block (without any overlap)
+        Block getBlock(const BlockDesc & blockDesc)const{
+            const Point blockStart(blockDesc * blockShape_ + roiBlock_.begin());
+            const Point blockEnd(blockStart + blockShape_);
+            return Block(blockStart, blockEnd) & roiBlock_;
+        }
+
+        Shape shape_;           // total shape of the input volume
+        Block roiBlock_;        // ROI in which to compute filters/algorithms
+        Shape blockShape_;      // shape sub-block for each thread (without border pixels)
+        Shape blocksPerAxis_;   // how many blocks are on each axis
+        size_t numBlocks_;      // total number of blocks
+
+
+        std::vector<Block> volumeBorderBlocks_;
+        Block insideVolBlock_;
+    };
+
+}
+
+#endif // VIGRA_MULTI_BLOCKING_HXX
diff --git a/include/vigra/multi_blockwise.hxx b/include/vigra/multi_blockwise.hxx
new file mode 100644
index 0000000..a2f83d7
--- /dev/null
+++ b/include/vigra/multi_blockwise.hxx
@@ -0,0 +1,463 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2015 by Thorsten Beier                       */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+
+#ifndef VIGRA_MULTI_BLOCKWISE_HXX
+#define VIGRA_MULTI_BLOCKWISE_HXX
+
+#include <cmath>
+#include <vector>
+#include "multi_blocking.hxx"
+#include "multi_convolution.hxx"
+#include "multi_tensorutilities.hxx"
+#include "threadpool.hxx"
+#include "array_vector.hxx"
+
+namespace vigra{
+
+    /** Option base class for blockwise algorithms.
+
+        Attaches blockshape to ParallelOptions.
+    */
+class BlockwiseOptions
+: public ParallelOptions
+{
+public:
+    typedef ArrayVector<MultiArrayIndex> Shape;
+
+    BlockwiseOptions()
+    :   ParallelOptions()
+    ,   blockShape_()
+    {}
+
+        /** Retrieve block shape as a std::vector.
+
+            If the returned vector is empty, a default block shape should be used.
+            If the returned vector has length 1, square blocks of size
+            <tt>getBlockShape()[0]</tt> should be used.
+        */
+    Shape const & getBlockShape() const
+    {
+        return blockShape_;
+    }
+
+        // for Python bindings
+    Shape readBlockShape() const
+    {
+        return blockShape_;
+    }
+
+        /** Retrieve block shape as a fixed-size vector.
+
+            Default shape specifications are appropriately expanded.
+            An exception is raised if the stored shape's length is
+            incompatible with dimension <tt>N</tt>.
+        */
+    template <int N>
+    TinyVector<MultiArrayIndex, N> getBlockShapeN() const
+    {
+        if(blockShape_.size() > 1)
+        {
+            vigra_precondition(blockShape_.size() == (size_t)N,
+                "BlockwiseOptions::getBlockShapeN(): dimension mismatch between N and stored block shape.");
+            return TinyVector<MultiArrayIndex, N>(blockShape_.data());
+        }
+        else if(blockShape_.size() == 1)
+        {
+            return TinyVector<MultiArrayIndex, N>(blockShape_[0]);
+        }
+        else
+        {
+            return detail::ChunkShape<N>::defaultShape();
+        }
+    }
+
+        /** Specify block shape as a std::vector of appropriate length.
+            If <tt>blockShape.size() == 0</tt>, the default shape is used.
+            If <tt>blockShape.size() == 1</tt>, square blocks of size
+            <tt>blockShape[0]</tt> are used.
+
+            Default: Use square blocks with side length <tt>VIGRA_DEFAULT_BLOCK_SHAPE</tt>.
+        */
+    BlockwiseOptions & blockShape(const Shape & blockShape){
+        blockShape_ = blockShape;
+        return *this;
+    }
+
+        // for Python bindings
+    void setBlockShape(const Shape & blockShape){
+        blockShape_ = blockShape;
+    }
+
+        /** Specify block shape by a fixed-size shape object.
+        */
+    template <class T, int N>
+    BlockwiseOptions & blockShape(const TinyVector<T, N> & blockShape){
+        Shape(blockShape.begin(), blockShape.end()).swap(blockShape_);
+        return *this;
+    }
+
+        /** Specify square block shape by its side length.
+        */
+    BlockwiseOptions & blockShape(MultiArrayIndex blockShape){
+        Shape(1, blockShape).swap(blockShape_);
+        return *this;
+    }
+
+    BlockwiseOptions & numThreads(const int n)
+    {
+        ParallelOptions::numThreads(n);
+        return *this;
+    }
+
+    void setNumThreads(const int n)
+    {
+        ParallelOptions::numThreads(n);
+    }
+
+private:
+    Shape blockShape_;
+};
+
+    /** Option class for blockwise convolution algorithms.
+
+        Simply derives from \ref vigra::BlockwiseOptions and
+        \ref vigra::ConvolutionOptions to join their capabilities.
+    */
+template<unsigned int N>
+class BlockwiseConvolutionOptions
+:   public  BlockwiseOptions
+,   public  ConvolutionOptions<N>{
+public:
+    BlockwiseConvolutionOptions()
+    :   BlockwiseOptions(),
+        ConvolutionOptions<N>()
+    {}
+};
+
+
+namespace blockwise{
+
+    /**
+        helper function to create blockwise parallel filters.
+        This implementation should be used if the filter functor
+        does not support the ROI/sub array options.
+    */
+    template<
+        unsigned int DIM,
+        class T_IN, class ST_IN,
+        class T_OUT, class ST_OUT,
+        class FILTER_FUNCTOR,
+        class C
+    >
+    void blockwiseCallerNoRoiApi(
+        const vigra::MultiArrayView<DIM, T_IN,  ST_IN > & source,
+        const vigra::MultiArrayView<DIM, T_OUT, ST_OUT> & dest,
+        FILTER_FUNCTOR & functor,
+        const vigra::MultiBlocking<DIM, C> & blocking,
+        const typename vigra::MultiBlocking<DIM, C>::Shape & borderWidth,
+        const BlockwiseConvolutionOptions<DIM>  & options
+    ){
+
+        typedef typename MultiBlocking<DIM, C>::BlockWithBorder BlockWithBorder;
+
+        auto beginIter  =  blocking.blockWithBorderBegin(borderWidth);
+        auto endIter   =  blocking.blockWithBorderEnd(borderWidth);
+
+        parallel_foreach(options.getNumThreads(),
+            beginIter, endIter,
+            [&](const int threadId, const BlockWithBorder bwb)
+            {
+                // get the input of the block as a view
+                vigra::MultiArrayView<DIM, T_IN, ST_IN> sourceSub = source.subarray(bwb.border().begin(),
+                                                                             bwb.border().end());
+                // get the output as NEW allocated array
+                vigra::MultiArray<DIM, T_OUT> destSub(sourceSub.shape());
+                // call the functor
+                functor(sourceSub, destSub);
+                 // write the core global out
+                vigra::MultiArrayView<DIM, T_OUT, ST_OUT> destSubCore = destSub.subarray(bwb.localCore().begin(),
+                                                                                bwb.localCore().end());
+                // write the core global out
+                dest.subarray(bwb.core().begin()-blocking.roiBegin(),
+                              bwb.core().end()  -blocking.roiBegin()  ) = destSubCore;
+            },
+            blocking.numBlocks()
+        );
+
+    }
+
+    /**
+        helper function to create blockwise parallel filters.
+        This implementation should be used if the filter functor
+        does support the ROI/sub array options.
+    */
+    template<
+        unsigned int DIM,
+        class T_IN, class ST_IN,
+        class T_OUT, class ST_OUT,
+        class FILTER_FUNCTOR,
+        class C
+    >
+    void blockwiseCaller(
+        const vigra::MultiArrayView<DIM, T_IN,  ST_IN > & source,
+        const vigra::MultiArrayView<DIM, T_OUT, ST_OUT> & dest,
+        FILTER_FUNCTOR & functor,
+        const vigra::MultiBlocking<DIM, C> & blocking,
+        const typename vigra::MultiBlocking<DIM, C>::Shape & borderWidth,
+        const BlockwiseConvolutionOptions<DIM>  & options
+    ){
+
+        typedef typename MultiBlocking<DIM, C>::BlockWithBorder BlockWithBorder;
+        //typedef typename MultiBlocking<DIM, C>::BlockWithBorderIter BlockWithBorderIter;
+        typedef typename MultiBlocking<DIM, C>::Block Block;
+
+
+        auto beginIter  =  blocking.blockWithBorderBegin(borderWidth);
+        auto endIter   =  blocking.blockWithBorderEnd(borderWidth);
+
+        parallel_foreach(options.getNumThreads(),
+            beginIter, endIter,
+            [&](const int threadId, const BlockWithBorder bwb)
+            {
+                // get the input of the block as a view
+                vigra::MultiArrayView<DIM, T_IN, ST_IN> sourceSub = source.subarray(bwb.border().begin(),
+                                                                            bwb.border().end());
+                // get the output of the blocks core as a view
+                vigra::MultiArrayView<DIM, T_OUT, ST_OUT> destCore = dest.subarray(bwb.core().begin(),
+                                                                            bwb.core().end());
+                const Block localCore =  bwb.localCore();
+                // call the functor
+                functor(sourceSub, destCore, localCore.begin(), localCore.end());
+            },
+            blocking.numBlocks()
+        );
+
+
+    }
+
+    #define CONVOLUTION_FUNCTOR(FUNCTOR_NAME, FUNCTION_NAME) \
+    template<unsigned int DIM> \
+    class FUNCTOR_NAME{ \
+    public: \
+        typedef ConvolutionOptions<DIM> ConvOpt; \
+        FUNCTOR_NAME(const ConvOpt & convOpt) \
+        : convOpt_(convOpt){} \
+        template<class S, class D> \
+        void operator()(const S & s, D & d)const{ \
+            FUNCTION_NAME(s, d, convOpt_); \
+        } \
+        template<class S, class D,class SHAPE> \
+        void operator()(const S & s, D & d, const SHAPE & roiBegin, const SHAPE & roiEnd){ \
+            ConvOpt convOpt(convOpt_); \
+            convOpt.subarray(roiBegin, roiEnd); \
+            FUNCTION_NAME(s, d, convOpt); \
+        } \
+    private: \
+        ConvOpt  convOpt_; \
+    };
+
+
+    CONVOLUTION_FUNCTOR(GaussianSmoothFunctor,            vigra::gaussianSmoothMultiArray);
+    CONVOLUTION_FUNCTOR(GaussianGradientFunctor,          vigra::gaussianGradientMultiArray);
+    CONVOLUTION_FUNCTOR(SymmetricGradientFunctor,         vigra::symmetricGradientMultiArray);
+    CONVOLUTION_FUNCTOR(GaussianDivergenceFunctor,        vigra::gaussianDivergenceMultiArray);
+    CONVOLUTION_FUNCTOR(HessianOfGaussianFunctor,         vigra::hessianOfGaussianMultiArray);
+    CONVOLUTION_FUNCTOR(LaplacianOfGaussianFunctor,       vigra::laplacianOfGaussianMultiArray);
+    CONVOLUTION_FUNCTOR(GaussianGradientMagnitudeFunctor, vigra::gaussianGradientMagnitude);
+    CONVOLUTION_FUNCTOR(StructureTensorFunctor,           vigra::structureTensorMultiArray);
+
+    #undef CONVOLUTION_FUNCTOR
+
+    template<unsigned int DIM>
+    class HessianOfGaussianEigenvaluesFunctor{
+    public:
+        typedef ConvolutionOptions<DIM> ConvOpt;
+        HessianOfGaussianEigenvaluesFunctor(const ConvOpt & convOpt)
+        : convOpt_(convOpt){}
+        template<class S, class D>
+        void operator()(const S & s, D & d)const{
+            typedef typename vigra::NumericTraits<typename S::value_type>::RealPromote RealType;
+            vigra::MultiArray<DIM, TinyVector<RealType, int(DIM*(DIM+1)/2)> >  hessianOfGaussianRes(d.shape());
+            vigra::hessianOfGaussianMultiArray(s, hessianOfGaussianRes, convOpt_);
+            vigra::tensorEigenvaluesMultiArray(hessianOfGaussianRes, d);
+        }
+        template<class S, class D,class SHAPE>
+        void operator()(const S & s, D & d, const SHAPE & roiBegin, const SHAPE & roiEnd){
+            typedef typename vigra::NumericTraits<typename S::value_type>::RealPromote RealType;
+            vigra::MultiArray<DIM, TinyVector<RealType, int(DIM*(DIM+1)/2)> >  hessianOfGaussianRes(roiEnd-roiBegin);
+            convOpt_.subarray(roiBegin, roiEnd);
+            vigra::hessianOfGaussianMultiArray(s, hessianOfGaussianRes, convOpt_);
+            vigra::tensorEigenvaluesMultiArray(hessianOfGaussianRes, d);
+        }
+    private:
+        ConvOpt  convOpt_;
+    };
+
+    template<unsigned int DIM, unsigned int EV>
+    class HessianOfGaussianSelectedEigenvalueFunctor{
+    public:
+        typedef ConvolutionOptions<DIM> ConvOpt;
+        HessianOfGaussianSelectedEigenvalueFunctor(const ConvOpt & convOpt)
+        : convOpt_(convOpt){}
+        template<class S, class D>
+        void operator()(const S & s, D & d)const{
+            typedef typename vigra::NumericTraits<typename S::value_type>::RealPromote RealType;
+
+            // compute the hessian of gaussian and extract eigenvalue
+            vigra::MultiArray<DIM, TinyVector<RealType, int(DIM*(DIM+1)/2)> >  hessianOfGaussianRes(s.shape());
+            vigra::hessianOfGaussianMultiArray(s, hessianOfGaussianRes, convOpt_);
+
+            vigra::MultiArray<DIM, TinyVector<RealType, DIM > >  allEigenvalues(s.shape());
+            vigra::tensorEigenvaluesMultiArray(hessianOfGaussianRes, allEigenvalues);
+
+            d = allEigenvalues.bindElementChannel(EV);
+        }
+        template<class S, class D,class SHAPE>
+        void operator()(const S & s, D & d, const SHAPE & roiBegin, const SHAPE & roiEnd){
+
+            typedef typename vigra::NumericTraits<typename S::value_type>::RealPromote RealType;
+
+            // compute the hessian of gaussian and extract eigenvalue
+            vigra::MultiArray<DIM, TinyVector<RealType, int(DIM*(DIM+1)/2)> >  hessianOfGaussianRes(roiEnd-roiBegin);
+            convOpt_.subarray(roiBegin, roiEnd);
+            vigra::hessianOfGaussianMultiArray(s, hessianOfGaussianRes, convOpt_);
+
+            vigra::MultiArray<DIM, TinyVector<RealType, DIM > >  allEigenvalues(roiEnd-roiBegin);
+            vigra::tensorEigenvaluesMultiArray(hessianOfGaussianRes, allEigenvalues);
+
+            d = allEigenvalues.bindElementChannel(EV);
+        }
+    private:
+        ConvOpt  convOpt_;
+    };
+
+
+    template<unsigned int DIM>
+    class HessianOfGaussianFirstEigenvalueFunctor
+    : public HessianOfGaussianSelectedEigenvalueFunctor<DIM, 0>{
+    public:
+        typedef ConvolutionOptions<DIM> ConvOpt;
+        HessianOfGaussianFirstEigenvalueFunctor(const ConvOpt & convOpt)
+        : HessianOfGaussianSelectedEigenvalueFunctor<DIM, 0>(convOpt){}
+    };
+
+    template<unsigned int DIM>
+    class HessianOfGaussianLastEigenvalueFunctor
+    : public HessianOfGaussianSelectedEigenvalueFunctor<DIM, DIM-1>{
+    public:
+        typedef ConvolutionOptions<DIM> ConvOpt;
+        HessianOfGaussianLastEigenvalueFunctor(const ConvOpt & convOpt)
+        : HessianOfGaussianSelectedEigenvalueFunctor<DIM, DIM-1>(convOpt){}
+    };
+
+
+
+
+
+
+    /// \warning this functions is deprecated
+    /// and should not be used from end users
+    template<unsigned int N>
+    vigra::TinyVector< vigra::MultiArrayIndex, N > getBorder(
+        const BlockwiseConvolutionOptions<N> & opt,
+        const size_t order,
+        const bool usesOuterScale = false
+    ){
+        vigra::TinyVector< vigra::MultiArrayIndex, N > res(vigra::SkipInitialization);
+
+        if(opt.getFilterWindowSize()<=0.00001){
+            for(size_t d=0; d<N; ++d){
+                double stdDev =  opt.getStdDev()[d];
+                if(usesOuterScale)
+                    stdDev += opt.getOuterScale()[d];
+                res[d] = static_cast<MultiArrayIndex>(3.0 * stdDev  + 0.5*static_cast<double>(order)+0.5);
+            }
+        }
+        else{
+            throw std::runtime_error("blockwise filters do not allow a user defined FilterWindowSize");
+        }
+        return res;
+    }
+
+} // end namespace blockwise
+
+#define VIGRA_BLOCKWISE(FUNCTOR, FUNCTION, ORDER, USES_OUTER_SCALE) \
+template <unsigned int N, class T1, class S1, class T2, class S2> \
+void FUNCTION( \
+    MultiArrayView<N, T1, S1> const & source, \
+    MultiArrayView<N, T2, S2> dest, \
+    BlockwiseConvolutionOptions<N> const & options \
+) \
+{  \
+    typedef  MultiBlocking<N, vigra::MultiArrayIndex> Blocking; \
+    typedef typename Blocking::Shape Shape; \
+    const Shape border = blockwise::getBorder(options, ORDER, USES_OUTER_SCALE); \
+    BlockwiseConvolutionOptions<N> subOptions(options); \
+    subOptions.subarray(Shape(0), Shape(0));  \
+    const Blocking blocking(source.shape(), options.template getBlockShapeN<N>()); \
+    blockwise::FUNCTOR<N> f(subOptions); \
+    blockwise::blockwiseCaller(source, dest, f, blocking, border, options); \
+}
+
+VIGRA_BLOCKWISE(GaussianSmoothFunctor,                   gaussianSmoothMultiArray,                   0, false );
+VIGRA_BLOCKWISE(GaussianGradientFunctor,                 gaussianGradientMultiArray,                 1, false );
+VIGRA_BLOCKWISE(SymmetricGradientFunctor,                symmetricGradientMultiArray,                1, false );
+VIGRA_BLOCKWISE(GaussianDivergenceFunctor,               gaussianDivergenceMultiArray,               1, false );
+VIGRA_BLOCKWISE(HessianOfGaussianFunctor,                hessianOfGaussianMultiArray,                2, false );
+VIGRA_BLOCKWISE(HessianOfGaussianEigenvaluesFunctor,     hessianOfGaussianEigenvaluesMultiArray,     2, false );
+VIGRA_BLOCKWISE(HessianOfGaussianFirstEigenvalueFunctor, hessianOfGaussianFirstEigenvalueMultiArray, 2, false );
+VIGRA_BLOCKWISE(HessianOfGaussianLastEigenvalueFunctor,  hessianOfGaussianLastEigenvalueMultiArray,  2, false );
+VIGRA_BLOCKWISE(LaplacianOfGaussianFunctor,              laplacianOfGaussianMultiArray,              2, false );
+VIGRA_BLOCKWISE(GaussianGradientMagnitudeFunctor,        gaussianGradientMagnitudeMultiArray,        1, false );
+VIGRA_BLOCKWISE(StructureTensorFunctor,                  structureTensorMultiArray,                  1, true  );
+
+#undef  VIGRA_BLOCKWISE
+
+    // alternative name for backward compatibility
+template <unsigned int N, class T1, class S1, class T2, class S2>
+inline void
+gaussianGradientMagnitude(
+    MultiArrayView<N, T1, S1> const & source,
+    MultiArrayView<N, T2, S2> dest,
+    BlockwiseConvolutionOptions<N> const & options)
+{
+    gaussianGradientMagnitudeMultiArray(source, dest, options);
+}
+
+
+} // end namespace vigra
+
+#endif // VIGRA_MULTI_BLOCKWISE_HXX
diff --git a/include/vigra/multi_convolution.hxx b/include/vigra/multi_convolution.hxx
index 4033b54..2e3ad9d 100644
--- a/include/vigra/multi_convolution.hxx
+++ b/include/vigra/multi_convolution.hxx
@@ -31,7 +31,7 @@
 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
-/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
 
@@ -51,6 +51,9 @@
 #include "tinyvector.hxx"
 #include "algorithm.hxx"
 
+
+#include <iostream>
+
 namespace vigra
 {
 
@@ -198,7 +201,7 @@ struct multiArrayScaleParam
 
 } // namespace detail
 
-#define VIGRA_CONVOLUTION_OPTIONS(function_name, default_value, member_name) \
+#define VIGRA_CONVOLUTION_OPTIONS(function_name, default_value, member_name, getter_setter_name) \
     template <class Param> \
     ConvolutionOptions & function_name(const Param & val) \
     { \
@@ -229,14 +232,19 @@ struct multiArrayScaleParam
     { \
         member_name = ParamVec(v0, v1, v2, v3, v4, "ConvolutionOptions::" #function_name); \
         return *this; \
+    } \
+    typename  ParamVec::p_vector  get##getter_setter_name()const{ \
+      return member_name.vec; \
+    } \
+    void set##getter_setter_name(typename ParamVec::p_vector vec){ \
+      member_name.vec = vec; \
     }
 
-
 /** \brief  Options class template for convolutions.
- 
+
   <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
   Namespace: vigra
-  
+
   This class enables the calculation of scale space convolutions
   such as \ref gaussianGradientMultiArray() on data with anisotropic
   discretization. For these, the result of the ordinary calculation
@@ -248,7 +256,7 @@ struct multiArrayScaleParam
   parameter \f$\sigma\f$ has to be replaced by
   \f$\sqrt{\sigma_\mathrm{eff}^2 - \sigma_\mathrm{D}^2}\Big/w\f$,
   where \f$\sigma_\mathrm{eff}\f$ is the resulting effective filtering
-  scale. The data is assumed to be already filtered by a 
+  scale. The data is assumed to be already filtered by a
   gaussian smoothing with the scale parameter \f$\sigma_\mathrm{D}\f$
   (such as by measuring equipment). All of the above changes are
   automatically employed by the convolution functions for <tt>MultiArray</tt>s
@@ -260,7 +268,7 @@ struct multiArrayScaleParam
   options are set by (overloaded) member functions explained below,
   or else default to neutral values corresponding to the absence of the
   particular option.
-  
+
   All member functions set <tt>dim</tt> values of the respective convolution
   option, one for each dimension. They may be set explicitly by multiple
   arguments for up to five dimensions, or by a single argument to the same
@@ -268,7 +276,7 @@ struct multiArrayScaleParam
   either a C-syle array, an iterator, or a C++ standard library style
   sequence (such as <tt>std::vector</tt>, with member functions <tt>begin()</tt>
   and <tt>size()</tt>) supplies the option values for any number of dimensions.
-  
+
   Note that the return value of all member functions is <tt>*this</tt>, which
   provides the mechanism for concatenating member function calls as shown below.
 
@@ -277,16 +285,16 @@ struct multiArrayScaleParam
   \code
   ConvolutionOptions<2> opt = ConvolutionOptions<2>().stepSize(1, 2.3);
   \endcode
- 
+
   <b>usage with arrays:</b>
- 
+
   \code
   const double step_size[3] = { x_scale, y_scale, z_scale };
   ConvolutionOptions<3> opt = ConvolutionOptions<3>().stepSize(step_size);
   \endcode
 
   <b>usage with C++ standard library style sequences:</b>
- 
+
   \code
   TinyVector<double, 4> step_size(1, 1, 2.0, 1.5);
   TinyVector<double, 4>  r_sigmas(1, 1, 2.3, 3.2);
@@ -310,7 +318,7 @@ struct multiArrayScaleParam
   \code
   MultiArray<3, double> test_image;
   MultiArray<3, double> out_image;
-  
+
   double scale = 5.0;
   gaussianSmoothMultiArray(test_image, out_image, scale,
                            ConvolutionOptions<3>()
@@ -318,7 +326,7 @@ struct multiArrayScaleParam
                               .resolutionStdDev(1, 1, 4)
                           );
   \endcode
- 
+
 */
 template <unsigned dim>
 class ConvolutionOptions
@@ -334,7 +342,7 @@ class ConvolutionOptions
     ParamVec outer_scale;
     double window_ratio;
     Shape from_point, to_point;
-     
+
     ConvolutionOptions()
     : sigma_eff(0.0),
       sigma_d(0.0),
@@ -366,14 +374,14 @@ class ConvolutionOptions
 
     // Step size per axis.
     // Default: dim values of 1.0
-    VIGRA_CONVOLUTION_OPTIONS(stepSize, 1.0, step_size)
+    VIGRA_CONVOLUTION_OPTIONS(stepSize, 1.0, step_size, StepSize)
 #ifdef DOXYGEN
         /** Step size(s) per axis, i.e., the distance between two
             adjacent pixels. Required for <tt>MultiArray</tt>
             containing anisotropic data.
- 
+
             Note that a convolution containing a derivative operator
-            of order <tt>n</tt> results in a multiplication by 
+            of order <tt>n</tt> results in a multiplication by
             \f${\rm stepSize}^{-n}\f$ for each axis.
             Also, the above standard deviations
             are scaled according to the step size of each axis.
@@ -385,11 +393,11 @@ class ConvolutionOptions
 
     // Resolution standard deviation per axis.
     // Default: dim values of 0.0
-    VIGRA_CONVOLUTION_OPTIONS(resolutionStdDev, 0.0, sigma_d)
+    VIGRA_CONVOLUTION_OPTIONS(resolutionStdDev, 0.0, sigma_d, ResolutionStdDev)
 #ifdef DOXYGEN
         /** Resolution standard deviation(s) per axis, i.e., a supposed
             pre-existing gaussian filtering by this value.
-       
+
             The standard deviation actually used by the convolution operators
             is \f$\sqrt{{\rm sigma}^{2} - {\rm resolutionStdDev}^{2}}\f$ for each
             axis.
@@ -401,12 +409,12 @@ class ConvolutionOptions
 
     // Standard deviation of scale space operators.
     // Default: dim values of 0.0
-    VIGRA_CONVOLUTION_OPTIONS(stdDev, 0.0, sigma_eff)
-    VIGRA_CONVOLUTION_OPTIONS(innerScale, 0.0, sigma_eff)
+    VIGRA_CONVOLUTION_OPTIONS(stdDev, 0.0, sigma_eff, StdDev)
+    VIGRA_CONVOLUTION_OPTIONS(innerScale, 0.0, sigma_eff, InnerScale)
 
 #ifdef DOXYGEN
         /** Standard deviation(s) of scale space operators, or inner scale(s) for \ref structureTensorMultiArray().
-        
+
             Usually not
             needed, since a single value for all axes may be specified as a parameter
             <tt>sigma</tt> to the call of
@@ -418,7 +426,7 @@ class ConvolutionOptions
     ConvolutionOptions<dim> & stdDev(...);
 
         /** Standard deviation(s) of scale space operators, or inner scale(s) for \ref structureTensorMultiArray().
-        
+
             Usually not
             needed, since a single value for all axes may be specified as a parameter
             <tt>sigma</tt> to the call of
@@ -432,10 +440,10 @@ class ConvolutionOptions
 
     // Outer scale, for structure tensor.
     // Default: dim values of 0.0
-    VIGRA_CONVOLUTION_OPTIONS(outerScale, 0.0, outer_scale)
+    VIGRA_CONVOLUTION_OPTIONS(outerScale, 0.0, outer_scale, OuterScale)
 #ifdef DOXYGEN
         /** Standard deviation(s) of the second convolution of the
-            structure tensor. 
+            structure tensor.
 
             Usually not needed, since a single value for
             all axes may be specified as a parameter <tt>outerScale</tt> to
@@ -448,18 +456,18 @@ class ConvolutionOptions
     ConvolutionOptions<dim> & outerScale(...);
 #endif
 
-        /** Size of the filter window as a multiple of the scale parameter. 
+        /** Size of the filter window as a multiple of the scale parameter.
 
             This option is only used for Gaussian filters and their derivatives.
-            By default, the window size of a Gaussian filter is automatically 
-            determined such that the error resulting from restricting the 
-            infinitely large Gaussian function to a finite size is minimized. 
+            By default, the window size of a Gaussian filter is automatically
+            determined such that the error resulting from restricting the
+            infinitely large Gaussian function to a finite size is minimized.
             In particular, the window radius is determined as
-            <tt>radius = round(3.0 * sigma + 0.5 * order)</tt>, where 'order' is the 
-            desired derivative order. In some cases, it is desirable to trade off 
+            <tt>radius = round(3.0 * sigma + 0.5 * order)</tt>, where 'order' is the
+            desired derivative order. In some cases, it is desirable to trade off
             accuracy for speed, and this function can be used to request a smaller
             window radius.
-            
+
             Default: <tt>0.0</tt> (i.e. determine the window size automatically)
         */
     ConvolutionOptions<dim> & filterWindowSize(double ratio)
@@ -470,14 +478,18 @@ class ConvolutionOptions
         return *this;
     }
 
-        /** Restrict the filter to a subregion of the input array. 
+    double getFilterWindowSize() const {
+      return window_ratio;
+    }
+
+        /** Restrict the filter to a subregion of the input array.
 
-            This is useful for speeding up computations by ignoring irrelevant 
+            This is useful for speeding up computations by ignoring irrelevant
             areas in the array. <b>Note:</b> It is assumed that the output array
-            of the convolution has the size given in this function.  Negative ROI 
-            boundaries are interpreted relative to the end of the respective dimension 
+            of the convolution has the size given in this function.  Negative ROI
+            boundaries are interpreted relative to the end of the respective dimension
             (i.e. <tt>if(to[k] < 0) to[k] += source.shape(k);</tt>).
-            
+
             Default: <tt>from = Shape(), to = Shape()</tt> (i.e. use entire array)
         */
     ConvolutionOptions<dim> & subarray(Shape const & from, Shape const & to)
@@ -486,6 +498,13 @@ class ConvolutionOptions
         to_point = to;
         return *this;
     }
+
+    std::pair<Shape, Shape> getSubarray()const{
+      std::pair<Shape, Shape> res;
+      res.first  = from_point;
+      res.second = to_point;
+      return res;
+    }
 };
 
 namespace detail
@@ -514,14 +533,14 @@ internalSeparableConvolveMultiArrayTmp(
 
     typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
     typedef MultiArrayNavigator<DestIterator, N> DNavigator;
-    
+
     TmpAcessor acc;
 
     {
         // only operate on first dimension here
         SNavigator snav( si, shape, 0 );
         DNavigator dnav( di, shape, 0 );
-        
+
         for( ; snav.hasMore(); snav++, dnav++ )
         {
              // first copy source to tmp for maximum cache efficiency
@@ -573,11 +592,12 @@ internalSeparableConvolveSubarray(
     typedef MultiArray<N, TmpType> TmpArray;
     typedef typename TmpArray::traverser TmpIterator;
     typedef typename AccessorTraits<TmpType>::default_accessor TmpAcessor;
-    
+
     SrcShape sstart, sstop, axisorder, tmpshape;
     TinyVector<double, N> overhead;
     for(int k=0; k<N; ++k)
     {
+        axisorder[k] = k;
         sstart[k] = start[k] - kit[k].right();
         if(sstart[k] < 0)
             sstart[k] = 0;
@@ -586,27 +606,26 @@ internalSeparableConvolveSubarray(
             sstop[k] = shape[k];
         overhead[k] = double(sstop[k] - sstart[k]) / (stop[k] - start[k]);
     }
-    
+
     indexSort(overhead.begin(), overhead.end(), axisorder.begin(), std::greater<double>());
-    
     SrcShape dstart, dstop(sstop - sstart);
     dstop[axisorder[0]]  = stop[axisorder[0]] - start[axisorder[0]];
-    
+
     // temporary array to hold the current line to enable in-place operation
     MultiArray<N, TmpType> tmp(dstop);
 
     typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
     typedef MultiArrayNavigator<TmpIterator, N> TNavigator;
-    
+
     TmpAcessor acc;
 
     {
         // only operate on first dimension here
         SNavigator snav( si, sstart, sstop, axisorder[0]);
         TNavigator tnav( tmp.traverser_begin(), dstart, dstop, axisorder[0]);
-        
+
         ArrayVector<TmpType> tmpline(sstop[axisorder[0]] - sstart[axisorder[0]]);
-        
+
         int lstart = start[axisorder[0]] - sstart[axisorder[0]];
         int lstop  = lstart + (stop[axisorder[0]] - start[axisorder[0]]);
 
@@ -614,20 +633,20 @@ internalSeparableConvolveSubarray(
         {
             // first copy source to tmp for maximum cache efficiency
             copyLine(snav.begin(), snav.end(), src, tmpline.begin(), acc);
-            
+
             convolveLine(srcIterRange(tmpline.begin(), tmpline.end(), acc),
                          destIter(tnav.begin(), acc),
                          kernel1d( kit[axisorder[0]] ), lstart, lstop);
         }
     }
-    
+
     // operate on further dimensions
     for( int d = 1; d < N; ++d)
     {
         TNavigator tnav( tmp.traverser_begin(), dstart, dstop, axisorder[d]);
-        
+
         ArrayVector<TmpType> tmpline(dstop[axisorder[d]] - dstart[axisorder[d]]);
-        
+
         int lstart = start[axisorder[d]] - sstart[axisorder[d]];
         int lstop  = lstart + (stop[axisorder[d]] - start[axisorder[d]]);
 
@@ -640,17 +659,17 @@ internalSeparableConvolveSubarray(
                          destIter( tnav.begin() + lstart, acc ),
                          kernel1d( kit[axisorder[d]] ), lstart, lstop);
         }
-        
+
         dstart[axisorder[d]] = lstart;
         dstop[axisorder[d]] = lstop;
     }
-    
-    copyMultiArray(tmp.traverser_begin()+dstart, stop-start, acc, di, dest);              
+
+    copyMultiArray(tmp.traverser_begin()+dstart, stop-start, acc, di, dest);
 }
 
 
 template <class K>
-void 
+void
 scaleKernel(K & kernel, double a)
 {
     for(int i = kernel.left(); i <= kernel.right(); ++i)
@@ -694,12 +713,12 @@ scaleKernel(K & kernel, double a)
     A full-sized internal array is only allocated if working on the destination
     array directly would cause round-off errors (i.e. if
     <tt>typeid(typename NumericTraits<T2>::RealPromote) != typeid(T2)</tt>).
-    
+
     If <tt>start</tt> and <tt>stop</tt> have non-default values, they must represent
-    a valid subarray of the input array. The convolution is then restricted to that 
+    a valid subarray of the input array. The convolution is then restricted to that
     subarray, and it is assumed that the output array only refers to the
     subarray (i.e. <tt>dest.shape() == stop - start</tt>). Negative ROI boundaries are
-    interpreted relative to the end of the respective dimension 
+    interpreted relative to the end of the respective dimension
     (i.e. <tt>if(stop[k] < 0) stop[k] += source.shape(k);</tt>).
 
     <b> Declarations:</b>
@@ -709,18 +728,18 @@ scaleKernel(K & kernel, double a)
     namespace vigra {
         // apply each kernel from the sequence 'kernels' in turn
         template <unsigned int N, class T1, class S1,
-                                  class T2, class S2, 
+                                  class T2, class S2,
                   class KernelIterator>
         void
         separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & source,
-                                    MultiArrayView<N, T2, S2> dest, 
+                                    MultiArrayView<N, T2, S2> dest,
                                     KernelIterator kernels,
                                     typename MultiArrayShape<N>::type start = typename MultiArrayShape<N>::type(),
                                     typename MultiArrayShape<N>::type stop  = typename MultiArrayShape<N>::type());
 
         // apply the same kernel to all dimensions
         template <unsigned int N, class T1, class S1,
-                                  class T2, class S2, 
+                                  class T2, class S2,
                   class T>
         void
         separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & source,
@@ -797,17 +816,17 @@ scaleKernel(K & kernel, double a)
 
     // smooth all dimensions with the same kernel
     separableConvolveMultiArray(source, dest, gauss);
-    
+
     // create 3 Gauss kernels, one for each dimension, but smooth the z-axis less
     ArrayVector<Kernel1D<float> > kernels(3, gauss);
     kernels[2].initGaussian(sigma / 2.0);
 
     // perform Gaussian smoothing on all dimensions
     separableConvolveMultiArray(source, dest, kernels.begin());
-    
+
     // create output array for a ROI
     MultiArray<3, float> destROI(shape - Shape3(10,10,10));
-     
+
     // only smooth the given ROI (ignore 5 pixels on all sides of the array)
     separableConvolveMultiArray(source, destROI, gauss, Shape3(5,5,5), Shape3(-5,-5,-5));
     \endcode
@@ -824,7 +843,7 @@ scaleKernel(K & kernel, double a)
     ArrayVector<Kernel1D<float> > kernels(3, gauss);
 
     // perform Gaussian smoothing on all dimensions
-    separableConvolveMultiArray(source, dest, 
+    separableConvolveMultiArray(source, dest,
                                 kernels.begin());
     \endcode
     <b> Required Interface:</b>
@@ -846,7 +865,7 @@ template <class SrcIterator, class SrcShape, class SrcAccessor,
           class DestIterator, class DestAccessor, class KernelIterator>
 void
 separableConvolveMultiArray( SrcIterator s, SrcShape const & shape, SrcAccessor src,
-                             DestIterator d, DestAccessor dest, 
+                             DestIterator d, DestAccessor dest,
                              KernelIterator kernels,
                              SrcShape start = SrcShape(),
                              SrcShape stop = SrcShape())
@@ -856,11 +875,11 @@ separableConvolveMultiArray( SrcIterator s, SrcShape const & shape, SrcAccessor
 
     if(stop != SrcShape())
     {
-        
+
         enum { N = 1 + SrcIterator::level };
         detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, start);
         detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, stop);
-        
+
         for(int k=0; k<N; ++k)
             vigra_precondition(0 <= start[k] && start[k] < stop[k] && stop[k] <= shape[k],
               "separableConvolveMultiArray(): invalid subarray shape.");
@@ -900,7 +919,7 @@ template <class SrcIterator, class SrcShape, class SrcAccessor,
           class DestIterator, class DestAccessor, class KernelIterator>
 inline void
 separableConvolveMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
-                            pair<DestIterator, DestAccessor> const & dest, 
+                            pair<DestIterator, DestAccessor> const & dest,
                             KernelIterator kit,
                             SrcShape const & start = SrcShape(),
                             SrcShape const & stop = SrcShape())
@@ -925,11 +944,11 @@ separableConvolveMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & s
 }
 
 template <unsigned int N, class T1, class S1,
-                          class T2, class S2, 
+                          class T2, class S2,
           class KernelIterator>
 inline void
 separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & source,
-                            MultiArrayView<N, T2, S2> dest, 
+                            MultiArrayView<N, T2, S2> dest,
                             KernelIterator kit,
                             typename MultiArrayShape<N>::type start = typename MultiArrayShape<N>::type(),
                             typename MultiArrayShape<N>::type stop = typename MultiArrayShape<N>::type())
@@ -951,7 +970,7 @@ separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & source,
 }
 
 template <unsigned int N, class T1, class S1,
-                          class T2, class S2, 
+                          class T2, class S2,
           class T>
 inline void
 separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & source,
@@ -977,10 +996,10 @@ separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & source,
     <tt>kernel</tt>. The destination array must already have the correct size.
 
     If <tt>start</tt> and <tt>stop</tt> have non-default values, they must represent
-    a valid subarray of the input array. The convolution is then restricted to that 
+    a valid subarray of the input array. The convolution is then restricted to that
     subarray, and it is assumed that the output array only refers to the
     subarray (i.e. <tt>dest.shape() == stop - start</tt>). Negative ROI boundaries are
-    interpreted relative to the end of the respective dimension 
+    interpreted relative to the end of the respective dimension
     (i.e. <tt>if(stop[k] < 0) stop[k] += source.shape(k);</tt>).
 
     This function may work in-place, which means that <tt>source.data() == dest.data()</tt> is allowed.
@@ -991,12 +1010,12 @@ separableConvolveMultiArray(MultiArrayView<N, T1, S1> const & source,
     \code
     namespace vigra {
         template <unsigned int N, class T1, class S1,
-                                  class T2, class S2, 
+                                  class T2, class S2,
                   class T>
         void
         convolveMultiArrayOneDimension(MultiArrayView<N, T1, S1> const & source,
                                        MultiArrayView<N, T2, S2> dest,
-                                       unsigned int dim, 
+                                       unsigned int dim,
                                        Kernel1D<T> const & kernel,
                                        typename MultiArrayShape<N>::type start = typename MultiArrayShape<N>::type(),
                                        typename MultiArrayShape<N>::type stop  = typename MultiArrayShape<N>::type());
@@ -1073,9 +1092,9 @@ convolveMultiArrayOneDimension(SrcIterator s, SrcShape const & shape, SrcAccesso
 
     typedef MultiArrayNavigator<SrcIterator, N> SNavigator;
     typedef MultiArrayNavigator<DestIterator, N> DNavigator;
-    
+
     SrcShape sstart, sstop(shape), dstart, dstop(shape);
-    
+
     if(stop != SrcShape())
     {
         sstart = start;
@@ -1115,12 +1134,12 @@ convolveMultiArrayOneDimension(triple<SrcIterator, SrcShape, SrcAccessor> const
 }
 
 template <unsigned int N, class T1, class S1,
-                          class T2, class S2, 
+                          class T2, class S2,
           class T>
 inline void
 convolveMultiArrayOneDimension(MultiArrayView<N, T1, S1> const & source,
                                MultiArrayView<N, T2, S2> dest,
-                               unsigned int dim, 
+                               unsigned int dim,
                                Kernel1D<T> const & kernel,
                                typename MultiArrayShape<N>::type start = typename MultiArrayShape<N>::type(),
                                typename MultiArrayShape<N>::type stop = typename MultiArrayShape<N>::type())
@@ -1157,9 +1176,16 @@ convolveMultiArrayOneDimension(MultiArrayView<N, T1, S1> const & source,
     that <tt>source.data() == dest.data()</tt> is allowed. It is implemented by a call to
     \ref separableConvolveMultiArray() with the appropriate kernel.
 
-    Anisotropic data should be passed with appropriate
-    \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise optional
-    unless the parameter <tt>sigma</tt> is omitted.
+    Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
+    to adjust the filter sizes for the resolution of each axis.
+    Otherwise, the parameter <tt>opt</tt> is optional unless the parameter
+    <tt>sigma</tt> is omitted.
+
+    If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
+    be executed in parallel on data blocks of a certain size. The block size can be
+    customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
+    usually work reasonably. By default, the number of threads equals the capabilities
+    of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
 
     <b> Declarations:</b>
 
@@ -1182,6 +1208,14 @@ convolveMultiArrayOneDimension(MultiArrayView<N, T1, S1> const & source,
         gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
                                  MultiArrayView<N, T2, S2> dest,
                                  ConvolutionOptions<N> opt);
+
+        // as above, but execute algorirhm in parallel
+        template <unsigned int N, class T1, class S1,
+                                  class T2, class S2>
+        void
+        gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
+                                 MultiArrayView<N, T2, S2> dest,
+                                 BlockwiseConvolutionOptions<N> opt);
     }
     \endcode
 
@@ -1214,7 +1248,8 @@ convolveMultiArrayOneDimension(MultiArrayView<N, T1, S1> const & source,
 
     <b> Usage:</b>
 
-    <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
+    <b>\#include</b> \<vigra/multi_convolution.hxx\> (sequential version)<br/>
+    <b>\#include</b> \<vigra/multi_blockwise.hxx\> (parallel version)<br/>
     Namespace: vigra
 
     \code
@@ -1226,6 +1261,21 @@ convolveMultiArrayOneDimension(MultiArrayView<N, T1, S1> const & source,
     gaussianSmoothMultiArray(source, dest, sigma);
     \endcode
 
+    <b> Multi-threaded execution:</b>
+
+    \code
+    Shape3 shape(width, height, depth);
+    MultiArray<3, unsigned char> source(shape);
+    MultiArray<3, float>         dest(shape);
+    ...
+    BlockwiseConvolutionOptions<3> opt;
+    opt.numThreads(4);       // use 4 threads (uses hardware default if not given)
+    opt.innerScale(sigma);
+
+    // perform isotropic Gaussian smoothing at scale 'sigma' in parallel
+    gaussianSmoothMultiArray(source, dest, sigma, opt);
+    \endcode
+
     <b> Usage with anisotropic data:</b>
 
     \code
@@ -1348,9 +1398,16 @@ gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
     dimensions. This function is implemented by calls to
     \ref separableConvolveMultiArray() with the appropriate kernels.
 
-    Anisotropic data should be passed with appropriate
-    \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise optional
-    unless the parameter <tt>sigma</tt> is omitted.
+    Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
+    to adjust the filter sizes for the resolution of each axis.
+    Otherwise, the parameter <tt>opt</tt> is optional unless the parameter
+    <tt>sigma</tt> is omitted.
+
+    If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
+    be executed in parallel on data blocks of a certain size. The block size can be
+    customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
+    usually work reasonably. By default, the number of threads equals the capabilities
+    of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
 
     <b> Declarations:</b>
 
@@ -1373,6 +1430,14 @@ gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
         gaussianGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
                                    MultiArrayView<N, TinyVector<T2, N>, S2> dest,
                                    ConvolutionOptions<N> opt);
+
+        // likewise, but execute algorithm in parallel
+        template <unsigned int N, class T1, class S1,
+                                  class T2, class S2>
+        void
+        gaussianGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
+                                   MultiArrayView<N, TinyVector<T2, N>, S2> dest,
+                                   BlockwiseConvolutionOptions<N> opt);
     }
     \endcode
 
@@ -1385,7 +1450,7 @@ gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
         void
         gaussianGradientMultiArray(SrcIterator siter, SrcShape const & shape, SrcAccessor src,
                                    DestIterator diter, DestAccessor dest,
-                                   double sigma, 
+                                   double sigma,
                                    const ConvolutionOptions<N> & opt = ConvolutionOptions<N>());
     }
     \endcode
@@ -1405,7 +1470,8 @@ gaussianSmoothMultiArray(MultiArrayView<N, T1, S1> const & source,
 
     <b> Usage:</b>
 
-    <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
+    <b>\#include</b> \<vigra/multi_convolution.hxx\> (sequential version)<br/>
+    <b>\#include</b> \<vigra/multi_blockwise.hxx\> (parallel version)<br/>
     Namespace: vigra
 
     \code
@@ -1446,7 +1512,7 @@ gaussianGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor s
     typedef typename DestAccessor::value_type DestType;
     typedef typename DestType::value_type     DestValueType;
     typedef typename NumericTraits<DestValueType>::RealPromote KernelType;
-   
+
     static const int N = SrcShape::static_size;
     typedef typename ConvolutionOptions<N>::ScaleIterator ParamType;
 
@@ -1475,7 +1541,7 @@ gaussianGradientMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor s
         ArrayVector<Kernel1D<KernelType> > kernels(plain_kernels);
         kernels[dim].initGaussianDerivative(params2.sigma_scaled(), 1, 1.0, opt.window_ratio);
         detail::scaleKernel(kernels[dim], 1.0 / params2.step_size());
-        separableConvolveMultiArray(si, shape, src, di, ElementAccessor(dim, dest), kernels.begin(), 
+        separableConvolveMultiArray(si, shape, src, di, ElementAccessor(dim, dest), kernels.begin(),
                                     opt.from_point, opt.to_point);
     }
 }
@@ -1558,7 +1624,7 @@ namespace detail {
 
 template <unsigned int N, class T1, class S1,
                           class T2, class S2>
-void 
+void
 gaussianGradientMagnitudeImpl(MultiArrayView<N+1, T1, S1> const & src,
                               MultiArrayView<N, T2, S2> dest,
                               ConvolutionOptions<N> opt = ConvolutionOptions<N>())
@@ -1576,18 +1642,18 @@ gaussianGradientMagnitudeImpl(MultiArrayView<N+1, T1, S1> const & src,
         vigra_precondition(shape == dest.shape(),
             "gaussianGradientMagnitude(): shape mismatch between input and output.");
     }
-              
+
     dest.init(0.0);
-    
+
     typedef typename NumericTraits<T1>::RealPromote TmpType;
     MultiArray<N, TinyVector<TmpType, N> > grad(dest.shape());
-    
+
     using namespace multi_math;
-    
+
     for(int k=0; k<src.shape(N); ++k)
     {
         gaussianGradientMultiArray(src.bindOuter(k), grad, opt);
-        
+
         dest += squaredNorm(grad);
     }
     dest = sqrt(dest);
@@ -1598,7 +1664,7 @@ gaussianGradientMagnitudeImpl(MultiArrayView<N+1, T1, S1> const & src,
     // documentation is in convolution.hxx
 template <unsigned int N, class T1, class S1,
                           class T2, class S2>
-inline void 
+inline void
 gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<T1>, S1> const & src,
                           MultiArrayView<N, T2, S2> dest,
                           ConvolutionOptions<N> const & opt)
@@ -1608,7 +1674,7 @@ gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<T1>, S1> const & src,
 
 template <unsigned int N, class T1, class S1,
                           class T2, class S2>
-inline void 
+inline void
 gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
                           MultiArrayView<N, T2, S2> dest,
                           ConvolutionOptions<N> const & opt)
@@ -1618,7 +1684,7 @@ gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
 
 template <unsigned int N, class T1, int M, class S1,
                           class T2, class S2>
-inline void 
+inline void
 gaussianGradientMagnitude(MultiArrayView<N, TinyVector<T1, M>, S1> const & src,
                           MultiArrayView<N, T2, S2> dest,
                           ConvolutionOptions<N> const & opt)
@@ -1628,7 +1694,7 @@ gaussianGradientMagnitude(MultiArrayView<N, TinyVector<T1, M>, S1> const & src,
 
 template <unsigned int N, class T1, unsigned int R, unsigned int G, unsigned int B, class S1,
                           class T2, class S2>
-inline void 
+inline void
 gaussianGradientMagnitude(MultiArrayView<N, RGBValue<T1, R, G, B>, S1> const & src,
                           MultiArrayView<N, T2, S2> dest,
                           ConvolutionOptions<N> const & opt)
@@ -1638,7 +1704,7 @@ gaussianGradientMagnitude(MultiArrayView<N, RGBValue<T1, R, G, B>, S1> const & s
 
 template <unsigned int N, class T1, class S1,
                           class T2, class S2>
-inline void 
+inline void
 gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
                           MultiArrayView<N, T2, S2> dest,
                           double sigma,
@@ -1649,7 +1715,7 @@ gaussianGradientMagnitude(MultiArrayView<N, T1, S1> const & src,
 
 template <unsigned int N, class T1, class S1,
                           class T2, class S2>
-inline void 
+inline void
 gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<T1>, S1> const & src,
                           MultiArrayView<N, T2, S2> dest,
                           double sigma,
@@ -1668,26 +1734,42 @@ gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<T1>, S1> const & src,
 
     This function computes the gradient of the given N-dimensional
     array with a sequence of symmetric difference filters a (differentiation is applied
-    to each dimension in turn, starting with the innermost dimension). 
+    to each dimension in turn, starting with the innermost dimension).
     The destination array is required to have a vector valued pixel type with as many
     elements as the number of dimensions. This function is implemented by calls to
     \ref convolveMultiArrayOneDimension() with the symmetric difference kernel.
 
-    Anisotropic data should be passed with appropriate
-    \ref ConvolutionOptions, the parameter <tt>opt</tt> is optional
-    otherwise.
-    
+    Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
+    to adjust the filter sizes for the resolution of each axis.
+    Otherwise, the parameter <tt>opt</tt> is optional unless the parameter
+    <tt>sigma</tt> is omitted.
+
+    If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
+    be executed in parallel on data blocks of a certain size. The block size can be
+    customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
+    usually work reasonably. By default, the number of threads equals the capabilities
+    of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
+
     <b> Declarations:</b>
 
     pass arbitrary-dimensional array views:
     \code
     namespace vigra {
+        // execute algorithm sequentially
         template <unsigned int N, class T1, class S1,
                                   class T2, class S2>
         void
         symmetricGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
                                     MultiArrayView<N, TinyVector<T2, N>, S2> dest,
                                     ConvolutionOptions<N> opt = ConvolutionOptions<N>());
+
+        // execute algorithm in parallel
+        template <unsigned int N, class T1, class S1,
+                                  class T2, class S2>
+        void
+        symmetricGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
+                                    MultiArrayView<N, TinyVector<T2, N>, S2> dest,
+                                    BlockwiseConvolutionOptions<N> opt);
     }
     \endcode
 
@@ -1718,7 +1800,8 @@ gaussianGradientMagnitude(MultiArrayView<N+1, Multiband<T1>, S1> const & src,
 
     <b> Usage:</b>
 
-    <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
+    <b>\#include</b> \<vigra/multi_convolution.hxx\> (sequential version)<br/>
+    <b>\#include</b> \<vigra/multi_blockwise.hxx\> (parallel version)<br/>
     Namespace: vigra
 
     \code
@@ -1831,13 +1914,20 @@ symmetricGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
 
     This function computes the Laplacian of the given N-dimensional
     array with a sequence of second-derivative-of-Gaussian filters at the given
-    standard deviation <tt>sigma</tt>. Both source and destination 
+    standard deviation <tt>sigma</tt>. Both source and destination
     arrays must have scalar value_type. This function is implemented by calls to
     \ref separableConvolveMultiArray() with the appropriate kernels, followed by summation.
 
-    Anisotropic data should be passed with appropriate
-    \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise optional
-    unless the parameter <tt>sigma</tt> is left out.
+    Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
+    to adjust the filter sizes for the resolution of each axis.
+    Otherwise, the parameter <tt>opt</tt> is optional unless the parameter
+    <tt>sigma</tt> is omitted.
+
+    If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
+    be executed in parallel on data blocks of a certain size. The block size can be
+    customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
+    usually work reasonably. By default, the number of threads equals the capabilities
+    of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
 
     <b> Declarations:</b>
 
@@ -1852,7 +1942,7 @@ symmetricGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
                                       MultiArrayView<N, T2, S2> dest,
                                       double sigma,
                                       ConvolutionOptions<N> opt = ConvolutionOptions<N>());
-        
+
         // pass scale(s) in option object
         template <unsigned int N, class T1, class S1,
                   class T2, class S2>
@@ -1860,6 +1950,14 @@ symmetricGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
         laplacianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
                                       MultiArrayView<N, T2, S2> dest,
                                       ConvolutionOptions<N> opt );
+
+        // likewise, but execute algorithm in parallel
+        template <unsigned int N, class T1, class S1,
+                  class T2, class S2>
+        void
+        laplacianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
+                                      MultiArrayView<N, T2, S2> dest,
+                                      BlockwiseConvolutionOptions<N> opt );
     }
     \endcode
 
@@ -1892,7 +1990,8 @@ symmetricGradientMultiArray(MultiArrayView<N, T1, S1> const & source,
 
     <b> Usage:</b>
 
-    <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
+    <b>\#include</b> \<vigra/multi_convolution.hxx\> (sequential version)<br/>
+    <b>\#include</b> \<vigra/multi_blockwise.hxx\> (parallel version)<br/>
     Namespace: vigra
 
     \code
@@ -1927,16 +2026,16 @@ void
 laplacianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor src,
                               DestIterator di, DestAccessor dest,
                               ConvolutionOptions<SrcShape::static_size> const & opt )
-{ 
+{
     using namespace functor;
-    
+
     typedef typename DestAccessor::value_type DestType;
     typedef typename NumericTraits<DestType>::RealPromote KernelType;
     typedef typename AccessorTraits<KernelType>::default_accessor DerivativeAccessor;
 
     static const int N = SrcShape::static_size;
     typedef typename ConvolutionOptions<N>::ScaleIterator ParamType;
-    
+
     ParamType params = opt.scaleParams();
     ParamType params2(params);
 
@@ -1946,11 +2045,11 @@ laplacianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAccesso
         double sigma = params.sigma_scaled("laplacianOfGaussianMultiArray");
         plain_kernels[dim].initGaussian(sigma, 1.0, opt.window_ratio);
     }
-    
+
     SrcShape dshape(shape);
     if(opt.to_point != SrcShape())
         dshape = opt.to_point - opt.from_point;
-    
+
     MultiArray<N, KernelType> derivative(dshape);
 
     // compute 2nd derivatives and sum them up
@@ -1962,15 +2061,15 @@ laplacianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAccesso
 
         if (dim == 0)
         {
-            separableConvolveMultiArray( si, shape, src, 
+            separableConvolveMultiArray( si, shape, src,
                                          di, dest, kernels.begin(), opt.from_point, opt.to_point);
         }
         else
         {
-            separableConvolveMultiArray( si, shape, src, 
-                                         derivative.traverser_begin(), DerivativeAccessor(), 
+            separableConvolveMultiArray( si, shape, src,
+                                         derivative.traverser_begin(), DerivativeAccessor(),
                                          kernels.begin(), opt.from_point, opt.to_point);
-            combineTwoMultiArrays(di, dshape, dest, derivative.traverser_begin(), DerivativeAccessor(), 
+            combineTwoMultiArrays(di, dshape, dest, derivative.traverser_begin(), DerivativeAccessor(),
                                   di, dest, Arg1() + Arg2() );
         }
     }
@@ -2060,9 +2159,16 @@ laplacianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
     This function is implemented by calls to
     \ref separableConvolveMultiArray() with the suitable kernels, followed by summation.
 
-    Anisotropic data should be passed with appropriate
-    \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise optional
-    unless the parameter <tt>sigma</tt> is omitted.
+    Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
+    to adjust the filter sizes for the resolution of each axis.
+    Otherwise, the parameter <tt>opt</tt> is optional unless the parameter
+    <tt>sigma</tt> is omitted.
+
+    If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
+    be executed in parallel on data blocks of a certain size. The block size can be
+    customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
+    usually work reasonably. By default, the number of threads equals the capabilities
+    of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
 
     <b> Declarations:</b>
 
@@ -2070,42 +2176,52 @@ laplacianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
     \code
     namespace vigra {
         // specify input vector field as a sequence of scalar arrays
-        template <class Iterator, 
+        template <class Iterator,
                   unsigned int N, class T, class S>
-        void 
+        void
         gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
                                      MultiArrayView<N, T, S> divergence,
                                      ConvolutionOptions<N> const & opt);
-        
-        template <class Iterator, 
+
+        template <class Iterator,
                   unsigned int N, class T, class S>
-        void 
+        void
         gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
                                      MultiArrayView<N, T, S> divergence,
                                      double sigma,
                                      ConvolutionOptions<N> opt = ConvolutionOptions<N>());
-        
+
         // pass input vector field as an array of vectors
         template <unsigned int N, class T1, class S1,
                                   class T2, class S2>
-        void 
+        void
         gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & vectorField,
                                      MultiArrayView<N, T2, S2> divergence,
                                      ConvolutionOptions<N> const & opt);
-                                     
+
         template <unsigned int N, class T1, class S1,
                                   class T2, class S2>
-        void 
+        void
         gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & vectorField,
                                      MultiArrayView<N, T2, S2> divergence,
                                      double sigma,
                                      ConvolutionOptions<N> opt = ConvolutionOptions<N>());
+
+        // pass input vector field as an array of vectors and
+        // execute algorithm in parallel
+        template <unsigned int N, class T1, class S1,
+                                  class T2, class S2>
+        void
+        gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & vectorField,
+                                     MultiArrayView<N, T2, S2> divergence,
+                                     BlockwiseConvolutionOptions<N> const & opt);
     }
     \endcode
 
     <b> Usage:</b>
 
-    <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
+    <b>\#include</b> \<vigra/multi_convolution.hxx\> (sequential version)<br/>
+    <b>\#include</b> \<vigra/multi_blockwise.hxx\> (parallel version)<br/>
     Namespace: vigra
 
     \code
@@ -2132,9 +2248,9 @@ laplacianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
 */
 doxygen_overloaded_function(template <...> void gaussianDivergenceMultiArray)
 
-template <class Iterator, 
+template <class Iterator,
           unsigned int N, class T, class S>
-void 
+void
 gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
                              MultiArrayView<N, T, S> divergence,
                              ConvolutionOptions<N> opt)
@@ -2143,11 +2259,11 @@ gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
     typedef typename ArrayType::value_type                       SrcType;
     typedef typename NumericTraits<SrcType>::RealPromote         TmpType;
     typedef Kernel1D<double>                                     Kernel;
-    
+
     vigra_precondition(std::distance(vectorField, vectorFieldEnd) == N,
         "gaussianDivergenceMultiArray(): wrong number of input arrays.");
     // more checks are performed in separableConvolveMultiArray()
-    
+
     typename ConvolutionOptions<N>::ScaleIterator params = opt.scaleParams();
     ArrayVector<double> sigmas(N);
     ArrayVector<Kernel> kernels(N);
@@ -2156,9 +2272,9 @@ gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
         sigmas[k] = params.sigma_scaled("gaussianDivergenceMultiArray");
         kernels[k].initGaussian(sigmas[k], 1.0, opt.window_ratio);
     }
-    
+
     MultiArray<N, TmpType> tmpDeriv(divergence.shape());
-    
+
     for(unsigned int k=0; k < N; ++k, ++vectorField)
     {
         kernels[k].initGaussianDerivative(sigmas[k], 1, 1.0, opt.window_ratio);
@@ -2175,9 +2291,9 @@ gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
     }
 }
 
-template <class Iterator, 
+template <class Iterator,
           unsigned int N, class T, class S>
-inline void 
+inline void
 gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
                              MultiArrayView<N, T, S> divergence,
                              double sigma,
@@ -2188,7 +2304,7 @@ gaussianDivergenceMultiArray(Iterator vectorField, Iterator vectorFieldEnd,
 
 template <unsigned int N, class T1, class S1,
                           class T2, class S2>
-inline void 
+inline void
 gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & vectorField,
                              MultiArrayView<N, T2, S2> divergence,
                              ConvolutionOptions<N> const & opt)
@@ -2202,7 +2318,7 @@ gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & ve
 
 template <unsigned int N, class T1, class S1,
                           class T2, class S2>
-inline void 
+inline void
 gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & vectorField,
                              MultiArrayView<N, T2, S2> divergence,
                              double sigma,
@@ -2221,15 +2337,22 @@ gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & ve
 
     This function computes the Hessian matrix the given scalar N-dimensional
     array with a sequence of second-derivative-of-Gaussian filters at the given
-    standard deviation <tt>sigma</tt>. The destination array must 
+    standard deviation <tt>sigma</tt>. The destination array must
     have a vector valued element type with N*(N+1)/2 elements (it represents the
-    upper triangular part of the symmetric Hessian matrix, flattened row-wise). 
+    upper triangular part of the symmetric Hessian matrix, flattened row-wise).
     This function is implemented by calls to
     \ref separableConvolveMultiArray() with the appropriate kernels.
 
-    Anisotropic data should be passed with appropriate
-    \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise optional
-    unless the parameter <tt>sigma</tt> is omitted.
+    Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
+    to adjust the filter sizes for the resolution of each axis.
+    Otherwise, the parameter <tt>opt</tt> is optional unless the parameter
+    <tt>sigma</tt> is omitted.
+
+    If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
+    be executed in parallel on data blocks of a certain size. The block size can be
+    customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
+    usually work reasonably. By default, the number of threads equals the capabilities
+    of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
 
     <b> Declarations:</b>
 
@@ -2244,7 +2367,7 @@ gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & ve
                                     MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>, S2> dest,
                                     double sigma,
                                     ConvolutionOptions<N> opt = ConvolutionOptions<N>());
-        
+
         // pass scale(s) in option object
         template <unsigned int N, class T1, class S1,
                                   class T2, class S2>
@@ -2252,6 +2375,14 @@ gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & ve
         hessianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
                                     MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>, S2> dest,
                                     ConvolutionOptions<N> opt);
+
+        // likewise, but execute algorithm in parallel
+        template <unsigned int N, class T1, class S1,
+                                  class T2, class S2>
+        void
+        hessianOfGaussianMultiArray(MultiArrayView<N, T1, S1> const & source,
+                                    MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>, S2> dest,
+                                    BlockwiseConvolutionOptions<N> opt);
     }
     \endcode
 
@@ -2284,7 +2415,8 @@ gaussianDivergenceMultiArray(MultiArrayView<N, TinyVector<T1, N>, S1> const & ve
 
     <b> Usage:</b>
 
-    <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
+    <b>\#include</b> \<vigra/multi_convolution.hxx\> (sequential version)<br/>
+    <b>\#include</b> \<vigra/multi_blockwise.hxx\> (parallel version)<br/>
     Namespace: vigra
 
     \code
@@ -2319,7 +2451,7 @@ void
 hessianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor src,
                             DestIterator di, DestAccessor dest,
                             ConvolutionOptions<SrcShape::static_size> const & opt )
-{ 
+{
     typedef typename DestAccessor::value_type DestType;
     typedef typename DestType::value_type     DestValueType;
     typedef typename NumericTraits<DestValueType>::RealPromote KernelType;
@@ -2327,7 +2459,7 @@ hessianOfGaussianMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor
     static const int N = SrcShape::static_size;
     static const int M = N*(N+1)/2;
     typedef typename ConvolutionOptions<N>::ScaleIterator ParamType;
-    
+
     for(int k=0; k<N; ++k)
         if(shape[k] <=0)
             return;
@@ -2447,7 +2579,7 @@ struct StructurTensorFunctor
 {
     typedef VectorType result_type;
     typedef typename VectorType::value_type ValueType;
-    
+
     template <class T>
     VectorType operator()(T const & in) const
     {
@@ -2474,19 +2606,25 @@ struct StructurTensorFunctor
 /** \brief Calculate th structure tensor of a multi-dimensional arrays.
 
     This function computes the gradient (outer product) tensor for each element
-    of the given N-dimensional array with first-derivative-of-Gaussian filters at 
+    of the given N-dimensional array with first-derivative-of-Gaussian filters at
     the given <tt>innerScale</tt>, followed by Gaussian smoothing at <tt>outerScale</tt>.
-    The destination array must have a vector valued pixel type with 
-    N*(N+1)/2 elements (it represents the upper triangular part of the symmetric 
-    structure tensor matrix, flattened row-wise). If the source array is also vector valued, the 
+    The destination array must have a vector valued pixel type with
+    N*(N+1)/2 elements (it represents the upper triangular part of the symmetric
+    structure tensor matrix, flattened row-wise). If the source array is also vector valued, the
     resulting structure tensor is the sum of the individual tensors for each channel.
     This function is implemented by calls to
     \ref separableConvolveMultiArray() with the appropriate kernels.
 
-    Anisotropic data should be passed with appropriate
-    \ref ConvolutionOptions, the parameter <tt>opt</tt> is otherwise optional
-    unless the parameters <tt>innerScale</tt> and <tt>outerScale</tt> are
-    both omitted.
+    Anisotropic data should be provided with appropriate \ref vigra::ConvolutionOptions
+    to adjust the filter sizes for the resolution of each axis.
+    Otherwise, the parameter <tt>opt</tt> is optional unless the parameters
+    <tt>innerScale</tt> and <tt>outerScale</tt> are both omitted.
+
+    If you pass \ref vigra::BlockwiseConvolutionOptions instead, the algorithm will
+    be executed in parallel on data blocks of a certain size. The block size can be
+    customized via <tt>BlockwiseConvolutionOptions::blockShape()</tt>, but the defaults
+    usually work reasonably. By default, the number of threads equals the capabilities
+    of your hardware, but you can change this via <tt>BlockwiseConvolutionOptions::numThreads()</tt>.
 
     <b> Declarations:</b>
 
@@ -2501,14 +2639,22 @@ struct StructurTensorFunctor
                                   MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>, S2> dest,
                                   double innerScale, double outerScale,
                                   ConvolutionOptions<N> opt = ConvolutionOptions<N>());
-        
+
         // pass scales in option object
         template <unsigned int N, class T1, class S1,
                                   class T2, class S2>
         void
         structureTensorMultiArray(MultiArrayView<N, T1, S1> const & source,
-                                  MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>, S2> dest, 
+                                  MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>, S2> dest,
                                   ConvolutionOptions<N> opt );
+
+        // likewise, but execute algorithm in parallel
+        template <unsigned int N, class T1, class S1,
+                                  class T2, class S2>
+        void
+        structureTensorMultiArray(MultiArrayView<N, T1, S1> const & source,
+                                  MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>, S2> dest,
+                                  BlockwiseConvolutionOptions<N> opt );
     }
     \endcode
 
@@ -2541,7 +2687,8 @@ struct StructurTensorFunctor
 
     <b> Usage:</b>
 
-    <b>\#include</b> \<vigra/multi_convolution.hxx\><br/>
+    <b>\#include</b> \<vigra/multi_convolution.hxx\> (sequential version)<br/>
+    <b>\#include</b> \<vigra/multi_blockwise.hxx\> (parallel version)<br/>
     Namespace: vigra
 
     \code
@@ -2574,12 +2721,12 @@ template <class SrcIterator, class SrcShape, class SrcAccessor,
           class DestIterator, class DestAccessor>
 void
 structureTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor src,
-                          DestIterator di, DestAccessor dest, 
+                          DestIterator di, DestAccessor dest,
                           ConvolutionOptions<SrcShape::static_size> opt)
 {
     static const int N = SrcShape::static_size;
     static const int M = N*(N+1)/2;
-    
+
     typedef typename DestAccessor::value_type DestType;
     typedef typename DestType::value_type     DestValueType;
     typedef typename NumericTraits<DestValueType>::RealPromote KernelType;
@@ -2593,17 +2740,17 @@ structureTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor sr
 
     vigra_precondition(M == (int)dest.size(di),
         "structureTensorMultiArray(): Wrong number of channels in output array.");
-        
+
     ConvolutionOptions<N> innerOptions = opt;
     ConvolutionOptions<N> outerOptions = opt.outerOptions();
     typename ConvolutionOptions<N>::ScaleIterator params = outerOptions.scaleParams();
-    
+
     SrcShape gradientShape(shape);
     if(opt.to_point != SrcShape())
     {
         detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, opt.from_point);
         detail::RelativeToAbsoluteCoordinate<N-1>::exec(shape, opt.to_point);
-        
+
         for(int k=0; k<N; ++k, ++params)
         {
             Kernel1D<double> gauss;
@@ -2619,16 +2766,16 @@ structureTensorMultiArray(SrcIterator si, SrcShape const & shape, SrcAccessor sr
 
     MultiArray<N, GradientVector> gradient(gradientShape);
     MultiArray<N, DestType> gradientTensor(gradientShape);
-    gaussianGradientMultiArray(si, shape, src, 
-                               gradient.traverser_begin(), GradientAccessor(), 
+    gaussianGradientMultiArray(si, shape, src,
+                               gradient.traverser_begin(), GradientAccessor(),
                                innerOptions,
                                "structureTensorMultiArray");
 
-    transformMultiArray(gradient.traverser_begin(), gradientShape, GradientAccessor(), 
-                        gradientTensor.traverser_begin(), GradientTensorAccessor(), 
+    transformMultiArray(gradient.traverser_begin(), gradientShape, GradientAccessor(),
+                        gradientTensor.traverser_begin(), GradientTensorAccessor(),
                         detail::StructurTensorFunctor<N, DestType>());
 
-    gaussianSmoothMultiArray(gradientTensor.traverser_begin(), gradientShape, GradientTensorAccessor(), 
+    gaussianSmoothMultiArray(gradientTensor.traverser_begin(), gradientShape, GradientTensorAccessor(),
                              di, dest, outerOptions,
                              "structureTensorMultiArray");
 }
@@ -2649,7 +2796,7 @@ template <class SrcIterator, class SrcShape, class SrcAccessor,
           class DestIterator, class DestAccessor>
 inline void
 structureTensorMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & source,
-                          pair<DestIterator, DestAccessor> const & dest, 
+                          pair<DestIterator, DestAccessor> const & dest,
                           ConvolutionOptions<SrcShape::static_size> const & opt )
 {
     structureTensorMultiArray( source.first, source.second, source.third,
@@ -2674,7 +2821,7 @@ template <unsigned int N, class T1, class S1,
                           class T2, class S2>
 inline void
 structureTensorMultiArray(MultiArrayView<N, T1, S1> const & source,
-                          MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>, S2> dest, 
+                          MultiArrayView<N, TinyVector<T2, int(N*(N+1)/2)>, S2> dest,
                           ConvolutionOptions<N> opt )
 {
     if(opt.to_point != typename MultiArrayShape<N>::type())
diff --git a/include/vigra/multi_distance.hxx b/include/vigra/multi_distance.hxx
index 8482be7..a8e8d19 100644
--- a/include/vigra/multi_distance.hxx
+++ b/include/vigra/multi_distance.hxx
@@ -1,7 +1,7 @@
 /************************************************************************/
 /*                                                                      */
-/*     Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn       */
-/*                        and Ullrich Koethe                            */
+/*     Copyright 2003-2007 by Kasim Terzic, Christian-Dennis Rahn,      */
+/*                            Philipp Schubert and Ullrich Koethe       */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -48,6 +48,9 @@
 #include "multi_pointoperators.hxx"
 #include "functorexpression.hxx"
 
+#include "multi_gridgraph.hxx"     //for boundaryGraph & boundaryMultiDistance
+#include "union_find.hxx"        //for boundaryGraph & boundaryMultiDistance
+
 namespace vigra
 {
 
@@ -58,10 +61,10 @@ template <class Value>
 struct DistParabolaStackEntry
 {
     double left, center, right;
-    Value prevVal;
+    Value apex_height;
     
     DistParabolaStackEntry(Value const & p, double l, double c, double r)
-    : left(l), center(c), right(r), prevVal(p)
+    : left(l), center(c), right(r), apex_height(p)
     {}
 };
 
@@ -93,31 +96,31 @@ void distParabola(SrcIterator is, SrcIterator iend, SrcAccessor sa,
     
     ++is;
     double current = 1.0;
-    while(current < w )
+    for(;current < w; ++is, ++current)
     {
-        Influence & s = _stack.back();
-        double diff = current - s.center;
-        double intersection = current + (sa(is) - s.prevVal - sigma2*sq(diff)) / (sigma22 * diff);
+        double intersection;
         
-        if( intersection < s.left) // previous point has no influence
+        while(true)
         {
-            _stack.pop_back();
-            if(_stack.empty())
+            Influence & s = _stack.back();
+            double diff = current - s.center;
+            intersection = current + (sa(is) - s.apex_height - sigma2*sq(diff)) / (sigma22 * diff);
+            
+            if( intersection < s.left) // previous point has no influence
             {
-                _stack.push_back(Influence(sa(is), 0.0, current, w));
+                _stack.pop_back();
+                if(!_stack.empty())
+                    continue;  // try new top of stack without advancing current
+                else
+                    intersection = 0.0;
             }
-            else
+            else if(intersection < s.right)
             {
-                continue; // try new top of stack without advancing current
+                s.right = intersection;
             }
+            break;
         }
-        else if(intersection < s.right)
-        {
-            s.right = intersection;
-            _stack.push_back(Influence(sa(is), intersection, current, w));
-        }
-        ++is;
-        ++current;
+        _stack.push_back(Influence(sa(is), intersection, current, w));
     }
 
     // Now we have the stack indicating which rows are influenced by (and therefore
@@ -128,7 +131,7 @@ void distParabola(SrcIterator is, SrcIterator iend, SrcAccessor sa,
     {
         while( current >= it->right) 
             ++it; 
-        da.set(sigma2 * sq(current - it->center) + it->prevVal, id);
+        da.set(sigma2 * sq(current - it->center) + it->apex_height, id);
     }
 }
 
@@ -234,10 +237,8 @@ inline void internalSeparableMultiArrayDistTmp( SrcIterator si, SrcShape const &
 
 /** \addtogroup MultiArrayDistanceTransform Euclidean distance transform for multi-dimensional arrays.
 
-    These functions perform the Euclidean distance transform an arbitrary dimensional
-    array that is specified by iterators (compatible to \ref MultiIteratorPage)
-    and shape objects. It can therefore be applied to a wide range of data structures
-    (\ref vigra::MultiArrayView, \ref vigra::MultiArray etc.).
+    These functions perform variants of the Euclidean distance transform on 
+    arbitrary dimensional arrays. 
 */
 //@{
 
@@ -576,7 +577,7 @@ separableMultiDistSquared(MultiArrayView<N, T1, S1> const & source,
     MultiArray<3, float> dest(shape);
     ...
 
-    // Calculate Euclidean distance squared for all background pixels 
+    // Calculate Euclidean distance for all background pixels 
     separableMultiDistance(source, dest, true);
     \endcode
 
@@ -657,6 +658,305 @@ separableMultiDistance(MultiArrayView<N, T1, S1> const & source,
                             destMultiArray(dest), background );
 }
 
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% BoundaryDistanceTransform %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+//rewrite labeled data and work with separableMultiDist
+namespace lemon_graph { 
+
+template <class Graph, class T1Map, class T2Map>
+void 
+markRegionBoundaries(Graph const & g,
+                     T1Map const & labels,
+                     T2Map & out)
+{
+    typedef typename Graph::NodeIt        graph_scanner;
+    typedef typename Graph::OutBackArcIt  neighbor_iterator;
+
+    //find faces
+    for (graph_scanner node(g); node != INVALID; ++node) 
+    {
+        typename T1Map::value_type center = labels[*node];
+        
+        for (neighbor_iterator arc(g, node); arc != INVALID; ++arc)
+        {
+            // set adjacent nodes with different labels to 1
+            if(center != labels[g.target(*arc)])
+            {
+                out[*node] = 1;
+                out[g.target(*arc)] = 1;
+            }
+        }
+    }
+}
+
+} //-- namspace lemon_graph
+
+doxygen_overloaded_function(template <...> unsigned int markRegionBoundaries)
+
+template <unsigned int N, class T1, class S1,
+                          class T2, class S2>
+inline void
+markRegionBoundaries(MultiArrayView<N, T1, S1> const & labels,
+                     MultiArrayView<N, T2, S2> out,
+                     NeighborhoodType neighborhood=DirectNeighborhood)
+{
+    vigra_precondition(labels.shape() == out.shape(),
+        "markRegionBoundaries(): shape mismatch between input and output.");
+
+    GridGraph<N, undirected_tag> graph(labels.shape(), neighborhood);
+
+    lemon_graph::markRegionBoundaries(graph, labels, out);
+}
+
+//MultiDistance which works directly on labeled data
+
+namespace detail
+{
+
+/********************************************************/
+/*                                                      */
+/*                boundaryDistParabola                  */
+/*                                                      */
+/********************************************************/
+
+template <class DestIterator, class LabelIterator>
+void 
+boundaryDistParabola(DestIterator is, DestIterator iend, 
+                     LabelIterator ilabels, 
+                     double dmax,
+                     bool array_border_is_active=false)
+{
+    // We assume that the data in the input is distance squared and treat it as such
+    double w = iend - is;
+    if(w <= 0)
+        return;
+
+    DestIterator id = is;
+    typedef typename LabelIterator::value_type LabelType;
+    typedef typename DestIterator::value_type DestType;
+    typedef detail::DistParabolaStackEntry<DestType> Influence;
+    typedef std::vector<Influence> Stack;
+
+    double apex_height = array_border_is_active
+                             ? 0.0
+                             : dmax;
+    Stack _stack(1, Influence(apex_height, 0.0, -1.0, w));
+    LabelType current_label = *ilabels;
+    for(double begin = 0.0, current = 0.0; current <= w; ++ilabels, ++is, ++current)
+    {
+        apex_height = (current < w)
+                          ? (current_label == *ilabels)
+                               ? *is
+                               : 0.0
+                          : array_border_is_active
+                                ? 0.0
+                                : dmax;
+        while(true)
+        {
+            Influence & s = _stack.back();
+            double diff = current - s.center;
+            double intersection = current + (apex_height - s.apex_height - sq(diff)) / (2.0 * diff);
+            
+            if(intersection < s.left) // previous parabola has no influence
+            {
+                _stack.pop_back();
+                if(_stack.empty())
+                    intersection = begin; // new parabola is valid for entire present segment
+                else
+                    continue;  // try new top of stack without advancing to next pixel
+            }
+            else if(intersection < s.right)
+            {
+                s.right = intersection;
+            }
+            if(intersection < w)
+                _stack.push_back(Influence(apex_height, intersection, current, w));
+            if(current < w && current_label == *ilabels)
+                break; // finished present pixel, advance to next one
+                
+            // label changed => finalize the current segment
+            typename Stack::iterator it = _stack.begin();
+            for(double c = begin; c < current; ++c, ++id)
+            {
+                while(c >= it->right) 
+                    ++it; 
+                *id = sq(c - it->center) + it->apex_height;
+            }
+            if(current == w)
+                break;  // stop when this was the last segment
+                
+            // initialize the new segment
+            begin = current;
+            current_label = *ilabels;
+            apex_height = *is;
+            Stack(1, Influence(0.0, begin-1.0, begin-1.0, w)).swap(_stack);
+            // don't advance to next pixel here, because the present pixel must also 
+            // be analysed in the context of the new segment
+        }
+    }
+}
+
+/********************************************************/
+/*                                                      */
+/*           internalBoundaryMultiArrayDist             */
+/*                                                      */
+/********************************************************/
+
+template <unsigned int N, class T1, class S1,
+                          class T2, class S2>
+void
+internalBoundaryMultiArrayDist(
+                      MultiArrayView<N, T1, S1> const & labels,
+                      MultiArrayView<N, T2, S2> dest,
+                      double dmax, bool array_border_is_active=false)
+{
+    typedef typename MultiArrayView<N, T1, S1>::const_traverser LabelIterator;
+    typedef typename MultiArrayView<N, T2, S2>::traverser DestIterator;
+    typedef MultiArrayNavigator<LabelIterator, N> LabelNavigator;
+    typedef MultiArrayNavigator<DestIterator, N> DNavigator;
+    
+    dest = dmax;
+    for( int d = 0; d < N; ++d )
+    {
+        LabelNavigator lnav( labels.traverser_begin(), labels.shape(), d );
+        DNavigator dnav( dest.traverser_begin(), dest.shape(), d );
+
+        for( ; dnav.hasMore(); dnav++, lnav++ )
+        {
+            boundaryDistParabola(dnav.begin(), dnav.end(),
+                                 lnav.begin(), 
+                                 dmax, array_border_is_active);
+        }
+    }
+}
+
+} // namespace detail
+
+    /** \brief Specify which boundary is used for boundaryMultiDistance().  
+    
+    */
+enum BoundaryDistanceTag {
+    OuterBoundary,      ///< Pixels just outside of each region
+    InterpixelBoundary, ///< Half-integer points between pixels of different labels
+    InnerBoundary       ///< Pixels just inside of each region
+};
+
+/********************************************************/
+/*                                                      */
+/*             boundaryMultiDistance                    */
+/*                                                      */
+/********************************************************/
+
+/** \brief Euclidean distance to the implicit boundaries of a multi-dimensional label array.
+
+
+    <b> Declarations:</b>
+
+    pass arbitrary-dimensional array views:
+    \code
+    namespace vigra {
+        template <unsigned int N, class T1, class S1,
+                  class T2, class S2>
+        void
+        boundaryMultiDistance(MultiArrayView<N, T1, S1> const & labels,
+                              MultiArrayView<N, T2, S2> dest,
+                              bool array_border_is_active=false,
+                              BoundaryDistanceTag boundary=InterpixelBoundary);
+    }
+    \endcode
+    
+    This function computes the distance transform of a labeled image <i>simultaneously</i>
+    for all regions. Depending on the requested type of \a boundary, three modes
+    are supported:
+    <ul>
+    <li><tt>OuterBoundary</tt>: In each region, compute the distance to the nearest pixel not
+               belonging to that regions. This is the same as if a normal distance transform
+               where applied to a binary image containing just this region.</li>
+    <li><tt>InterpixelBoundary</tt> (default): Like <tt>OuterBoundary</tt>, but shift the distance
+               to the interpixel boundary by subtractiong 1/2. This make the distences consistent
+               accross boundaries.</li>
+    <li><tt>InnerBoundary</tt>: In each region, compute the distance to the nearest pixel in the 
+               region which is adjacent to the boundary. </li>
+    </ul>
+    If <tt>array_border_is_active=true</tt>, the 
+    outer border of the array (i.e. the interpixel boundary between the array 
+    and the infinite region) is also used. Otherwise (the default), regions 
+    touching the array border are treated as if they extended to infinity.
+    
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/multi_distance.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    Shape3 shape(width, height, depth);
+    MultiArray<3, unsigned char> source(shape);
+    MultiArray<3, UInt32> labels(shape);
+    MultiArray<3, float> dest(shape);
+    ...
+
+    // find regions (interpixel boundaries are implied)
+    labelMultiArray(source, labels);
+    
+    // Calculate Euclidean distance to interpixel boundary for all pixels 
+    boundaryMultiDistance(labels, dest);
+    \endcode
+
+    \see vigra::distanceTransform(), vigra::separableMultiDistance()
+*/
+doxygen_overloaded_function(template <...> void boundaryMultiDistance)
+
+template <unsigned int N, class T1, class S1,
+                          class T2, class S2>
+void
+boundaryMultiDistance(MultiArrayView<N, T1, S1> const & labels,
+                      MultiArrayView<N, T2, S2> dest,
+                      bool array_border_is_active=false,
+                      BoundaryDistanceTag boundary=InterpixelBoundary)
+{
+    vigra_precondition(labels.shape() == dest.shape(),
+        "boundaryMultiDistance(): shape mismatch between input and output.");
+        
+    using namespace vigra::functor;
+    
+    if(boundary == InnerBoundary)
+    {
+        MultiArray<N, unsigned char> boundaries(labels.shape());
+        
+        markRegionBoundaries(labels, boundaries, IndirectNeighborhood);
+        if(array_border_is_active)
+            initMultiArrayBorder(boundaries, 1, 1);
+        separableMultiDistance(boundaries, dest, true);
+    }
+    else
+    {
+        T2 offset = 0.0;
+        
+        if(boundary == InterpixelBoundary)
+        {
+            vigra_precondition(!NumericTraits<T2>::isIntegral::value,
+                "boundaryMultiDistance(..., InterpixelBoundary): output pixel type must be float or double.");
+            offset = T2(0.5);
+        }
+        double dmax = squaredNorm(labels.shape()) + N;
+        if(dmax > double(NumericTraits<T2>::max()))
+        {
+            // need a temporary array to avoid overflows
+            typedef typename NumericTraits<T2>::RealPromote Real;
+            MultiArray<N, Real> tmpArray(labels.shape());
+            detail::internalBoundaryMultiArrayDist(labels, tmpArray,
+                                                      dmax, array_border_is_active);
+            transformMultiArray(tmpArray, dest, sqrt(Arg1()) - Param(offset) );
+        }
+        else
+        {
+            // can work directly on the destination array
+            detail::internalBoundaryMultiArrayDist(labels, dest, dmax, array_border_is_active);
+            transformMultiArray(dest, dest, sqrt(Arg1()) - Param(offset) );
+        }
+    }
+}
+
 //@}
 
 } //-- namespace vigra
diff --git a/include/vigra/multi_fft.hxx b/include/vigra/multi_fft.hxx
index 695fdef..840c2cd 100644
--- a/include/vigra/multi_fft.hxx
+++ b/include/vigra/multi_fft.hxx
@@ -38,8 +38,10 @@
 
 #include "fftw3.hxx"
 #include "multi_array.hxx"
+#include "multi_math.hxx"
 #include "navigator.hxx"
 #include "copyimage.hxx"
+#include "threading.hxx"
 
 namespace vigra {
 
@@ -166,6 +168,37 @@ inline void moveDCToHalfspaceUpperLeft(MultiArrayView<N, T, C> a)
 namespace detail
 {
 
+#ifndef VIGRA_SINGLE_THREADED
+
+template <int DUMMY=0>
+class FFTWLock
+{
+  public:
+    threading::lock_guard<threading::mutex> guard_;
+    
+    FFTWLock()
+    : guard_(plan_mutex_)
+    {}
+    
+    static threading::mutex plan_mutex_;
+};
+
+template <int DUMMY>
+threading::mutex FFTWLock<DUMMY>::plan_mutex_;
+
+#else // VIGRA_SINGLE_THREADED
+
+template <int DUMMY=0>
+class FFTWLock
+{
+  public:
+    
+    FFTWLock()
+    {}
+};
+
+#endif // not VIGRA_SINGLE_THREADED
+
 inline fftw_plan 
 fftwPlanCreate(unsigned int N, int* shape, 
                FFTWComplex<double> * in,  int* instrides,  int instep,
@@ -925,6 +958,7 @@ class FFTWPlan
         */
     ~FFTWPlan()
     {
+        detail::FFTWLock<> lock;
         detail::fftwPlanDestroy(plan);
     }
 
@@ -1077,12 +1111,16 @@ FFTWPlan<N, Real>::initImpl(MI ins, MO outs, int SIGN, unsigned int planner_flag
         ototal[j] = outs.stride(j-1) / outs.stride(j);
     }
     
-    PlanType newPlan = detail::fftwPlanCreate(N, newShape.begin(), 
-                                  ins.data(), itotal.begin(), ins.stride(N-1),
-                                  outs.data(), ototal.begin(), outs.stride(N-1),
-                                  SIGN, planner_flags);
-    detail::fftwPlanDestroy(plan);
-    plan = newPlan;
+    {
+        detail::FFTWLock<> lock;
+        PlanType newPlan = detail::fftwPlanCreate(N, newShape.begin(), 
+                                      ins.data(), itotal.begin(), ins.stride(N-1),
+                                      outs.data(), ototal.begin(), outs.stride(N-1),
+                                      SIGN, planner_flags);
+        detail::fftwPlanDestroy(plan);
+        plan = newPlan;
+    }
+    
     shape.swap(newShape);
     instrides.swap(newIStrides);
     outstrides.swap(newOStrides);
@@ -1417,7 +1455,10 @@ class FFTWConvolvePlan
     template <class C1, class C2, class C3>
     void execute(MultiArrayView<N, Real, C1> in, 
                  MultiArrayView<N, Real, C2> kernel,
-                 MultiArrayView<N, Real, C3> out);
+                 MultiArrayView<N, Real, C3> out)
+    {
+        executeImpl(in, kernel, out);
+    }
     
         /** \brief Execute a plan to convolve a real array with a complex kernel.
          
@@ -1485,7 +1526,7 @@ class FFTWConvolvePlan
         executeManyImpl(in, kernels, kernelsEnd, outs, UseFourierKernel());
     }
 
-  private:
+  protected:
   
     template <class KernelIterator, class OutIterator>
     Shape checkShapes(Shape in, 
@@ -1502,6 +1543,12 @@ class FFTWConvolvePlan
                              KernelIterator kernels, KernelIterator kernelsEnd,
                              OutIterator outs);
     
+    template <class C1, class C2, class C3>
+    void executeImpl(MultiArrayView<N, Real, C1> in, 
+                     MultiArrayView<N, Real, C2> kernel,
+                     MultiArrayView<N, Real, C3> out,
+                     bool do_correlation=false);
+    
     template <class C1, class KernelIterator, class OutIterator>
     void 
     executeManyImpl(MultiArrayView<N, Real, C1> in, 
@@ -1610,9 +1657,10 @@ FFTWConvolvePlan<N, Real>::initComplex(Shape in, Shape kernel,
 template <unsigned int N, class Real>
 template <class C1, class C2, class C3>
 void 
-FFTWConvolvePlan<N, Real>::execute(MultiArrayView<N, Real, C1> in, 
-                                    MultiArrayView<N, Real, C2> kernel,
-                                    MultiArrayView<N, Real, C3> out)
+FFTWConvolvePlan<N, Real>::executeImpl(MultiArrayView<N, Real, C1> in, 
+                                       MultiArrayView<N, Real, C2> kernel,
+                                       MultiArrayView<N, Real, C3> out,
+                                       bool do_correlation)
 {
     vigra_precondition(!useFourierKernel,
        "FFTWConvolvePlan::execute(): plan was generated for Fourier kernel, got spatial kernel.");
@@ -1634,8 +1682,16 @@ FFTWConvolvePlan<N, Real>::execute(MultiArrayView<N, Real, C1> in,
     detail::fftEmbedKernel(kernel, realKernel);
     forward_plan.execute(realKernel, fourierKernel);
     
-    fourierArray *= fourierKernel;
-    
+    if(do_correlation)
+    {
+        using namespace multi_math;
+        fourierArray *= conj(fourierKernel);
+    }
+    else
+    {
+        fourierArray *= fourierKernel;
+    }
+        
     backward_plan.execute(fourierArray, realArray);
     
     out = realArray.subarray(left, right);
@@ -1645,8 +1701,8 @@ template <unsigned int N, class Real>
 template <class C1, class C2, class C3>
 void 
 FFTWConvolvePlan<N, Real>::execute(MultiArrayView<N, Real, C1> in, 
-                                    MultiArrayView<N, FFTWComplex<Real>, C2> kernel,
-                                    MultiArrayView<N, Real, C3> out)
+                                   MultiArrayView<N, FFTWComplex<Real>, C2> kernel,
+                                   MultiArrayView<N, Real, C3> out)
 {
     vigra_precondition(useFourierKernel,
        "FFTWConvolvePlan::execute(): plan was generated for spatial kernel, got Fourier kernel.");
@@ -1927,6 +1983,123 @@ FFTWConvolvePlan<N, Real>::checkShapesComplex(Shape in,
     }
 }
  
+/********************************************************/
+/*                                                      */
+/*                  FFTWCorrelatePlan                   */
+/*                                                      */
+/********************************************************/
+
+/** Like FFTWConvolvePlan, but performs correlation rather than convolution.
+ 
+ See \ref vigra::FFTWConvolvePlan for details.
+ 
+ <b> Usage:</b>
+ 
+ <b>\#include</b> \<vigra/multi_fft.hxx\><br>
+ Namespace: vigra
+ 
+ \code
+ // convolve a real array with a real kernel
+ MultiArray<2, double> src(Shape2(w, h)), dest(Shape2(w, h));
+ 
+ MultiArray<2, double> spatial_kernel(Shape2(9, 9));
+ Gaussian<double> gauss(1.0);
+ 
+ for(int y=0; y<9; ++y)
+ for(int x=0; x<9; ++x)
+ spatial_kernel(x, y) = gauss(x-4.0)*gauss(y-4.0);
+ 
+ // create an optimized plan by measuring the speed of several algorithm variants
+ FFTWCorrelatePlan<2, double> plan(src, spatial_kernel, dest, FFTW_MEASURE);
+ 
+ plan.execute(src, spatial_kernel, dest);
+ \endcode
+ */
+template <unsigned int N, class Real>
+class FFTWCorrelatePlan
+: private FFTWConvolvePlan<N, Real>
+{
+    typedef FFTWConvolvePlan<N, Real> BaseType;
+public:
+    
+    typedef typename MultiArrayShape<N>::type Shape;
+    
+        /** \brief Create an empty plan.
+         
+         The plan can be initialized later by one of the init() functions.
+         */
+    FFTWCorrelatePlan()
+    : BaseType()
+    {}
+    
+        /** \brief Create a plan to correlate a real array with a real kernel.
+         
+         The kernel must be defined in the spatial domain.
+         See \ref correlateFFT() for detailed information on required shapes and internal padding.
+         
+         \arg planner_flags must be a combination of the
+         <a href="http://www.fftw.org/doc/Planner-Flags.html">planner
+         flags</a> defined by the FFTW library. The default <tt>FFTW_ESTIMATE</tt> will guess
+         optimal algorithm settings or read them from pre-loaded
+         <a href="http://www.fftw.org/doc/Wisdom.html">"wisdom"</a>.
+         */
+    template <class C1, class C2, class C3>
+    FFTWCorrelatePlan(MultiArrayView<N, Real, C1> in,
+                      MultiArrayView<N, Real, C2> kernel,
+                      MultiArrayView<N, Real, C3> out,
+                      unsigned int planner_flags = FFTW_ESTIMATE)
+    : BaseType(in, kernel, out, planner_flags)
+    {}
+    
+        /** \brief Create a plan from just the shape information.
+         
+         See \ref convolveFFT() for detailed information on required shapes and internal padding.
+         
+         \arg fourierDomainKernel determines if the kernel is defined in the spatial or
+         Fourier domain.
+         \arg planner_flags must be a combination of the
+         <a href="http://www.fftw.org/doc/Planner-Flags.html">planner
+         flags</a> defined by the FFTW library. The default <tt>FFTW_ESTIMATE</tt> will guess
+         optimal algorithm settings or read them from pre-loaded
+         <a href="http://www.fftw.org/doc/Wisdom.html">"wisdom"</a>.
+         */
+    template <class C1, class C2, class C3>
+    FFTWCorrelatePlan(Shape inOut, Shape kernel,
+                     bool useFourierKernel = false,
+                     unsigned int planner_flags = FFTW_ESTIMATE)
+    : BaseType(inOut, kernel, false, planner_flags)
+    {}
+    
+        /** \brief Init a plan to convolve a real array with a real kernel.
+         
+         See the constructor with the same signature for details.
+         */
+    template <class C1, class C2, class C3>
+    void init(MultiArrayView<N, Real, C1> in,
+              MultiArrayView<N, Real, C2> kernel,
+              MultiArrayView<N, Real, C3> out,
+              unsigned int planner_flags = FFTW_ESTIMATE)
+    {
+        vigra_precondition(in.shape() == out.shape(),
+                           "FFTWCorrelatePlan::init(): input and output must have the same shape.");
+        BaseType::init(in.shape(), kernel.shape(), planner_flags);
+    }
+    
+        /** \brief Execute a plan to correlate a real array with a real kernel.
+         
+         The array shapes must be the same as in the corresponding init function
+         or constructor. However, execute() can be called several times on
+         the same plan, even with different arrays, as long as they have the appropriate
+         shapes.
+         */
+    template <class C1, class C2, class C3>
+    void execute(MultiArrayView<N, Real, C1> in,
+                 MultiArrayView<N, Real, C2> kernel,
+                 MultiArrayView<N, Real, C3> out)
+    {
+        BaseType::executeImpl(in, kernel, out, true);
+    }
+};
 
 /********************************************************/
 /*                                                      */
@@ -2004,24 +2177,24 @@ fourierTransformInverse(MultiArrayView<N, FFTWComplex<Real>, C1> in,
     
     The following functions implement various variants of FFT-based convolution:
     
-        <DL>
-        <DT><b>convolveFFT</b><DD> Convolve a real-valued input array with a kernel such that the 
-                            result is also real-valued. That is, the kernel is either provided
-                            as a real-valued array in the spatial domain, or as a 
-                            complex-valued array in the Fourier domain, using the half-space format 
-                            of the R2C Fourier transform (see below).
-        <DT><b>convolveFFTMany</b><DD> Like <tt>convolveFFT</tt>, but you may provide many kernels at once 
-                            (using an iterator pair specifying the kernel sequence). 
-                            This has the advantage that the forward transform of the input array needs 
-                            to be executed only once.
-        <DT><b>convolveFFTComplex</b><DD> Convolve a complex-valued input array with a complex-valued kernel, 
-                            resulting in a complex-valued output array. An additional flag is used to 
-                            specify whether the kernel is defined in the spatial or frequency domain.
-        <DT><b>convolveFFTComplexMany</b><DD> Like <tt>convolveFFTComplex</tt>, but you may provide many kernels at once 
-                            (using an iterator pair specifying the kernel sequence). 
-                            This has the advantage that the forward transform of the input array needs 
-                            to be executed only once.
-        </DL>
+    <DL>
+    <DT><b>convolveFFT</b><DD> Convolve a real-valued input array with a kernel such that the 
+                        result is also real-valued. That is, the kernel is either provided
+                        as a real-valued array in the spatial domain, or as a 
+                        complex-valued array in the Fourier domain, using the half-space format 
+                        of the R2C Fourier transform (see below).
+    <DT><b>convolveFFTMany</b><DD> Like <tt>convolveFFT</tt>, but you may provide many kernels at once 
+                        (using an iterator pair specifying the kernel sequence). 
+                        This has the advantage that the forward transform of the input array needs 
+                        to be executed only once.
+    <DT><b>convolveFFTComplex</b><DD> Convolve a complex-valued input array with a complex-valued kernel, 
+                        resulting in a complex-valued output array. An additional flag is used to 
+                        specify whether the kernel is defined in the spatial or frequency domain.
+    <DT><b>convolveFFTComplexMany</b><DD> Like <tt>convolveFFTComplex</tt>, but you may provide many 
+                        kernels at once (using an iterator pair specifying the kernel sequence). 
+                        This has the advantage that the forward transform of the input array needs 
+                        to be executed only once.
+    </DL>
     
     The output arrays must have the same shape as the input arrays. In the "Many" variants of the
     convolution functions, the kernels must all have the same shape.
@@ -2066,7 +2239,7 @@ fourierTransformInverse(MultiArrayView<N, FFTWComplex<Real>, C1> in,
     <tt>libfftw3f</tt> and <tt>libfftw3l</tt> respectively.
     
     The Fourier transform functions internally create <a href="http://www.fftw.org/doc/Using-Plans.html">FFTW plans</a>
-    which control the algorithm details. The plans are creates with the flag <tt>FFTW_ESTIMATE</tt>, i.e.
+    which control the algorithm details. The plans are created with the flag <tt>FFTW_ESTIMATE</tt>, i.e.
     optimal settings are guessed or read from saved "wisdom" files. If you need more control over planning,
     you can use the class \ref FFTWConvolvePlan.
     
@@ -2241,6 +2414,65 @@ convolveFFTComplexMany(MultiArrayView<N, FFTWComplex<Real>, C1> in,
     plan.initMany(in, kernels, kernelsEnd, outs, fourierDomainKernel);
     plan.executeMany(in, kernels, kernelsEnd, outs);
 }
+    
+/********************************************************/
+/*                                                      */
+/*                     correlateFFT                     */
+/*                                                      */
+/********************************************************/
+
+/** \brief Correlate an array with a kernel by means of the Fourier transform.
+ 
+ This function correlates a real-valued input array with a real-valued kernel 
+ such that the result is also real-valued. Thanks to the correlation theorem of 
+ Fourier theory, a correlation in the spatial domain is equivalent to a multiplication 
+ with the complex conjugate in the frequency domain. Thus, for
+ certain kernels (especially large, non-separable ones), it is advantageous to perform the 
+ correlation by first transforming both array and kernel to the frequency domain, multiplying
+ the frequency representations, and transforming the result back into the spatial domain.
+ 
+ The output arrays must have the same shape as the input arrays.
+ 
+ See also \ref convolveFFT() for corresponding functionality.
+ 
+ <b> Declarations:</b>
+ 
+ \code
+ namespace vigra {
+     template <unsigned int N, class Real, class C1, class C2, class C3>
+     void
+     correlateFFT(MultiArrayView<N, Real, C1> in,
+                  MultiArrayView<N, Real, C2> kernel,
+                  MultiArrayView<N, Real, C3> out);
+ }
+ \endcode
+ 
+ <b> Usage:</b>
+ 
+ <b>\#include</b> \<vigra/multi_fft.hxx\><br>
+ Namespace: vigra
+ 
+ \code
+ // correlate real array with a template to find best matches
+ // (implicitly uses padding by at least 4 pixels)
+ MultiArray<2, double> src(Shape2(w, h)), dest(Shape2(w, h));
+ 
+ MultiArray<2, double> template(Shape2(9, 9));
+ template = ...; 
+
+ correlateFFT(src, template, dest);
+ \endcode
+ */
+doxygen_overloaded_function(template <...> void correlateFFT)
+
+template <unsigned int N, class Real, class C1, class C2, class C3>
+void
+correlateFFT(MultiArrayView<N, Real, C1> in,
+            MultiArrayView<N, Real, C2> kernel,
+            MultiArrayView<N, Real, C3> out)
+{
+    FFTWCorrelatePlan<N, Real>(in, kernel, out).execute(in, kernel, out);
+}
 
 //@}
 
diff --git a/include/vigra/multi_fwd.hxx b/include/vigra/multi_fwd.hxx
new file mode 100644
index 0000000..4bb5335
--- /dev/null
+++ b/include/vigra/multi_fwd.hxx
@@ -0,0 +1,223 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2011-2014 by Ullrich Koethe                            */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_MULTI_FWD_HXX
+#define VIGRA_MULTI_FWD_HXX
+
+#include <memory>
+#include "metaprogramming.hxx"
+#include "tinyvector.hxx"
+
+namespace vigra {
+
+/** \addtogroup MultiIteratorGroup  Multi-dimensional Shapes and Array Iterators
+
+    \brief Shape objects and general iterators for arrays of arbitrary dimension.
+*/
+//@{
+
+/********************************************************/
+/*                                                      */
+/*                        shape                         */
+/*                                                      */
+/********************************************************/
+
+    /** Index type for a single dimension of a MultiArrayView or
+        MultiArray.
+    */
+typedef std::ptrdiff_t MultiArrayIndex;
+
+template <unsigned int N>
+class MultiArrayShape;
+
+/********************************************************/
+/*                                                      */
+/*                    memory layout                     */
+/*                                                      */
+/********************************************************/
+
+// the resulting MultiArray has no explicit channel axis
+// (i.e. the number of channels is implicitly one)
+template <class T>
+struct Singleband;
+
+// the last axis is explicitly designated as channel axis
+template <class T>
+struct Multiband;
+
+// the array is organised in chunks
+template <class T>
+struct ChunkedMemory;
+
+// helper classes to map memory layout to actual type
+namespace detail {
+
+template <class T>
+struct ResolveMultiband;
+
+template <class T>
+struct ResolveChunkedMemory;
+
+} // namespace detail
+
+/********************************************************/
+/*                                                      */
+/*                    constructor tag                   */
+/*                                                      */
+/********************************************************/
+
+    /** \brief Initialize a MultiArray in a standard way.  
+    
+    */
+enum MultiArrayInitializationTag {
+    LinearSequence ///< Initialize array by a linear sequence in scan order
+};
+
+/********************************************************/
+/*                                                      */
+/*                   element handles                    */
+/*                                                      */
+/********************************************************/
+
+template <class T, class NEXT>
+class CoupledHandle;
+
+template <unsigned int N, class T>
+class SharedChunkHandle;
+
+/********************************************************/
+/*                                                      */
+/*                     array types                      */
+/*                                                      */
+/********************************************************/
+
+template <unsigned int N, class T, class C = StridedArrayTag>
+class MultiArrayView;
+
+template <unsigned int N, class T, 
+          class A = std::allocator<typename detail::ResolveMultiband<T>::type> >
+class MultiArray;
+
+template <unsigned int N, class T>
+class ChunkedArrayBase;
+
+template <unsigned int N, class T>
+class ChunkedArray;
+
+/********************************************************/
+/*                                                      */
+/*                iterators / traversers                */
+/*                                                      */
+/********************************************************/
+
+// DEPRECATED!
+// hierarchical iterator whose innermost dimension is unstrided
+template <unsigned int N, class T, class REFERENCE = T &, class POINTER = T *>
+class MultiIterator;
+
+// DEPRECATED!
+// hierarchical iterator whose innermost dimension may be strided
+template <unsigned int N, class T, class REFERENCE = T &, class POINTER = T *>
+class StridedMultiIterator;
+
+// multi-dimensional scan-order iteration returning the coordinate of the current element
+template<unsigned int N>
+class MultiCoordinateIterator;
+
+// scan-order iteration returning the current element of a multi-dimensional array
+template <unsigned int N, class V, class REFERENCE, class POINTER>
+class StridedScanOrderIterator;
+
+// simultaneous scan-order iteration over several multi-dimensional arrays
+template <unsigned int N,
+          class HANDLES=CoupledHandle<TinyVector<MultiArrayIndex, N>, void>,
+          int DIMENSION = N-1>
+class CoupledScanOrderIterator;
+
+// scan-order iteration over the chunks of a chunked array
+// returns a MultiArrayView for the current chunk
+template<unsigned int N, class T>
+class ChunkIterator;
+
+/********************************************************/
+/*                                                      */
+/*                 neighborhood types                   */
+/*                                                      */
+/********************************************************/
+
+    /** \brief Choose the neighborhood system in a dimension-independent way.  
+    
+        DirectNeighborhood corresponds to 4-neighborhood in 2D and 6-neighborhood in 3D, whereas
+        IndirectNeighborhood means 8-neighborhood in 2D and 26-neighborhood in 3D. The general
+        formula for N dimensions are 2*N for direct neighborhood and 3^N-1 for indirect neighborhood. 
+    */
+enum NeighborhoodType { 
+        DirectNeighborhood=0,   ///< use only direct neighbors
+        IndirectNeighborhood=1  ///< use direct and indirect neighbors
+};
+
+
+/********************************************************/
+/*                                                      */
+/*                     grid graph                       */
+/*                                                      */
+/********************************************************/
+
+template<unsigned int N, bool BackEdgesOnly=false>
+class GridGraphNeighborIterator;
+
+template<unsigned int N, bool BackEdgesOnly=false>
+class GridGraphEdgeIterator;
+
+template<unsigned int N, bool BackEdgesOnly=false>
+class GridGraphOutEdgeIterator;
+
+template<unsigned int N, bool BackEdgesOnly=false>
+class GridGraphArcIterator;
+
+template<unsigned int N, bool BackEdgesOnly=false>
+class GridGraphOutArcIterator;
+
+template<unsigned int N, bool BackEdgesOnly=false>
+class GridGraphInArcIterator;
+
+template<unsigned int N, class DirectedTag>
+class GridGraph;
+
+//@}
+
+} // namespace vigra
+
+#endif // VIGRA_MULTI_FWD_HXX
diff --git a/include/vigra/multi_gridgraph.hxx b/include/vigra/multi_gridgraph.hxx
index 67c4c65..59f46c5 100644
--- a/include/vigra/multi_gridgraph.hxx
+++ b/include/vigra/multi_gridgraph.hxx
@@ -36,6 +36,7 @@
 #ifndef VIGRA_MULTI_GRIDGRAPH_HXX
 #define VIGRA_MULTI_GRIDGRAPH_HXX
 
+#include "multi_fwd.hxx"
 #include "multi_iterator.hxx"
 #include "multi_array.hxx"
 #include "graphs.hxx"
@@ -45,11 +46,23 @@ struct NeighborhoodTests;
 
 namespace vigra {
 
-/** \addtogroup GraphDataStructures Graph Data Structures
+template<unsigned int N, class T, class Stride>
+inline
+typename vigra::MultiArrayView<N, T, Stride>::const_reference 
+get(vigra::MultiArrayView<N, T, Stride> const & pmap,
+    typename vigra::MultiArrayView<N, T, Stride>::difference_type const & k)
+{ 
+    return pmap[k]; 
+}
+
+/** \addtogroup GraphDataStructures Graph Data Structures and Algorithms
+        
+        Graph algorithms and the underlying graph data structures (e.g. GridGraph and AdjacencyListGraph)
+        implementing the APIs of the 
+        <a href="http://www.boost.org/doc/libs/release/libs/graph/">boost::graph</a> and
+        <a href="http://lemon.cs.elte.hu/">LEMON</a> libraries. 
         
-        A GridGraph class implementing the APIs of the <a href="http://www.boost.org/doc/libs/release/libs/graph/">boost::graph</a> and
-        <a href="http://lemon.cs.elte.hu/">LEMON</a> libraries. See also
-        the \ref BoostGraphExtensions.
+        See also the \ref BoostGraphExtensions.
 */
 //@{
 
@@ -247,7 +260,7 @@ computeNeighborOffsets(ArrayVector<Shape> const & neighborOffsets,
 
 } // namespace detail
 
-template<unsigned int N, bool BackEdgesOnly=false>
+template<unsigned int N, bool BackEdgesOnly>
 class GridGraphNeighborIterator
 {
 public:
@@ -400,9 +413,6 @@ public:
 };
 
 template<unsigned int N, bool BackEdgesOnly>
-class GridGraphEdgeIterator;
-
-template<unsigned int N, bool BackEdgesOnly=false>
 class GridGraphOutEdgeIterator
 {
   public:
@@ -435,8 +445,13 @@ class GridGraphOutEdgeIterator
       edge_descriptor_(),
       index_(0)
     {
-        unsigned int nbtype = g.get_border_type(v);
-        init(&(*g.edgeIncrementArray())[nbtype], &(*g.neighborIndexArray(BackEdgesOnly))[nbtype], *v, opposite);
+        if(v.isValid()){
+            unsigned int nbtype = g.get_border_type(v);
+            init(&(*g.edgeIncrementArray())[nbtype], &(*g.neighborIndexArray(BackEdgesOnly))[nbtype], *v, opposite);
+        }
+        else{
+            index_ = (index_type)neighborIndices_->size();
+        }
     }
 
     template <class DirectedTag>
@@ -448,8 +463,13 @@ class GridGraphOutEdgeIterator
       edge_descriptor_(),
       index_(0)
     {
-        unsigned int nbtype = g.get_border_type(v);
-        init(&(*g.edgeIncrementArray())[nbtype], &(*g.neighborIndexArray(BackEdgesOnly))[nbtype], v, opposite);
+        if(isInside(g, v)){
+            unsigned int nbtype = g.get_border_type(v);
+            init(&(*g.edgeIncrementArray())[nbtype], &(*g.neighborIndexArray(BackEdgesOnly))[nbtype], v, opposite);
+        }
+        else{
+            index_ = (index_type)neighborIndices_->size();
+        }
     }
     
     GridGraphOutEdgeIterator & operator++()
@@ -567,7 +587,7 @@ class GridGraphOutEdgeIterator
     index_type index_;
 };
 
-template<unsigned int N, bool BackEdgesOnly=false>
+template<unsigned int N, bool BackEdgesOnly>
 class GridGraphOutArcIterator
 : public GridGraphOutEdgeIterator<N, BackEdgesOnly>
 {
@@ -648,7 +668,7 @@ class GridGraphOutArcIterator
     {}
 };
 
-template<unsigned int N, bool BackEdgesOnly=false>
+template<unsigned int N, bool BackEdgesOnly>
 class GridGraphInArcIterator
 : public GridGraphOutEdgeIterator<N, BackEdgesOnly>
 {
@@ -761,6 +781,42 @@ public:
         }
     }
 
+
+
+    template <class DirectedTag>
+    GridGraphEdgeIterator(GridGraph<N, DirectedTag> const & g, const typename  GridGraph<N, DirectedTag>::Edge & edge)
+    : neighborOffsets_(g.edgeIncrementArray()),
+      neighborIndices_(g.neighborIndexArray(BackEdgesOnly)),
+      vertexIterator_(g,g.u(edge)),
+      outEdgeIterator_(g, vertexIterator_)
+    {
+        if(vertexIterator_.isValid()){
+            // vigra_precondition(edge!=lemon::INVALID,"no invalid edges here");
+            // vigra_precondition( allLess(*vertexIterator_,g.shape()), "fixme1");
+            // vigra_precondition( allGreaterEqual(*vertexIterator_,shape_type() ), "fixme2");
+
+
+            if(edge[N] >= 0  && edge[N] < g.maxUniqueDegree( ) && 
+                (*( g.neighborExistsArray()))[vertexIterator_.borderType()][edge[N]] ){
+                while(*outEdgeIterator_!=edge){
+                    ++outEdgeIterator_;
+                }
+            }
+            else{
+                vertexIterator_ = vertexIterator_.getEndIterator();
+            }
+
+            // vigra_precondition(edge[N] >= 0 && edge[N] < g.maxUniqueDegree(),"fixme3");
+            // vigra_precondition(    ,"fixme4");
+            // vigra_precondition(!outEdgeIterator_.atEnd(),"fixme5");
+
+
+        }
+    }
+
+
+
+
     GridGraphEdgeIterator & operator++()
     {
         ++outEdgeIterator_;
@@ -797,6 +853,12 @@ public:
     {
         return outEdgeIterator_.operator->();
     }
+    
+    MultiArrayIndex neighborIndex() const
+    {
+        return outEdgeIterator_.neighborIndex();
+    }
+
 
     bool operator==(GridGraphEdgeIterator const & other) const
     {
@@ -995,8 +1057,8 @@ VIGRA_LEMON_INVALID_COMPARISON(GridGraphArcIterator)
 
 #undef VIGRA_LEMON_INVALID_COMPARISON
 
-using boost::directed_tag;
-using boost::undirected_tag;
+using boost_graph::directed_tag;
+using boost_graph::undirected_tag;
 
 namespace detail {
 
@@ -1017,7 +1079,7 @@ struct GridGraphBase<N, directed_tag>
         typedef typename base_type::value_type             value_type; 
         typedef typename base_type::reference              reference;
         typedef typename base_type::const_reference        const_reference;
-        typedef boost::read_write_property_map_tag         category;
+        typedef boost_graph::read_write_property_map_tag   category;
         
         typedef lemon::True                                ReferenceMapTag;
         typedef key_type                                   Key;
@@ -1082,7 +1144,7 @@ struct GridGraphBase<N, undirected_tag>
         typedef typename base_type::value_type             value_type; 
         typedef typename base_type::reference              reference;
         typedef typename base_type::const_reference        const_reference;
-        typedef boost::read_write_property_map_tag         category;
+        typedef boost_graph::read_write_property_map_tag   category;
         
         typedef lemon::True                                ReferenceMapTag;
         typedef key_type                                   Key;
@@ -1173,7 +1235,7 @@ struct GridGraphBase<N, undirected_tag>
 
     Another choice to be made at compile time is whether the graph should be directed 
     or undirected. This is defined via the <tt>DirectedTag</tt> template parameter
-    which can take the values <tt>directed_tag</tt> or <tt>undirected_tag</tt>.
+    which can take the values <tt>directed_tag</tt> or <tt>undirected_tag</tt> (default).
     
     The main difficulty in a grid graph is to skip the missing neighbors
     of the pixels near the grid's border. For example, the upper left pixel in a 
@@ -1361,7 +1423,7 @@ struct GridGraphBase<N, undirected_tag>
     A slightly enhanced version of this code is actually used to implement this
     functionality in VIGRA.
 */
-template<unsigned int N, class DirectedTag>
+template<unsigned int N, class DirectedTag=undirected_tag>
 class GridGraph
 : public detail::GridGraphBase<N, DirectedTag>
 {
@@ -1373,6 +1435,10 @@ public:
     typedef detail::GridGraphBase<N, DirectedTag>   base_type;
     typedef GridGraph<N, DirectedTag>               self_type;
     
+        /** \brief Dimension of the grid.
+        */
+    static const unsigned int dimension = N;
+    
         /** \brief Shape type of the graph and a node property map.
         */
     typedef typename MultiArrayShape<N>::type       shape_type;
@@ -1458,12 +1524,12 @@ public:
                   (API: boost::graph, use via 
                   <tt>boost::graph_traits<Graph>::edge_parallel_category</tt>).
         */
-    typedef boost::disallow_parallel_edge_tag       edge_parallel_category;
+    typedef boost_graph::disallow_parallel_edge_tag  edge_parallel_category;
     
         /** \brief The graph does not define internal property maps (API: boost::graph,
              use via <tt>boost::graph_traits<Graph>::vertex_property_type</tt>).
         */
-    typedef boost::no_property                      vertex_property_type; // we only support "external properties".
+    typedef boost_graph::no_property                 vertex_property_type; // we only support "external properties".
     // FIXME: Maybe support the vertex -> coordinate map (identity) as the only internal property map
     // and additionally the vertex_descriptor -> ID map (vertex_index = SOI).
 
@@ -1471,11 +1537,11 @@ public:
              use via <tt>boost::graph_traits<Graph>::traversal_category</tt>).
         */
     struct traversal_category 
-    : virtual public boost::bidirectional_graph_tag,
-      virtual public boost::adjacency_graph_tag,
-      virtual public boost::vertex_list_graph_tag,
-      virtual public boost::edge_list_graph_tag,
-      virtual public boost::adjacency_matrix_tag
+    : virtual public boost_graph::bidirectional_graph_tag,
+      virtual public boost_graph::adjacency_graph_tag,
+      virtual public boost_graph::vertex_list_graph_tag,
+      virtual public boost_graph::edge_list_graph_tag,
+      virtual public boost_graph::adjacency_matrix_tag
     {};
     
         // internal types
@@ -1483,6 +1549,9 @@ public:
     typedef ArrayVector<NeighborOffsetArray>             RelativeNeighborOffsetsArray;
     typedef ArrayVector<ArrayVector<edge_descriptor> >   RelativeEdgeOffsetsArray;
     typedef ArrayVector<ArrayVector<MultiArrayIndex> >   IndexArray;
+    typedef ArrayVector<ArrayVector<bool> >              NeighborExistsArray;
+        
+
 
     ////////////////////////////////////////////////////////////////////
     
@@ -1557,7 +1626,7 @@ public:
         typedef typename base_type::value_type             value_type; 
         typedef typename base_type::reference              reference;
         typedef typename base_type::const_reference        const_reference;
-        typedef boost::read_write_property_map_tag         category;
+        typedef boost_graph::read_write_property_map_tag   category;
         
         typedef lemon::True                                ReferenceMapTag;
         typedef key_type                                   Key;
@@ -1645,7 +1714,7 @@ public:
         typedef typename base_type::value_type             value_type; 
         typedef typename base_type::reference              reference;
         typedef typename base_type::const_reference        const_reference;
-        typedef boost::read_write_property_map_tag         category;
+        typedef boost_graph::read_write_property_map_tag   category;
         
         typedef lemon::True                                ReferenceMapTag;
         typedef key_type                                   Key;
@@ -1774,7 +1843,7 @@ public:
         typedef Key                                     key_type;
         typedef Value                                   value_type; 
         typedef Value const &                           reference;
-        typedef boost::readable_property_map_tag        category;
+        typedef boost_graph::readable_property_map_tag  category;
 
         IndexMap()
         {}
@@ -1806,7 +1875,7 @@ public:
         typedef Key                                     key_type;
         typedef Value                                   value_type; 
         typedef Value const &                           reference;
-        typedef boost::readable_property_map_tag        category;
+        typedef boost_graph::readable_property_map_tag  category;
         
             /** \brief Construct property map for the given graph.
             */
@@ -1840,7 +1909,7 @@ public:
         typedef Key                                     key_type;
         typedef Value                                   value_type; 
         typedef Value const &                           reference;
-        typedef boost::readable_property_map_tag        category;
+        typedef boost_graph::readable_property_map_tag  category;
         
             /** \brief Construct property map for the given graph.
             */
@@ -1855,7 +1924,6 @@ public:
             return graph_.out_degree(key);
         }
         
-      protected:
       
         GridGraph const & graph_;
     };
@@ -1864,6 +1932,9 @@ public:
     
         // dummy default constructor to satisfy adjacency_graph concept
     GridGraph()
+    : max_node_id_(-1), 
+      max_arc_id_(-1), 
+      max_edge_id_(-1)
     {}
         
         /** \brief Construct a grid graph with given \a shape and neighborhood type \a ntype.
@@ -1878,14 +1949,15 @@ public:
     : shape_(shape),
       num_vertices_(prod(shape)),
       num_edges_(gridGraphEdgeCount(shape, ntype, is_directed)), 
+      max_node_id_(num_vertices_ - 1), 
+      max_arc_id_(-2), 
+      max_edge_id_(-2), 
       neighborhoodType_(ntype)
     {
-        ArrayVector<ArrayVector<bool> > neighborExists;
-        
         // populate the neighborhood tables:
         // FIXME: this might be static (but make sure that it works with multi-threading)
-        detail::makeArrayNeighborhood(neighborOffsets_, neighborExists, neighborhoodType_);
-        detail::computeNeighborOffsets(neighborOffsets_, neighborExists, incrementalOffsets_, 
+        detail::makeArrayNeighborhood(neighborOffsets_, neighborExists_, neighborhoodType_);
+        detail::computeNeighborOffsets(neighborOffsets_, neighborExists_, incrementalOffsets_, 
                                        edgeDescriptorOffsets_, neighborIndices_, backIndices_, is_directed);
         
         // compute the neighbor offsets per neighborhood type
@@ -1915,9 +1987,14 @@ public:
     }
     
         /** \brief Get node descriptor for given node ID \a i (API: LEMON).
+        
+            Return <tt>Node(lemon::INVALID)</tt> when the ID does not exist in this graph.
         */
     Node nodeFromId(index_type i) const
     {
+        if(i < 0 || i > maxNodeId())
+            return Node(lemon::INVALID);
+        
         Node res(SkipInitialization);
         detail::ScanOrderToCoordinate<N>::exec(i, shape(), res);
         return res;
@@ -2043,25 +2120,61 @@ public:
     }
 
         /** \brief Get the edge descriptor for the given edge ID \a i (API: LEMON).
+        
+            Return <tt>Edge(lemon::INVALID)</tt> when the ID does not exist
+            in this graph. 
         */
     Edge edgeFromId(index_type i) const
     {
+        if(i < 0 || i > maxEdgeId())
+            return Edge(lemon::INVALID);
+        
         Edge res(SkipInitialization);
         detail::ScanOrderToCoordinate<N+1>::exec(i, edge_propmap_shape(), res);
-        return res;
+        
+        unsigned int b = detail::BorderTypeImpl<N>::exec(res.template subarray<0, N>(), shape());
+        if(neighborExists_[b][res[N]])
+            return res;
+        else
+            return Edge(lemon::INVALID);
     }
     
         /** \brief Get the maximum ID of any edge in this graph (API: LEMON).
         */
     index_type maxEdgeId() const
     {
-        if(is_directed)
-            return maxArcId();
+        if(max_edge_id_ == -2) // -2 means uninitialized
+            const_cast<GridGraph *>(this)->computeMaxEdgeAndArcId();
+        return max_edge_id_;
+    }
+    
+        /* Initial computation of the max_arc_id_ and max_edge_id_ (call in the constructor and
+           whenever the shape changes).
+        */
+    void computeMaxEdgeAndArcId()
+    {
         if(edgeNum() == 0)
-            return -1;
-        Node lastNode = shape() - shape_type(1);
-        Arc a(lastNode, backIndices_[get_border_type(lastNode)].back(), false);
-        return detail::CoordinateToScanOrder<N+1>::exec(edge_propmap_shape(), a);
+        {
+            max_arc_id_ = -1;
+            max_edge_id_ = -1;
+        }
+        else
+        {
+            Node lastNode = shape() - shape_type(1);
+            index_type n = neighborIndices_[get_border_type(lastNode)][0];
+            Arc a(neighbor(lastNode, n), oppositeIndex(n), false);
+            max_arc_id_ = detail::CoordinateToScanOrder<N+1>::exec(arc_propmap_shape(), a);
+            
+            if(is_directed)
+            {
+                max_edge_id_ = max_arc_id_;
+            }
+            else
+            {
+                Arc a(lastNode, backIndices_[get_border_type(lastNode)].back(), false);
+                max_edge_id_ = detail::CoordinateToScanOrder<N+1>::exec(edge_propmap_shape(), a);
+            }
+        }
     }
     
         /** \brief Get the ID (i.e. scan-order index an an arc property map) for 
@@ -2088,24 +2201,31 @@ public:
     }
         
         /** \brief Get an arc descriptor for the given arc ID \a i (API: LEMON).
+        
+            Return <tt>Arc(lemon::INVALID)</tt> when the ID does not exist
+            in this graph. 
         */
     Arc arcFromId(index_type i) const
     {
+        if(i < 0 || i > maxArcId())
+            return Arc(lemon::INVALID);
+        
         Arc res;
         detail::ScanOrderToCoordinate<N+1>::exec(i, arc_propmap_shape(), res);
-        return undirectedArc(res);
+        unsigned int b = detail::BorderTypeImpl<N>::exec(res.template subarray<0, N>(), shape());
+        if(neighborExists_[b][res[N]])
+            return undirectedArc(res);
+        else
+            return Arc(lemon::INVALID);
     }
     
         /** \brief Get the maximal ID af any arc in this graph (API: LEMON).
         */
     index_type maxArcId() const
     {
-        if(edgeNum() == 0)
-            return -1;
-        Node lastNode = shape() - shape_type(1);
-        index_type n = neighborIndices_[get_border_type(lastNode)][0];
-        Arc a(neighbor(lastNode, n), oppositeIndex(n), false);
-        return detail::CoordinateToScanOrder<N+1>::exec(arc_propmap_shape(), a);
+        if(max_arc_id_ == -2) // -2 means uninitialized
+            const_cast<GridGraph *>(this)->computeMaxEdgeAndArcId();
+        return max_arc_id_;
     }
     
         /** \brief Return <tt>true</tt> when the arc is looking on the underlying
@@ -2166,6 +2286,8 @@ public:
     }
     
         // internal function
+        // transforms the arc into its directed form (i.e. a.isReversed() is 
+        // guaranteed to be false in the returned arc).
     Arc directedArc(Arc const & a) const
     {
         return a.isReversed()
@@ -2174,6 +2296,9 @@ public:
     }
     
         // internal function
+        // transforms the arc into its undirected form (i.e. a.isReversed() will 
+        // be true in the returned arc if this graph is undirected and the arc
+        // traverses the edge backwards).
     Arc undirectedArc(Arc const & a) const
     {
         return a.edgeIndex() < maxUniqueDegree() 
@@ -2577,27 +2702,44 @@ public:
                    : &neighborIndices_;
     }
 
+    NeighborExistsArray const * neighborExistsArray() const
+    {
+        return &neighborExists_;
+    }
+
   protected:
     NeighborOffsetArray neighborOffsets_;
+    NeighborExistsArray neighborExists_;
     IndexArray neighborIndices_, backIndices_;
     RelativeNeighborOffsetsArray incrementalOffsets_;
     RelativeEdgeOffsetsArray edgeDescriptorOffsets_;
     shape_type shape_;
-    MultiArrayIndex num_vertices_, num_edges_;
+    MultiArrayIndex num_vertices_, num_edges_, max_node_id_, max_arc_id_, max_edge_id_;
     NeighborhoodType neighborhoodType_;
 };
 
+template<unsigned int N, class DirectedTag>
+inline
+bool
+isInside(GridGraph<N, DirectedTag> const & g,
+         typename GridGraph<N, DirectedTag>::vertex_descriptor const & v) 
+{
+    return allLess(v, g.shape()) && allGreaterEqual(v, typename MultiArrayShape<N>::type());
+}
+
 //@}
 
+#ifdef WITH_BOOST_GRAPH
+
 } // namespace vigra
 
 namespace boost {
 
-/** \addtogroup BoostGraphExtensions GridGraph additions to namespace <tt>boost</tt>
-        
-        provides the required functionality to make \ref vigra::GridGraph compatible to the boost::graph library.
-*/
-//@{
+#else
+
+namespace boost_graph {
+
+#endif 
 
 
 
@@ -2608,7 +2750,7 @@ struct property_traits<vigra::MultiArray<N, T, Acc> >
     typedef typename type::key_type                  key_type;
     typedef typename type::value_type                value_type; 
     typedef typename type::reference                 reference;
-    typedef boost::read_write_property_map_tag       category;
+    typedef read_write_property_map_tag              category;
 };
 
 template <unsigned int N, class T, class Acc>
@@ -2618,7 +2760,7 @@ struct property_traits<vigra::MultiArray<N, T, Acc> const>
     typedef typename type::key_type                  key_type;
     typedef typename type::value_type                value_type; 
     typedef typename type::const_reference           reference;
-    typedef boost::readable_property_map_tag         category;
+    typedef readable_property_map_tag                category;
 };
 
 template <unsigned int N, class T, class Stride>
@@ -2628,7 +2770,7 @@ struct property_traits<vigra::MultiArrayView<N, T, Stride> >
     typedef typename type::key_type                   key_type;
     typedef typename type::value_type                 value_type; 
     typedef typename type::reference                  reference;
-    typedef boost::read_write_property_map_tag        category;
+    typedef read_write_property_map_tag               category;
 };
 
 template <unsigned int N, class T, class Stride>
@@ -2638,9 +2780,24 @@ struct property_traits<vigra::MultiArrayView<N, T, Stride> const>
     typedef typename type::key_type                       key_type;
     typedef typename type::value_type                     value_type; 
     typedef typename type::const_reference                reference;
-    typedef boost::readable_property_map_tag              category;
+    typedef readable_property_map_tag                     category;
 };
 
+#ifdef WITH_BOOST_GRAPH
+
+} // namespace boost
+
+namespace vigra {
+namespace boost_graph {
+
+#endif 
+
+/** \addtogroup BoostGraphExtensions GridGraph additions to namespace <tt>boost</tt>
+        
+        provides the required functionality to make \ref vigra::GridGraph compatible to the boost::graph library.
+*/
+//@{
+
     /** \brief Return number of outgoing edges of vertex \a v (API: boost).
     */
 template<unsigned int N, class DirectedTag>
@@ -2853,81 +3010,19 @@ void put(vigra::MultiArrayView<N, T, Stride> & pmap,
 
     /** \brief Read the value at key \a k in property map \a pmap (API: boost).
     */
-template<unsigned int N, class T, class Stride>
-inline
-typename vigra::MultiArrayView<N, T, Stride>::const_reference 
-get(vigra::MultiArrayView<N, T, Stride> const & pmap,
-    typename vigra::MultiArrayView<N, T, Stride>::difference_type const & k)
-{ 
-    return pmap[k]; 
-}
-
-#if 0
-
-// property map support for mapping coordinates to scan-order indices:
-
-template<unsigned int N>
-struct IDMapper {
-    typedef typename vigra::GridGraph<N> graph_type;
-    typedef boost::readable_property_map_tag category;
-    typedef typename graph_type::index_type value_type;
-    typedef typename graph_type::vertex_descriptor key_type;
-    typedef const value_type& reference;
-
-
-    IDMapper(const graph_type &graph) 
-        : map_helper(graph.get_vertex_iterator())
-    {}
-
-    typename graph_type::vertex_iterator map_helper;
-};
+//template<unsigned int N, class T, class Stride>
+//inline
+//typename vigra::MultiArrayView<N, T, Stride>::const_reference 
+//get(vigra::MultiArrayView<N, T, Stride> const & pmap,
+//    typename vigra::MultiArrayView<N, T, Stride>::difference_type const & k)
+//{ 
+//    return pmap[k]; 
+//}
 
-template<unsigned int N>
-struct property_map<vigra::GridGraph<N>, boost::vertex_index_t>
-{
-    typedef IDMapper<N> type;
-    typedef IDMapper<N> const_type;
-};
-
-
-template<unsigned int N>
-inline
-typename IDMapper<N>::value_type
-get(const IDMapper<N> & mapper, 
-    const typename IDMapper<N>::key_type &k)
-{ 
-    return (mapper.map_helper + k).scanOrderIndex();
-}
-
-
-template<unsigned int N>
-typename boost::property_map<vigra::GridGraph<N>, boost::vertex_index_t>::type
-//typename IDMapper<N>
-get(boost::vertex_index_t, const vigra::GridGraph<N> &graph) {
-    // return a lightweight wrapper for the CoupledIterator, which easily allows the conversion of 
-    // coordinates via its += operator followed by index().
-    return IDMapper<N>(graph);
-}
-
-// CHECK if required: also provide the direct (three-parameter) version for index lookup
-template<unsigned int N>
-typename vigra::GridGraph<N>::vertices_size_type
-get(boost::vertex_index_t, 
-    const vigra::GridGraph<N> &graph,
-    const typename vigra::GridGraph<N>::vertex_descriptor &v) {
-    return (IDMapper<N>(graph).map_helper + v).scanOrderIndex();
-}
-
-
-// TODO:
-// eventually provide an edge_index property map as well?
-// (edge_descriptor -> linear contiguous edge index)
-
-#endif
 
 //@}
 
-} // namespace boost
+}} // namespace vigra::boost_graph
 
 namespace lemon {
 
@@ -2966,14 +3061,6 @@ class OutDegMap<vigra::GridGraph<N, DirectedTag> >
 
 } // namespace lemon
 
-namespace vigra {
-namespace boost_graph { 
-
-using boost::get;
-
-}} // namespace vigra::boost_graph
-
-
 namespace std {
 
 template<unsigned int N, class DirectedTag>
diff --git a/include/vigra/multi_handle.hxx b/include/vigra/multi_handle.hxx
new file mode 100644
index 0000000..b017116
--- /dev/null
+++ b/include/vigra/multi_handle.hxx
@@ -0,0 +1,1103 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2011-2014 by Ullrich Koethe                            */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef MULTI_HANDLE_HXX
+#define MULTI_HANDLE_HXX
+
+#include "multi_fwd.hxx"
+#include "metaprogramming.hxx"
+#include "multi_shape.hxx"
+
+namespace vigra {
+
+template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX=Handle::index>
+struct CoupledHandleCast;
+
+#ifndef _MSC_VER  // Visual Studio doesn't like these forward declarations
+template <unsigned int TARGET_INDEX, class Handle>
+typename CoupledHandleCast<TARGET_INDEX, Handle>::reference
+get(Handle & handle);
+
+template <unsigned int TARGET_INDEX, class Handle>
+typename CoupledHandleCast<TARGET_INDEX, Handle>::const_reference
+get(Handle const & handle);
+#endif
+
+/** \addtogroup MultiIteratorGroup
+*/
+//@{
+
+  /**
+     Handle class, used by CoupledScanOrderIterator as the value type to simultaneously itearate over multiple images.
+  */
+template <class T, class NEXT>
+class CoupledHandle
+: public NEXT
+{
+public:
+    typedef NEXT                            base_type;
+    typedef CoupledHandle<T, NEXT>          self_type;
+
+    static const int index =                NEXT::index + 1;    // index of this member of the chain
+    static const unsigned int dimensions =  NEXT::dimensions;
+
+    typedef T                               value_type;
+    typedef T *                             pointer;
+    typedef T const *                       const_pointer;
+    typedef T &                             reference;
+    typedef T const &                       const_reference;
+    typedef typename base_type::shape_type  shape_type;
+
+    CoupledHandle()
+    : base_type(),
+      pointer_(),
+      strides_()
+    {}
+
+    template <class NEXT1>
+    CoupledHandle(CoupledHandle<T, NEXT1> const & h, NEXT const & next)
+    : base_type(next),
+      pointer_(h.pointer_),
+      strides_(h.strides_)
+    {}
+
+    CoupledHandle(const_pointer p, shape_type const & strides, NEXT const & next)
+    : base_type(next),
+      pointer_(const_cast<pointer>(p)),
+      strides_(strides)
+    {}
+
+    template <class Stride>
+    CoupledHandle(MultiArrayView<dimensions, T, Stride> const & v, NEXT const & next)
+    : base_type(next),
+      pointer_(const_cast<pointer>(v.data())),
+      strides_(v.stride())
+    {
+        vigra_precondition(v.shape() == this->shape(), "createCoupledIterator(): shape mismatch.");
+    }
+
+    inline void incDim(int dim)
+    {
+        pointer_ += strides_[dim];
+        base_type::incDim(dim);
+    }
+
+    inline void decDim(int dim)
+    {
+        pointer_ -= strides_[dim];
+        base_type::decDim(dim);
+    }
+
+    inline void addDim(int dim, MultiArrayIndex d)
+    {
+        pointer_ += d*strides_[dim];
+        base_type::addDim(dim, d);
+    }
+
+    inline void add(shape_type const & d)
+    {
+        pointer_ += dot(d, strides_);
+        base_type::add(d);
+    }
+
+    template<int DIMENSION>
+    inline void increment()
+    {
+        pointer_ += strides_[DIMENSION];
+        base_type::template increment<DIMENSION>();
+    }
+
+    template<int DIMENSION>
+    inline void decrement()
+    {
+        pointer_ -= strides_[DIMENSION];
+        base_type::template decrement<DIMENSION>();
+    }
+
+    // TODO: test if making the above a default case of the this hurts performance
+    template<int DIMENSION>
+    inline void increment(MultiArrayIndex offset)
+    {
+        pointer_ += offset*strides_[DIMENSION];
+        base_type::template increment<DIMENSION>(offset);
+    }
+
+    template<int DIMENSION>
+    inline void decrement(MultiArrayIndex offset)
+    {
+        pointer_ -= offset*strides_[DIMENSION];
+        base_type::template decrement<DIMENSION>(offset);
+    }
+
+    void restrictToSubarray(shape_type const & start, shape_type const & end)
+    {
+        pointer_ += dot(start, strides_);
+        base_type::restrictToSubarray(start, end);
+    }
+
+    // ptr access
+    reference operator*()
+    {
+        return *pointer_;
+    }
+
+    const_reference operator*() const
+    {
+        return *pointer_;
+    }
+
+    pointer operator->()
+    {
+        return pointer_;
+    }
+
+    const_pointer operator->() const
+    {
+        return pointer_;
+    }
+
+    pointer ptr()
+    {
+        return pointer_;
+    }
+
+    const_pointer ptr() const
+    {
+        return pointer_;
+    }
+
+    shape_type const & strides() const
+    {
+        return strides_;
+    }
+
+    MultiArrayView<dimensions, T>
+    arrayView() const
+    {
+        return MultiArrayView<dimensions, T>(this->shape(), strides(), ptr() - dot(this->point(), strides()));
+    }
+
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, CoupledHandle, index>::reference
+    get()
+    {
+        return vigra::get<TARGET_INDEX>(*this);
+    }
+
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, CoupledHandle, index>::const_reference
+    get() const
+    {
+        return vigra::get<TARGET_INDEX>(*this);
+    }
+
+    // NOTE: dangerous function - only use it when you know what you are doing
+    void internal_reset(const_pointer p)
+    {
+        pointer_ = const_cast<pointer>(p);
+    }
+
+    pointer pointer_;
+    shape_type strides_;
+};
+
+    //  CoupledHandle holding the current coordinate
+    // (always the end of a CoupledHandle chain)
+template <int N>
+class CoupledHandle<TinyVector<MultiArrayIndex, N>, void>
+{
+public:
+    static const unsigned int index      = 0; // index of this member of the chain
+    static const unsigned int dimensions = N;
+
+    typedef typename MultiArrayShape<N>::type   value_type;
+    typedef value_type const *                  pointer;
+    typedef value_type const *                  const_pointer;
+    typedef value_type const &                  reference;
+    typedef value_type const &                  const_reference;
+    typedef value_type                          shape_type;
+    typedef CoupledHandle<value_type, void>     self_type;
+
+    CoupledHandle()
+    : point_(),
+      shape_(),
+      scanOrderIndex_()
+    {}
+
+    CoupledHandle(value_type const & shape)
+    : point_(),
+      shape_(shape),
+      scanOrderIndex_()
+    {}
+
+    CoupledHandle(typename MultiArrayShape<N+1>::type const & shape)
+    : point_(),
+      shape_(shape.begin()),
+      scanOrderIndex_()
+    {}
+
+    inline void incDim(int dim)
+    {
+        ++point_[dim];
+    }
+
+    inline void decDim(int dim)
+    {
+        --point_[dim];
+    }
+
+    inline void addDim(int dim, MultiArrayIndex d)
+    {
+        point_[dim] += d;
+    }
+
+    inline void add(shape_type const & d)
+    {
+        point_ += d;
+    }
+
+    template<int DIMENSION>
+    inline void increment()
+    {
+        ++point_[DIMENSION];
+    }
+
+    template<int DIMENSION>
+    inline void decrement()
+    {
+        --point_[DIMENSION];
+    }
+
+    // TODO: test if making the above a default case of the this hurts performance
+    template<int DIMENSION>
+    inline void increment(MultiArrayIndex offset)
+    {
+        point_[DIMENSION] += offset;
+    }
+
+    template<int DIMENSION>
+    inline void decrement(MultiArrayIndex offset)
+    {
+        point_[DIMENSION] -= offset;
+    }
+
+    void restrictToSubarray(shape_type const & start, shape_type const & end)
+    {
+        point_ = shape_type();
+        shape_ = end - start;
+        scanOrderIndex_ = 0;
+    }
+
+    inline void incrementIndex()
+    {
+        ++scanOrderIndex_;
+    }
+
+    inline void decrementIndex()
+    {
+        --scanOrderIndex_;
+    }
+
+    inline void incrementIndex(MultiArrayIndex offset)
+    {
+        scanOrderIndex_ += offset;
+    }
+
+    inline void decrementIndex(MultiArrayIndex offset)
+    {
+        scanOrderIndex_ -= offset;
+    }
+
+    // access
+    MultiArrayIndex scanOrderIndex() const
+    {
+        return scanOrderIndex_;
+    }
+
+    // access
+    const_reference point() const
+    {
+        return point_;
+    }
+
+    // access
+    const_reference shape() const
+    {
+        return shape_;
+    }
+
+    const_reference operator*() const
+    {
+        return point_;
+    }
+
+    const_pointer operator->() const
+    {
+        return &point_;
+    }
+
+    const_pointer ptr() const
+    {
+        return &point_;
+    }
+
+    unsigned int borderType() const
+    {
+        return detail::BorderTypeImpl<N>::exec(point_, shape_);
+    }
+
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, CoupledHandle, index>::reference
+    get()
+    {
+        return vigra::get<TARGET_INDEX>(*this);
+    }
+
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, CoupledHandle, index>::const_reference
+    get() const
+    {
+        return vigra::get<TARGET_INDEX>(*this);
+    }
+
+    // NOTE: dangerous function - only use it when you know what you are doing
+    void internal_reset(value_type const & point)
+    {
+        point_ = point;
+    }
+
+    value_type point_, shape_;
+    MultiArrayIndex scanOrderIndex_;
+};
+
+    //  CoupledHandle for multi-band data
+template <class T, class NEXT>
+class CoupledHandle<Multiband<T>, NEXT>
+: public NEXT
+{
+public:
+    typedef NEXT                                  base_type;
+    typedef CoupledHandle<Multiband<T>, NEXT>     self_type;
+
+    static const unsigned int index =             NEXT::index + 1;    // index of this member of the chain
+    static const unsigned int dimensions =        NEXT::dimensions;
+
+    typedef MultiArrayView<1, T, StridedArrayTag> value_type;
+    typedef value_type *                          pointer;
+    typedef value_type const *                    const_pointer;
+    typedef value_type &                          reference;
+    typedef value_type const &                    const_reference;
+    typedef typename base_type::shape_type        shape_type;
+
+    CoupledHandle()
+    : base_type(),
+      view_(),
+      strides_()
+    {}
+
+    template <class NEXT1>
+    CoupledHandle(CoupledHandle<Multiband<T>, NEXT1> const & h, NEXT const & next)
+    : base_type(next),
+      view_(h.view_),
+      strides_(h.strides_)
+    {}
+
+    CoupledHandle(const_reference p, shape_type const & strides, NEXT const & next)
+    : base_type(next),
+      view_(p),
+      strides_(strides)
+    {}
+
+    template <class Stride>
+    CoupledHandle(MultiArrayView<dimensions+1, Multiband<T>, Stride> const & v, NEXT const & next)
+    : base_type(next),
+      view_(v.bindInner(shape_type())),
+      strides_(v.bindOuter(0).stride())
+    {
+        vigra_precondition(v.bindOuter(0).shape() == this->shape(), "createCoupledIterator(): shape mismatch.");
+    }
+
+    inline void incDim(int dim)
+    {
+        view_.unsafePtr() += strides_[dim];
+        base_type::incDim(dim);
+    }
+
+    inline void decDim(int dim)
+    {
+        view_.unsafePtr() -= strides_[dim];
+        base_type::decDim(dim);
+    }
+
+    inline void addDim(int dim, MultiArrayIndex d)
+    {
+        view_.unsafePtr() += d*strides_[dim];
+        base_type::addDim(dim, d);
+    }
+
+    inline void add(shape_type const & d)
+    {
+        view_.unsafePtr() += dot(d, strides_);
+        base_type::add(d);
+    }
+
+    template<int DIMENSION>
+    inline void increment()
+    {
+        view_.unsafePtr() += strides_[DIMENSION];
+        base_type::template increment<DIMENSION>();
+    }
+
+    template<int DIMENSION>
+    inline void decrement()
+    {
+        view_.unsafePtr() -= strides_[DIMENSION];
+        base_type::template decrement<DIMENSION>();
+    }
+
+    // TODO: test if making the above a default case of the this hurts performance
+    template<int DIMENSION>
+    inline void increment(MultiArrayIndex offset)
+    {
+        view_.unsafePtr() += offset*strides_[DIMENSION];
+        base_type::template increment<DIMENSION>(offset);
+    }
+
+    template<int DIMENSION>
+    inline void decrement(MultiArrayIndex offset)
+    {
+        view_.unsafePtr() -= offset*strides_[DIMENSION];
+        base_type::template decrement<DIMENSION>(offset);
+    }
+
+    void restrictToSubarray(shape_type const & start, shape_type const & end)
+    {
+        view_.unsafePtr() += dot(start, strides_);
+        base_type::restrictToSubarray(start, end);
+    }
+
+    // ptr access
+    reference operator*()
+    {
+        return view_;
+    }
+
+    const_reference operator*() const
+    {
+        return view_;
+    }
+
+    pointer operator->()
+    {
+        return &view_;
+    }
+
+    const_pointer operator->() const
+    {
+        return &view_;
+    }
+
+    pointer ptr()
+    {
+        return &view_;
+    }
+
+    const_pointer ptr() const
+    {
+        return &view_;
+    }
+
+    shape_type const & strides() const
+    {
+        return strides_;
+    }
+
+    MultiArrayView<dimensions+1, Multiband<T> >
+    arrayView() const
+    {
+        typedef MultiArrayView<dimensions+1, T> View;
+        typename View::difference_type vshape(SkipInitialization), vstride(SkipInitialization);
+        vshape.template subarray<0, dimensions>() = this->shape();
+        vstride.template subarray<0, dimensions>() = strides();
+        vshape[dimensions] = view_.shape(0);
+        vstride[dimensions] = view_.stride(0);
+        return View(vshape, vstride, view_.data() - dot(this->point(), strides())).multiband();
+    }
+
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, CoupledHandle, index>::reference
+    get()
+    {
+        return vigra::get<TARGET_INDEX>(*this);
+    }
+
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, CoupledHandle, index>::const_reference
+    get() const
+    {
+        return vigra::get<TARGET_INDEX>(*this);
+    }
+
+    template <class U>
+    void internal_reset(U const & p)
+    {
+        vigra_fail("CoupledHandle<Multiband<T>>::internal_reset(): not implemented.");
+    }
+
+    value_type view_;
+    shape_type strides_;
+};
+
+    //  helper class for CoupledHandle for CunkedArray
+template <unsigned int N, class T>
+class IteratorChunkHandle
+{
+  public:
+    typedef ChunkedArray<N, T>             array_type;
+    typedef typename MultiArrayShape<N>::type  shape_type;
+
+    IteratorChunkHandle()
+    : offset_(),
+      chunk_(0)
+    {}
+
+    IteratorChunkHandle(shape_type const & offset)
+    : offset_(offset),
+      chunk_(0)
+    {}
+
+    IteratorChunkHandle(IteratorChunkHandle const & other)
+    : offset_(other.offset_),
+      chunk_(0)
+    {}
+
+    IteratorChunkHandle & operator=(IteratorChunkHandle const & other)
+    {
+        offset_ = other.offset_;
+        chunk_ = 0;
+        return *this;
+    }
+
+    shape_type offset_;
+    SharedChunkHandle<N, T> * chunk_;
+};
+
+    /*  CoupledHandle for CunkedArray
+
+        The handle must store a pointer to a chunk because the chunk knows
+        about memory menagement, and to an array view because it knows about
+        subarrays and slices.
+
+        Perhaps we can reduce this to a single pointer or otherwise reduce
+        the handle memory to make it faster?
+    */
+template <class U, class NEXT>
+class CoupledHandle<ChunkedMemory<U>, NEXT>
+: public NEXT,
+  public IteratorChunkHandle<NEXT::dimensions, typename UnqualifiedType<U>::type>
+{
+public:
+    typedef typename UnqualifiedType<U>::type     T;
+    typedef NEXT                                  base_type;
+    typedef IteratorChunkHandle<NEXT::dimensions, T>    base_type2;
+    typedef CoupledHandle<ChunkedMemory<U>, NEXT> self_type;
+
+    static const unsigned int index =             NEXT::index + 1;    // index of this member of the chain
+    static const unsigned int dimensions =        NEXT::dimensions;
+
+    typedef typename IfBool<UnqualifiedType<U>::isConst,
+          ChunkedArrayBase<dimensions, T> const,
+          ChunkedArrayBase<dimensions, T> >::type array_type;
+    typedef detail::ChunkShape<dimensions, T>     chunk_shape;
+    typedef T                                     value_type;
+    typedef U *                                   pointer;
+    typedef value_type const *                    const_pointer;
+    typedef U &                                   reference;
+    typedef value_type const &                    const_reference;
+    typedef typename base_type::shape_type        shape_type;
+
+    CoupledHandle()
+    : base_type(),
+      base_type2(),
+      pointer_(),
+      strides_(),
+      upper_bound_(),
+      array_()
+    {}
+
+    CoupledHandle(CoupledHandle const & other)
+    : base_type(other),
+      base_type2(other),
+      pointer_(other.pointer_),
+      strides_(other.strides_),
+      upper_bound_(other.upper_bound_),
+      array_(other.array_)
+    {
+        if(array_)
+            pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+    }
+
+    CoupledHandle(array_type const & array, NEXT const & next)
+    : base_type(next),
+      base_type2(),
+      pointer_(),
+      array_(const_cast<array_type*>(&array))
+    {
+        if(array_)
+            pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+    }
+
+    ~CoupledHandle()
+    {
+        // deref the present chunk
+        if(array_)
+            array_->unrefChunk(this);
+    }
+
+    CoupledHandle & operator=(CoupledHandle const & other)
+    {
+        if(this != &other)
+        {
+            // deref the present chunk
+            if(array_)
+                array_->unrefChunk(this);
+            base_type::operator=(other);
+            base_type2::operator=(other);
+            array_ = other.array_;
+            if(array_)
+            {
+                pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+            }
+            else
+            {
+                pointer_ = other.pointer_;
+                strides_ = other.strides_;
+                upper_bound_ = other.upper_bound_;
+            }
+        }
+        return *this;
+    }
+
+    using base_type::point;
+    using base_type::shape;
+
+    inline void incDim(int dim)
+    {
+        base_type::incDim(dim);
+        pointer_ += strides_[dim];
+        if(point()[dim] == upper_bound_[dim])
+        {
+            // if(point()[dim] < shape()[dim])
+                pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+        }
+    }
+
+    inline void decDim(int dim)
+    {
+        base_type::decDim(dim);
+        pointer_ -= strides_[dim];
+        if(point()[dim] < upper_bound_[dim] - array_->chunk_shape_[dim])
+        {
+            // if(point()[dim] >= 0)
+                pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+        }
+    }
+
+    inline void addDim(int dim, MultiArrayIndex d)
+    {
+        base_type::addDim(dim, d);
+        if(point()[dim] < shape()[dim] && point()[dim] >= 0)
+            pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+    }
+
+    inline void add(shape_type const & d)
+    {
+        base_type::add(d);
+        pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+    }
+
+    template<int DIMENSION>
+    inline void increment()
+    {
+        // incDim(DIMENSION);
+        base_type::template increment<DIMENSION>();
+        pointer_ += strides_[DIMENSION];
+        if(point()[DIMENSION] == upper_bound_[DIMENSION])
+        {
+            if(point()[DIMENSION] > shape()[DIMENSION])
+                // this invariant check prevents the compiler from optimizing stupidly
+                // (it makes a difference of a factor of 2!)
+                vigra_invariant(false, "CoupledHandle<ChunkedMemory<T>>: internal error.");
+            else
+                pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+        }
+    }
+
+    template<int DIMENSION>
+    inline void decrement()
+    {
+        // decDim(DIMENSION);
+        base_type::template decrement<DIMENSION>();
+        pointer_ -= strides_[DIMENSION];
+        if(point()[DIMENSION] < upper_bound_[DIMENSION] - array_->chunk_shape_[DIMENSION])
+        {
+            if(point()[DIMENSION] < -1)
+                // this invariant check prevents the compiler from optimizing stupidly
+                // (it makes a difference of a factor of 2!)
+                vigra_invariant(false, "CoupledHandle<ChunkedMemory<T>>: internal error.");
+            else
+                pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+        }
+    }
+
+    template<int DIMENSION>
+    inline void increment(MultiArrayIndex d)
+    {
+        addDim(DIMENSION, d);
+    }
+
+    template<int DIMENSION>
+    inline void decrement(MultiArrayIndex d)
+    {
+        addDim(DIMENSION, -d);
+    }
+
+    void restrictToSubarray(shape_type const & start, shape_type const & end)
+    {
+        base_type::restrictToSubarray(start, end);
+        this->offset_ += start;
+        pointer_ = array_->chunkForIterator(point(), strides_, upper_bound_, this);
+    }
+
+    // ptr access
+    reference operator*()
+    {
+        return *pointer_;
+    }
+
+    const_reference operator*() const
+    {
+        return *pointer_;
+    }
+
+    pointer operator->()
+    {
+        return pointer_;
+    }
+
+    const_pointer operator->() const
+    {
+        return pointer_;
+    }
+
+    pointer ptr()
+    {
+        return pointer_;
+    }
+
+    const_pointer ptr() const
+    {
+        return pointer_;
+    }
+
+    array_type const &
+    arrayView() const
+    {
+        return *array_;
+    }
+
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, CoupledHandle, index>::reference
+    get()
+    {
+        return vigra::get<TARGET_INDEX>(*this);
+    }
+
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, CoupledHandle, index>::const_reference
+    get() const
+    {
+        return vigra::get<TARGET_INDEX>(*this);
+    }
+
+    template <class V>
+    void internal_reset(V const & p)
+    {
+        vigra_fail("CoupledHandle<ChunkedMemory<T>>::internal_reset(): not implemented.");
+    }
+
+    pointer pointer_;
+    shape_type strides_, upper_bound_;
+    array_type * array_;
+};
+
+    // meta-programming helper classes to implement 'get<INDEX>(CoupledHandle)'
+template <unsigned TARGET_INDEX>
+struct Error__CoupledHandle_index_out_of_range;
+
+namespace detail {
+
+template <unsigned TARGET_INDEX, class Handle, bool isValid, unsigned int INDEX=Handle::index>
+struct CoupledHandleCastImpl
+{
+    typedef typename CoupledHandleCastImpl<TARGET_INDEX, typename Handle::base_type, isValid>::type type;
+    typedef typename type::value_type value_type;
+    typedef typename type::reference reference;
+    typedef typename type::const_reference const_reference;
+};
+
+template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX>
+struct CoupledHandleCastImpl<TARGET_INDEX, Handle, false, INDEX>
+{
+    typedef Error__CoupledHandle_index_out_of_range<TARGET_INDEX> type;
+    typedef Error__CoupledHandle_index_out_of_range<TARGET_INDEX> value_type;
+    typedef Error__CoupledHandle_index_out_of_range<TARGET_INDEX> reference;
+    typedef Error__CoupledHandle_index_out_of_range<TARGET_INDEX> const_reference;
+};
+
+template <unsigned TARGET_INDEX, class Handle>
+struct CoupledHandleCastImpl<TARGET_INDEX, Handle, true, TARGET_INDEX>
+{
+    typedef Handle type;
+    typedef typename type::value_type value_type;
+    typedef typename type::reference reference;
+    typedef typename type::const_reference const_reference;
+};
+
+} // namespace detail
+
+template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX>
+struct CoupledHandleCast
+: public detail::CoupledHandleCastImpl<TARGET_INDEX, Handle, (TARGET_INDEX <= INDEX), INDEX>
+{};
+
+template <unsigned int TARGET_INDEX, class Handle>
+inline
+typename CoupledHandleCast<TARGET_INDEX, Handle>::type &
+cast(Handle & handle)
+{
+    return handle;
+}
+
+template <unsigned int TARGET_INDEX, class Handle>
+inline
+typename CoupledHandleCast<TARGET_INDEX, Handle>::type const &
+cast(Handle const & handle)
+{
+    return handle;
+}
+
+  /** Returns reference to the element in the band of the handle with index TARGET_INDEX.
+   */
+template <unsigned int TARGET_INDEX, class Handle>
+inline
+typename CoupledHandleCast<TARGET_INDEX, Handle>::reference
+get(Handle & handle)
+{
+    return *cast<TARGET_INDEX>(handle);
+}
+
+  /** Returns a constant reference to the element in the band of the handle with index TARGET_INDEX.
+   */
+template <unsigned int TARGET_INDEX, class Handle>
+inline
+typename CoupledHandleCast<TARGET_INDEX, Handle>::const_reference
+get(Handle const & handle)
+{
+    return *cast<TARGET_INDEX>(handle);
+}
+
+    // meta-programming helper classes to infer the type of
+    // a CoupledHandle for a set of arrays
+template <unsigned int N, class List>
+struct ComposeCoupledHandle;
+
+template <unsigned int N, class T, class TAIL>
+struct ComposeCoupledHandle<N, TypeList<T, TAIL> >
+{
+    typedef typename ComposeCoupledHandle<N, TAIL>::type  BaseType;
+    typedef typename MultiArrayShape<N>::type             shape_type;
+    typedef CoupledHandle<T, BaseType>                    type;
+
+    template <class S>
+    type exec(MultiArrayView<N, T, S> const & m,
+              shape_type const & start, shape_type const & end,
+              BaseType const & base)
+    {
+        return type(m.subarray(start, end).data(), m.stride(), base);
+    }
+
+    template <class S>
+    type exec(MultiArrayView<N, T, S> const & m, BaseType const & base)
+    {
+        return type(m.data(), m.stride(), base);
+    }
+};
+
+template <unsigned int N>
+struct ComposeCoupledHandle<N, void>
+{
+    typedef typename MultiArrayShape<N>::type  shape_type;
+    typedef CoupledHandle<shape_type, void>    type;
+
+    type exec(shape_type const & shape)
+    {
+        return type(shape);
+    }
+
+    type exec(shape_type const & start, shape_type const & end)
+    {
+        return type(end-start);
+    }
+};
+
+
+template <unsigned int N, class T1=void, class T2=void, class T3=void, class T4=void, class T5=void>
+struct CoupledHandleType
+{
+    // reverse the order to get the desired index order
+    typedef typename MakeTypeList<T5, T4, T3, T2, T1>::type TypeList;
+    typedef typename ComposeCoupledHandle<N, TypeList>::type type;
+};
+
+template <unsigned int N, class T1, class T2, class T3, class T4, class T5>
+struct CoupledHandleType<N, Multiband<T1>, T2, T3, T4, T5>
+{
+    // reverse the order to get the desired index order
+    typedef typename MakeTypeList<T5, T4, T3, T2, Multiband<T1> >::type TypeList;
+    typedef typename ComposeCoupledHandle<N-1, TypeList>::type type;
+};
+
+    // meta-programming helper classes to implement 'zip(iterator1, iterator2)'
+template <class A, class B>
+struct ZipCoupledHandles;
+
+template <class A, class Head, class Tail>
+struct ZipCoupledHandles<A, CoupledHandle<Head, Tail> >
+{
+    typedef typename ZipCoupledHandles<A, Tail>::type Next;
+    typedef CoupledHandle<Head, Next> type;
+
+    static type construct(A const & a, CoupledHandle<Head, Tail> const & h)
+    {
+        return type(h, ZipCoupledHandles<A, Tail>::construct(a, (Tail const &)h));
+    }
+};
+
+template <class A, class Shape>
+struct ZipCoupledHandles<A, CoupledHandle<Shape, void> >
+{
+    typedef A type;
+
+    static type construct(A const & a, CoupledHandle<Shape, void> const &)
+    {
+        return a;
+    }
+};
+
+    // allow an iterator that uses CoupledHandle to specialize its
+    // dereferencing functions, such that
+    //    '*iter' returns a referenc to the current point if
+    //            the handle is just a coordinate handle
+    //    '*iter' returns a reference to the current data element
+    //            if the handle referes to just one array
+    //    '*iter' returns a reference to the handle itself if it refers to
+    //            several arrays simultaneously (i.e. is actualy a coupled handle)
+template <class Handle, unsigned int INDEX=Handle::index>
+struct CoupledHandleTraits
+{
+    typedef Handle value_type;
+    typedef Handle & reference;
+    typedef Handle const & const_reference;
+    typedef Handle * pointer;
+    typedef Handle const * const_pointer;
+
+    static reference dereference(Handle & h)
+    {
+        return h;
+    }
+
+    static const_reference dereference(Handle const & h)
+    {
+        return h;
+    }
+};
+
+template <class Handle>
+struct CoupledHandleTraits<Handle, 0>
+{
+    typedef typename Handle::value_type value_type;
+    typedef typename Handle::reference reference;
+    typedef typename Handle::const_reference const_reference;
+    typedef typename Handle::pointer pointer;
+    typedef typename Handle::const_pointer const_pointer;
+
+    static reference dereference(Handle & h)
+    {
+        return *h;
+    }
+
+    static const_reference dereference(Handle const & h)
+    {
+        return *h;
+    }
+};
+
+template <class Handle>
+struct CoupledHandleTraits<Handle, 1>
+{
+    typedef typename Handle::value_type value_type;
+    typedef typename Handle::reference reference;
+    typedef typename Handle::const_reference const_reference;
+    typedef typename Handle::pointer pointer;
+    typedef typename Handle::const_pointer const_pointer;
+
+    static reference dereference(Handle & h)
+    {
+        return *h;
+    }
+
+    static const_reference dereference(Handle const & h)
+    {
+        return *h;
+    }
+};
+
+
+//@}
+
+} // namespace vigra
+
+#endif /* MULTI_HANDLE_HXX */
diff --git a/include/vigra/multi_hierarchical_iterator.hxx b/include/vigra/multi_hierarchical_iterator.hxx
new file mode 100644
index 0000000..8e22299
--- /dev/null
+++ b/include/vigra/multi_hierarchical_iterator.hxx
@@ -0,0 +1,631 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2003-2012 by Gunnar Kedenburg and Ullrich Koethe       */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    ( Version 1.3.0, Sep 10 2004 )                                    */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_MULTI_HIERARCHICAL_ITERATOR_HXX
+#define VIGRA_MULTI_HIERARCHICAL_ITERATOR_HXX
+
+#include <sys/types.h>
+#include "multi_fwd.hxx"
+#include "iteratortags.hxx"
+#include "multi_handle.hxx"
+
+namespace vigra {
+
+/** \addtogroup MultiIteratorGroup
+*/
+//@{
+
+/********************************************************/
+/*                                                      */
+/*                 MultiHierarchicalIterator            */
+/*                                                      */
+/********************************************************/
+
+template <unsigned int N,
+          class HANDLES,
+          int DIMENSION = N-1>
+class HierarchicalIterator
+#ifndef DOXYGEN  // doxygen doesn't understand this inheritance
+: public HierarchicalIterator<N, HANDLES, DIMENSION-1>
+#endif
+{
+  public:
+
+    typedef HierarchicalIterator<N, HANDLES, DIMENSION-1> base_type;
+    static const int level = DIMENSION;
+    typedef typename base_type::value_type value_type;
+    typedef typename base_type::reference reference;
+    typedef typename base_type::const_reference const_reference;
+    typedef typename base_type::pointer pointer;
+    typedef typename base_type::const_pointer const_pointer;
+    typedef typename base_type::difference_type difference_type;
+    typedef typename base_type::shape_type shape_type;
+
+    explicit HierarchicalIterator(HANDLES const & handles = HANDLES())
+    : base_type(handles)
+    {}
+
+    void operator++ ()
+    {
+        this->handles_.template increment<level>();
+    }
+
+    void operator-- ()
+    {
+        this->handles_.template decrement<level>();
+    }
+
+    HierarchicalIterator operator++ (int)
+    {
+        HierarchicalIterator ret = *this;
+        ++(*this);
+        return ret;
+    }
+
+    HierarchicalIterator operator-- (int)
+    {
+        HierarchicalIterator ret = *this;
+        --(*this);
+        return ret;
+    }
+
+    HierarchicalIterator & operator+= (difference_type n)
+    {
+        this->handles_.addDim(level, n);
+        return *this;
+    }
+
+    HierarchicalIterator & operator+= (shape_type const & d)
+    {
+        base_type::operator+=(d);
+        return *this;
+    }
+
+    HierarchicalIterator  &operator-= (difference_type n)
+    {
+        this->handles_.addDim(level, -n);
+        return *this;
+    }
+
+    // HierarchicalIterator & operator-= (multi_difference_type const & d)
+    // {
+        // this->m_ptr -= total_stride(d.begin());
+        // return *this;
+    // }
+
+    HierarchicalIterator operator+ (difference_type n) const
+    {
+        return HierarchicalIterator(*this) += n;
+    }
+
+    // HierarchicalIterator operator+ (multi_difference_type const & d) const
+    // {
+        // StridedMultiIterator ret = *this;
+        // ret += d;
+        // return ret;
+    // }
+
+    difference_type operator- (HierarchicalIterator const & d) const
+    {
+        return this->point()[level] - d.point()[level];
+    }
+
+    HierarchicalIterator operator- (difference_type n) const
+    {
+        return HierarchicalIterator(*this) -= n;
+    }
+
+    // HierarchicalIterator operator- (multi_difference_type const & d) const
+    // {
+        // HierarchicalIterator ret = *this;
+        // ret -= d;
+        // return ret;
+    // }
+
+    bool operator== (const HierarchicalIterator &rhs) const
+    {
+        return this->point()[level] == rhs.point()[level];
+    }
+
+    bool operator!= (const HierarchicalIterator &rhs) const
+    {
+        return this->point()[level] != rhs.point()[level];
+    }
+
+    bool operator< (const HierarchicalIterator &rhs) const
+    {
+        return this->point()[level] < rhs.point()[level];
+    }
+
+    bool operator<= (const HierarchicalIterator &rhs) const
+    {
+        return this->point()[level] <= rhs.point()[level];
+    }
+
+    bool operator> (const HierarchicalIterator &rhs) const
+    {
+        return this->point()[level] > rhs.point()[level];
+    }
+
+    bool operator>= (const HierarchicalIterator &rhs) const
+    {
+        return this->point()[level] >= rhs.point()[level];
+    }
+
+    base_type begin () const
+    {
+        return *this;
+    }
+
+    base_type end () const
+    {
+        return base_type(*this) += this->shape()[level-1] - this->point()[level-1];
+    }
+    
+    HierarchicalIterator getEndIterator() const
+    {
+        return HierarchicalIterator(*this) += this->shape() - this->point();
+    }
+
+    // iterator iteratorForDimension(unsigned int d) const
+    // {
+        // vigra_precondition(d <= level,
+            // "StridedMultiIterator<N>::iteratorForDimension(d): d < N required");
+        // return iterator(this->m_ptr, stride_traits::shift(m_stride, d), 0);
+    // }
+
+    template <int K>
+    HierarchicalIterator<N, HANDLES, K> &
+    dim()
+    {
+        return *this;
+    }
+
+    template <int K>
+    HierarchicalIterator<N, HANDLES, K> const &
+    dim() const
+    {
+        return *this;
+    }
+};
+
+/********************************************************/
+
+template <unsigned int N,
+          class HANDLES>
+class HierarchicalIterator<N, HANDLES, 0>
+{
+  public:
+    static const int level = 0;
+    
+    typedef CoupledHandleTraits<HANDLES> HandleTraits;
+    typedef typename HandleTraits::value_type value_type;
+    typedef typename HandleTraits::reference reference;
+    typedef typename HandleTraits::const_reference const_reference;
+    typedef typename HandleTraits::pointer pointer;
+    typedef typename HandleTraits::const_pointer const_pointer;
+    typedef MultiArrayIndex difference_type;
+    typedef typename MultiArrayShape<N>::type shape_type;
+    typedef HierarchicalIterator<N, HANDLES, 0> iterator;
+    typedef std::random_access_iterator_tag iterator_category;
+
+  protected:
+    HANDLES handles_;
+
+  public:
+    explicit HierarchicalIterator(HANDLES const & handles = HANDLES())
+    : handles_(handles)
+    {}
+
+    void operator++ ()
+    {
+        handles_.template increment<level>();
+    }
+
+    void operator-- ()
+    {
+        handles_.template decrement<level>();
+    }
+
+    HierarchicalIterator operator++ (int)
+    {
+        HierarchicalIterator ret = *this;
+        ++(*this);
+        return ret;
+    }
+
+    HierarchicalIterator operator-- (int)
+    {
+        HierarchicalIterator ret = *this;
+        --(*this);
+        return ret;
+    }
+
+    HierarchicalIterator & operator+= (difference_type n)
+    {
+        handles_.addDim(level, n);
+        return *this;
+    }
+
+    HierarchicalIterator & operator+= (shape_type const & d)
+    {
+        handles_.add(d);
+        handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>::exec(shape(), d);
+        return *this;
+    }
+
+    HierarchicalIterator & operator-= (difference_type n)
+    {
+        handles_.addDim(level, -n);
+        return *this;
+    }
+
+    // HierarchicalIterator & operator-= (multi_difference_type const & d)
+    // {
+        // m_ptr -= d[level];
+        // return *this;
+    // }
+
+    HierarchicalIterator operator+ (difference_type n) const
+    {
+        return HierarchicalIterator(*this) += n;
+    }
+
+    // HierarchicalIterator operator+ (multi_difference_type const & d) const
+    // {
+        // HierarchicalIterator ret = *this;
+        // ret += d;
+        // return ret;
+    // }
+
+    difference_type operator- (HierarchicalIterator const & d) const
+    {
+        return point()[level] - d.point()[level];
+    }
+
+    HierarchicalIterator operator- (difference_type n) const
+    {
+        return HierarchicalIterator(*this) -= n;
+    }
+
+    // HierarchicalIterator operator- (multi_difference_type const & d) const
+    // {
+        // HierarchicalIterator ret = *this;
+        // ret -= d;
+        // return ret;
+    // }
+
+    // reference operator[] (difference_type n) const
+    // {
+        // return m_ptr [n];
+    // }
+
+    // reference operator[] (multi_difference_type const & d) const
+    // {
+        // return m_ptr [d[level]];
+    // }
+    
+    reference operator* ()
+    {
+        return HandleTraits::dereference(handles_);
+    }
+
+    const_reference operator* () const
+    {
+        return HandleTraits::dereference(handles_);
+    }
+    
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, HANDLES>::reference
+    get()
+    {
+        return handles_.template get<TARGET_INDEX>();
+    }
+    
+    template <unsigned int TARGET_INDEX>
+    typename CoupledHandleCast<TARGET_INDEX, HANDLES>::const_reference
+    get() const
+    {
+        return handles_.template get<TARGET_INDEX>();
+    }
+
+    pointer operator->()
+    {
+        return &HandleTraits::dereference(handles_);
+    }
+
+    const_pointer operator->() const
+    {
+        return &HandleTraits::dereference(handles_);
+    }
+
+    bool operator== (const HierarchicalIterator &rhs) const
+    {
+        return point()[level] == rhs.point()[level];
+    }
+
+    bool operator!= (const HierarchicalIterator &rhs) const
+    {
+        return point()[level] != rhs.point()[level];
+    }
+
+    bool operator< (const HierarchicalIterator &rhs) const
+    {
+        return point()[level] < rhs.point()[level];
+    }
+
+    bool operator<= (const HierarchicalIterator &rhs) const
+    {
+        return point()[level] <= rhs.point()[level];
+    }
+
+    bool operator> (const HierarchicalIterator &rhs) const
+    {
+        return point()[level] > rhs.point()[level];
+    }
+
+    bool operator>= (const HierarchicalIterator &rhs) const
+    {
+        return point()[level] >= rhs.point()[level];
+    }
+
+    // iterator iteratorForDimension(unsigned int d) const
+    // {
+        // vigra_precondition(d == 0,
+            // "MultiIterator<1>::iteratorForDimension(d): d == 0 required");
+        // const difference_type stride = 1;
+        // return iterator(m_ptr, &stride, 0);
+    // }
+    
+    HierarchicalIterator getEndIterator() const
+    {
+        return HierarchicalIterator(*this) += shape() - point();
+    }
+
+    shape_type const & point() const
+    {
+        return handles_.point();
+    }
+
+    shape_type const & shape() const
+    {
+        return handles_.shape();
+    }
+
+    difference_type scanOrderIndex() const
+    {
+        return handles_.scanOrderIndex();
+    }
+    
+    HANDLES const & handles() const
+    {
+        return handles_;
+    }
+
+    template <int K>
+    HierarchicalIterator<N, HANDLES, 0> &
+    dim()
+    {
+        return *this;
+    }
+    
+    template <int K>
+    HierarchicalIterator<N, HANDLES, 0> const &
+    dim() const
+    {
+        return *this;
+    }
+
+  // protected:
+
+    // difference_type 
+    // total_stride(typename multi_difference_type::const_iterator d) const
+    // {
+        // return d[level];
+    // }
+};
+
+/** Helper class to easliy get the type of a CoupledScanOrderIterator (and corresponding CoupledHandle) for up to five arrays of dimension N with element types T1,...,T5.
+ */
+template <unsigned int N, class T1=void, class T2=void, class T3=void, class T4=void, class T5=void>
+struct HierarchicalIteratorType
+{
+    /** Type of the CoupledHandle.*/
+    typedef typename CoupledHandleType<N, T1, T2, T3, T4, T5>::type HandleType;
+  
+    /** Type of the CoupledScanOrderIterator.*/
+    typedef HierarchicalIterator<HandleType::dimensions, HandleType> IteratorType;
+    typedef IteratorType                                             type;
+};
+
+// /** Alias for \ref vigra::CoupledIteratorType (maybe easier to remember).
+ // */
+// template <unsigned int N, class T1=void, class T2=void, class T3=void, class T4=void, class T5=void>
+// struct CoupledArrays
+// : public CoupledIteratorType<N, T1, T2, T3, T4, T5>
+// {};
+
+/** Returns a HierarchicalIterator from shape to iterate over coordinates. 
+ */
+template <int N>
+typename HierarchicalIteratorType<N>::type
+createHierarchicalIterator(TinyVector<MultiArrayIndex, N> const & shape)
+{
+    typedef typename CoupledHandleType<N>::type   P0;
+    typedef HierarchicalIterator<N, P0> IteratorType;
+    
+    return IteratorType(P0(shape));
+}
+
+/** Returns a HierarchicalIterator to simultaneously iterate over image m1 and its coordinates. 
+ */
+template <unsigned int N1, class T1, class S1>
+typename HierarchicalIteratorType<N1, T1>::type
+createHierarchicalIterator(MultiArrayView<N1, T1, S1> const & m1)
+{
+    typedef typename CoupledHandleType<N1, T1>::type             P1;
+    typedef typename P1::base_type                               P0;
+    typedef HierarchicalIterator<P1::dimensions, P1>         IteratorType;
+    
+    return IteratorType(P1(m1, 
+                        P0(m1.shape())));
+}
+
+/** Returns a HierarchicalIterator to simultaneously iterate over images m1, m2 and their coordinates. 
+ */
+template <unsigned int N1, class T1, class S1,
+          unsigned int N2, class T2, class S2>
+typename HierarchicalIteratorType<N1, T1, T2>::type
+createHierarchicalIterator(MultiArrayView<N1, T1, S1> const & m1,
+                           MultiArrayView<N2, T2, S2> const & m2)
+{
+    typedef typename CoupledHandleType<N1, T1, T2>::type         P2;
+    typedef typename P2::base_type                               P1;
+    typedef typename P1::base_type                               P0;
+    typedef HierarchicalIterator<P2::dimensions, P2> IteratorType;
+    
+    return IteratorType(P2(m2, 
+                        P1(m1, 
+                        P0(m1.shape()))));
+}
+
+/** Returns a HierarchicalIterator to simultaneously iterate over images m1, m2, m3 and their coordinates. 
+ */
+template <unsigned int N1, class T1, class S1,
+          unsigned int N2, class T2, class S2,
+          unsigned int N3, class T3, class S3>
+typename HierarchicalIteratorType<N1, T1, T2, T3>::type
+createHierarchicalIterator(MultiArrayView<N1, T1, S1> const & m1,
+                           MultiArrayView<N2, T2, S2> const & m2,
+                           MultiArrayView<N3, T3, S3> const & m3)
+{
+    typedef typename CoupledHandleType<N1, T1, T2, T3>::type     P3;
+    typedef typename P3::base_type                               P2;
+    typedef typename P2::base_type                               P1;
+    typedef typename P1::base_type                               P0;
+    typedef HierarchicalIterator<P3::dimensions, P3> IteratorType;
+    
+    return IteratorType(P3(m3, 
+                        P2(m2, 
+                        P1(m1, 
+                        P0(m1.shape())))));
+}
+
+/** Returns a HierarchicalIterator to simultaneously iterate over images m1, m2, m3, m4 and their coordinates. 
+ */
+template <unsigned int N1, class T1, class S1,
+          unsigned int N2, class T2, class S2,
+          unsigned int N3, class T3, class S3,
+          unsigned int N4, class T4, class S4>
+typename HierarchicalIteratorType<N1, T1, T2, T3, T4>::type
+createHierarchicalIterator(MultiArrayView<N1, T1, S1> const & m1,
+                           MultiArrayView<N2, T2, S2> const & m2,
+                           MultiArrayView<N3, T3, S3> const & m3,
+                           MultiArrayView<N4, T4, S4> const & m4)
+{
+    typedef typename CoupledHandleType<N1, T1, T2, T3, T4>::type P4;
+    typedef typename P4::base_type                               P3;
+    typedef typename P3::base_type                               P2;
+    typedef typename P2::base_type                               P1;
+    typedef typename P1::base_type                               P0;
+    typedef HierarchicalIterator<P4::dimensions, P4> IteratorType;
+    
+    return IteratorType(P4(m4, 
+                        P3(m3, 
+                        P2(m2, 
+                        P1(m1, 
+                        P0(m1.shape()))))));
+}
+
+/** Returns a HierarchicalIterator to simultaneously iterate over images m1, m2, m3, m4, m5 and their coordinates. 
+ */
+template <unsigned int N1, class T1, class S1,
+          unsigned int N2, class T2, class S2,
+          unsigned int N3, class T3, class S3,
+          unsigned int N4, class T4, class S4,
+          unsigned int N5, class T5, class S5>
+typename HierarchicalIteratorType<N1, T1, T2, T3, T4, T5>::type
+createHierarchicalIterator(MultiArrayView<N1, T1, S1> const & m1,
+                           MultiArrayView<N2, T2, S2> const & m2,
+                           MultiArrayView<N3, T3, S3> const & m3,
+                           MultiArrayView<N4, T4, S4> const & m4,
+                           MultiArrayView<N5, T5, S5> const & m5)
+{
+    typedef typename CoupledHandleType<N1, T1, T2, T3, T4, T5>::type P5;
+    typedef typename P5::base_type                                   P4;
+    typedef typename P4::base_type                                   P3;
+    typedef typename P3::base_type                                   P2;
+    typedef typename P2::base_type                                   P1;
+    typedef typename P1::base_type                                   P0;
+    typedef HierarchicalIterator<P5::dimensions, P5> IteratorType;
+    
+    return IteratorType(P5(m5, 
+                        P4(m4, 
+                        P3(m3, 
+                        P2(m2, 
+                        P1(m1, 
+                        P0(m1.shape())))))));
+}
+
+
+template <unsigned int N, class A, class B>
+HierarchicalIterator<N, typename ZipCoupledHandles<A, B>::type>
+zip(HierarchicalIterator<N, A> const & a, HierarchicalIterator<N, B> const & b)
+{
+    vigra_precondition(a.shape() == b.shape() && a.scanOrderIndex() == b.scanOrderIndex(),
+         "zip(HierarchicalIterator): iterators must have identical shape and position.");
+         
+    typedef typename ZipCoupledHandles<A, B>::type Handle;
+    typedef HierarchicalIterator<N, Handle> IteratorType;
+    return IteratorType(ZipCoupledHandles<A, B>::construct(a.handles(), b.handles()));
+}
+
+//@}
+
+} // namespace vigra
+
+// namespace std {
+
+// template <unsigned int N, class T, class REFERENCE, class POINTER>
+// ostream & operator<<(ostream & o, vigra::StridedScanOrderIterator<N, T, REFERENCE, POINTER> const & i)
+// {
+    // o << *i;
+    // return o;
+// }
+
+// } // namespace std
+
+#endif // VIGRA_MULTI_HIERARCHICAL_ITERATOR_HXX
diff --git a/include/vigra/multi_histogram.hxx b/include/vigra/multi_histogram.hxx
new file mode 100644
index 0000000..e8796f9
--- /dev/null
+++ b/include/vigra/multi_histogram.hxx
@@ -0,0 +1,332 @@
+/************************************************************************/
+/*                                                                      */
+/*         Copyright 2002-2003 by Ullrich Koethe, Hans Meine            */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_MULTI_HISTOGRAMM_HXX
+#define VIGRA_MULTI_HISTOGRAMM_HXX
+
+#include "multi_array.hxx"
+#include "tinyvector.hxx"
+#include "multi_gridgraph.hxx"
+#include "multi_convolution.hxx"
+
+
+namespace vigra{
+
+
+    template< unsigned int DIM , class T_DATA ,unsigned int CHANNELS, class T_HIST >
+    void multiGaussianHistogram(
+        const MultiArrayView<DIM, TinyVector<T_DATA,CHANNELS> > & image,
+        const TinyVector<T_DATA,CHANNELS> minVals,
+        const TinyVector<T_DATA,CHANNELS> maxVals,
+        const size_t bins,
+        const float sigma,
+        const float sigmaBin,
+        MultiArrayView<DIM+2 , T_HIST>    histogram
+    ){
+        typedef vigra::GridGraph< DIM , undirected_tag> Graph;
+        typedef typename Graph::NodeIt graph_scanner;
+        typedef typename Graph::Node   Node;
+        typedef T_HIST ValueType;
+        typedef TinyVector<ValueType,CHANNELS> ChannelsVals;
+        typedef typename MultiArrayView<DIM+2 , T_HIST>::difference_type HistCoord;
+        const Graph g(image.shape());
+        const ChannelsVals nBins(bins);
+        histogram.init(1.0);
+        // iterate over all nodes (i.e. pixels)
+        for (graph_scanner n(g); n != lemon::INVALID; ++n){
+            const Node node(*n);
+            ChannelsVals  binIndex = image[node];
+            binIndex -=minVals;
+            binIndex /=maxVals;
+            binIndex *=nBins;
+            HistCoord histCoord;
+            for(size_t d=0;d<DIM;++d){
+                histCoord[d]=node[d];
+            }
+            for(size_t c=0;c<CHANNELS;++c){
+                const float fi = binIndex[c];
+                const size_t bi = std::floor(fi+0.5);
+                histCoord[DIM]=std::min(bi,static_cast<size_t>(bins-1));
+                histCoord[DIM+1]=c;
+                histogram[histCoord]+=1.0;
+            }
+        }
+
+        //MultiArray<DIM+2 , T_HIST>    histogramBuffer(histogram);
+        Kernel1D<float> gauss,gaussBin;
+        gauss.initGaussian(sigma);
+        gaussBin.initGaussian(sigmaBin);
+        for(size_t c=0;c<CHANNELS;++c){
+
+            // histogram for one channel
+            MultiArrayView<DIM+1,T_HIST> histc       = histogram.bindOuter(c);
+            //MultiArrayView<DIM+1,T_HIST> histcBuffer = histogram.bindOuter(c);
+
+            ConvolutionOptions<DIM+1> opts;
+            TinyVector<double, DIM+1> sigmaVec(sigma);
+            sigmaVec[DIM] = sigmaBin;
+            opts.stdDev(sigmaVec);
+
+            // convolve spatial dimensions
+            gaussianSmoothMultiArray(histc, histc, opts);
+
+        }
+
+    }
+
+    template< unsigned int DIM , class T_DATA, class T_HIST >
+    void multiGaussianCoHistogram(
+        const MultiArrayView<DIM, T_DATA > & imageA,
+        const MultiArrayView<DIM, T_DATA > & imageB,
+        const TinyVector<T_DATA,2> & minVals,
+        const TinyVector<T_DATA,2> & maxVals,
+        const TinyVector<int,2> & nBins,
+        const TinyVector<float,3> & sigma,
+        MultiArrayView<DIM+2, T_HIST> histogram
+    ){
+        typedef vigra::GridGraph< DIM , undirected_tag> Graph;
+        typedef typename Graph::NodeIt graph_scanner;
+        typedef typename Graph::Node   Node;
+        typedef typename MultiArrayView<DIM+2 , T_HIST>::difference_type HistCoord;
+        const Graph g(imageA.shape());
+        histogram.init(0.0);
+        // iterate over all nodes (i.e. pixels)
+        for (graph_scanner n(g); n != lemon::INVALID; ++n){
+
+            const Node node(*n);
+            T_DATA  binIndexA = imageA[node];
+            T_DATA  binIndexB = imageA[node];
+
+            binIndexA -=minVals[0];
+            binIndexA /=maxVals[0];
+            binIndexA *=nBins[0];
+
+            binIndexB -=minVals[1];
+            binIndexB /=maxVals[1];
+            binIndexB *=nBins[1];
+
+            HistCoord histCoord;
+            for(size_t d=0;d<DIM;++d)
+                histCoord[d]=node[d];
+
+            histCoord[DIM]=binIndexA;
+            histCoord[DIM+1]=binIndexB;
+
+            const float fiA = binIndexA;
+            const unsigned int biA = std::floor(fiA+0.5);
+            const float fiB = binIndexB;
+            const unsigned int biB = std::floor(fiA+0.5);
+            histCoord[DIM]=std::min(biA,static_cast<unsigned int>(nBins[0]-1));
+            histCoord[DIM+1]=std::min(biB,static_cast<unsigned int>(nBins[1]-1));
+            histogram[histCoord]+=1.0;
+
+        }
+
+        MultiArray<DIM+2 , T_HIST>    histogramBuffer(histogram);
+        Kernel1D<float> gaussS,gaussA,gaussB;
+        gaussS.initGaussian(sigma[0]);
+        gaussA.initGaussian(sigma[1]);
+        gaussB.initGaussian(sigma[2]);
+
+        if(DIM==2){
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogram), destMultiArray(histogramBuffer), 0, gaussS);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogramBuffer), destMultiArray(histogram), 1, gaussS);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogram), destMultiArray(histogramBuffer), 2, gaussA);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogramBuffer), destMultiArray(histogram), 3, gaussB);
+        }
+        else if(DIM==3){
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogram), destMultiArray(histogramBuffer), 0, gaussS);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogramBuffer), destMultiArray(histogram), 1, gaussS);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogram), destMultiArray(histogramBuffer), 2, gaussS);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogramBuffer), destMultiArray(histogram), 3, gaussA);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogram), destMultiArray(histogramBuffer), 4, gaussB);
+            histogram=histogramBuffer;
+        }
+        else if(DIM==4){
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogram), destMultiArray(histogramBuffer), 0, gaussS);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogramBuffer), destMultiArray(histogram), 1, gaussS);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogram), destMultiArray(histogramBuffer), 2, gaussS);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogramBuffer), destMultiArray(histogram), 3, gaussS);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogram), destMultiArray(histogramBuffer), 4, gaussA);
+            convolveMultiArrayOneDimension(srcMultiArrayRange(histogramBuffer), destMultiArray(histogram), 5, gaussA);
+        }
+        else{
+            throw std::runtime_error("not yet implemented for arbitrary dimension");
+        }
+
+    }
+
+
+
+
+    template< unsigned int DIM , class T, class V, class U>
+    void multiGaussianRankOrder(
+        const MultiArrayView<DIM, T > & image,
+        const T minVal,
+        const T maxVal,
+        const size_t bins,
+        const TinyVector<double, DIM+1> sigmas,
+        const MultiArrayView<1, V> & ranks,
+        MultiArrayView<DIM+1, U> out
+    ){
+        typedef MultiArray<DIM, T> ImgType;
+        typedef typename ImgType::difference_type ImgCoord;
+
+        typedef MultiArray<DIM+1, float> HistType;
+        typedef typename HistType::difference_type HistCoord;
+
+        typedef MultiArray<DIM+1, U> OutType;
+        typedef typename OutType::difference_type OutCoord;
+
+
+        HistCoord histShape;
+        std::copy(image.shape().begin(), image.shape().end(), histShape.begin());
+        histShape[DIM] = bins;
+        HistType histA(histShape);
+
+        histA = 0.0;
+
+        // collect values
+        HistCoord histCoord,nextHistCoord;
+        {
+            MultiCoordinateIterator<DIM> iter(image.shape());
+            for(std::ptrdiff_t i=0 ;i<image.size(); ++i, ++iter){
+                const ImgCoord imgCoord(*iter);
+                std::copy(imgCoord.begin(),imgCoord.end(),histCoord.begin() );
+
+                const T value = image[imgCoord];
+                const T fbinIndex = ((value-minVal)/(maxVal-minVal))*bins;
+                const T fFloorBin = std::floor(fbinIndex);
+                const int floorBin = static_cast<int>(fFloorBin);
+                const int ceilBin = static_cast<int>(std::ceil(fbinIndex));
+
+                if(floorBin==ceilBin){
+                   histCoord[DIM] = floorBin;
+                   histA[histCoord] += 1.0;
+                }
+                else{
+                    const T floorBin = std::floor(fbinIndex);
+                    const T ceilBin = std::ceil(fbinIndex);
+                    const double ceilW = (fbinIndex - fFloorBin);
+                    const double floorW = 1.0 - ceilW;
+                    histCoord[DIM] = floorBin;
+                    histA[histCoord] += floorW;
+                    histCoord[DIM] = ceilBin;
+                    histA[histCoord] += ceilW;
+                }
+
+            }
+        }
+        //
+        ConvolutionOptions<DIM+1> opts;
+        opts.stdDev(sigmas);
+
+        // convolve spatial dimensions
+        gaussianSmoothMultiArray(histA, histA, opts);
+
+        OutCoord outCoord;
+
+
+        std::vector<float> histBuffer(bins);
+        //std::cout<<"normalize and compute ranks\n";
+        {
+            MultiCoordinateIterator<DIM> iter(image.shape());
+            for(std::ptrdiff_t i=0 ;i<image.size(); ++i, ++iter){
+
+                // normalize
+                const ImgCoord imgCoord(*iter);
+                //std::cout<<"at pixel "<<imgCoord<<"\n";
+
+                std::copy(imgCoord.begin(),imgCoord.end(),histCoord.begin() );
+                nextHistCoord = histCoord;
+                std::copy(imgCoord.begin(),imgCoord.end(),outCoord.begin() );
+                double sum = 0;
+                for(size_t bi=0; bi<bins; ++bi){
+                    histCoord[DIM] = bi;
+                    sum += histA[histCoord];
+                }
+                for(size_t bi=0; bi<bins; ++bi){
+                    histCoord[DIM] = bi;
+                    histA[histCoord] /= sum;
+                }
+                histCoord[DIM] = 0;
+                histBuffer[0] = histA[histCoord];
+                for(size_t bi=1; bi<bins; ++bi){
+
+                    double prevVal =  histA[histCoord];
+                    histCoord[DIM] = bi;
+                    histA[histCoord] +=prevVal;
+                    histBuffer[bi] = histA[histCoord];
+                }
+
+
+
+                size_t bi=0;
+                for(std::ptrdiff_t r=0; r<ranks.size(); ++r){
+                    outCoord[DIM] = r;
+                    const V rank = ranks[r];
+                    histCoord[DIM] = bi;
+                    nextHistCoord[DIM] = bi +1;
+                    //std::cout<<"    bi "<<bi<<" rank "<<rank<<" "<<histA[histCoord]<<"\n";
+                    // corner cases
+                    if(rank < histA[histCoord] ||
+                       std::abs(rank-histA[histCoord])< 0.0000001 ||
+                       bi==bins-1
+                    ){
+                        out[outCoord] = static_cast<U>((maxVal-minVal)*bi*bins + minVal);
+                        break;
+                    }
+                    else{
+                        // with binary search
+                        const size_t upperBinIndex =
+                            std::distance(histBuffer.begin(),std::lower_bound(histBuffer.begin()+bi, histBuffer.end(),float(rank)));
+                        bi = upperBinIndex - 1;
+                        histCoord[DIM] = bi;
+                        nextHistCoord[DIM] = upperBinIndex;
+                        const double rankVal0 = static_cast<U>((maxVal-minVal)*bi*bins + minVal);
+                        const double rankVal1 = static_cast<U>((maxVal-minVal)*(bi+1)*bins + minVal);
+                        const double dd = histA[nextHistCoord] - histA[histCoord];
+                        const double relD0 = (rank - histA[histCoord])/dd;
+                        out[outCoord] = rankVal1 * relD0  + (1.0 - relD0)*rankVal0;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
+//end namespace vigra
+
+#endif //VIGRA_MULTI_HISTOGRAMM_HXX
diff --git a/include/vigra/multi_impex.hxx b/include/vigra/multi_impex.hxx
index e154cec..9ec1498 100644
--- a/include/vigra/multi_impex.hxx
+++ b/include/vigra/multi_impex.hxx
@@ -66,9 +66,9 @@ namespace vigra {
 
 /** \brief Argument object for the function importVolume().
 
-    See \ref importVolume() for usage example. This object can be used
-    to define the properties of a volume data set to be read from disk.
-    Sorry, no \ref detailedDocumentation() available yet.
+    This object can be used to define the properties of a volume
+    data set to be read from disk. It works like \ref vigra::ImageImportInfo,
+    but for 3-dimensional data. See \ref importVolume() for usage example.
 
     <b>\#include</b> \<vigra/multi_impex.hxx\> <br/>
     Namespace: vigra
@@ -88,14 +88,14 @@ class VolumeImportInfo
     typedef TinyVector<float, 3>       Resolution;
 
         /** Construct VolumeImportInfo from a single filename.
-        
+
             The \a filename (which may contain a path) can be interpreted in three different ways:
             <ul>
             <li>If the name refers to a file that contains volume data, the header information
                 of this file is read. Two file formats are currently supported: Andor .SIF
                 and multi-page TIFF.
             <li>If the name refers to a textfile, the constructor will attempt to interpret the file
-                in the ".info" format to obtain the header information. The volume data 
+                in the ".info" format to obtain the header information. The volume data
                 are then expected to be located in an accompanying RAW file. The ".info" file must
                 contain the following key-value pairs:
                 <UL>
@@ -107,9 +107,9 @@ class VolumeImportInfo
                 <li> depth = [positive integer] (required)
                 <li> datatype = [ UINT8 | INT16 | UINT16 | INT32 | UINT32 | FLOAT | DOUBLE ] (required)
                 </UL>
-                Lines starting with "#" are ignored. To read the data correctly, the 
-                value_type of the target MultiArray must match the datatype stored in the file. 
-                Only single-band files are currently supported. 
+                Lines starting with "#" are ignored. To read the data correctly, the
+                value_type of the target MultiArray must match the datatype stored in the file.
+                Only single-band files are currently supported.
             <li>If the name refers to a 2D image file, the constructor will attempt to decompose
                 the filename into the format <tt>base_name + slice_number + name_extension</tt>.
                 If this decomposition succeeds, all images with the same base_name and name_extension
@@ -122,12 +122,12 @@ class VolumeImportInfo
     VIGRA_EXPORT VolumeImportInfo(const std::string &filename);
 
         /** Construct VolumeImportInfo for a stack of images.
-        
+
             The constructor will look for filenames of the form <tt>base_name + slice_number + name_extension</tt>.
-            All images conforming to this pattern will be considered as the slices of an image stack. 
-            Slice numbers need not be consecutive (i.e. gaps are allowed) and will be interpreted according 
+            All images conforming to this pattern will be considered as the slices of an image stack.
+            Slice numbers need not be consecutive (i.e. gaps are allowed) and will be interpreted according
             to their numerical order (i.e. "009", "010", "011" are read in the same order as "9", "10", "11").
-            The number of images found determines the depth of the volume, the remaining header data are read 
+            The number of images found determines the depth of the volume, the remaining header data are read
             from the given image. \a name_base may contain a path.
          */
     VIGRA_EXPORT VolumeImportInfo(const std::string &base_name, const std::string &name_extension);
@@ -196,7 +196,7 @@ class VolumeImportInfo
 
         /** Query the pixel type of the volume data.
 
-            Same as getPixelType(), but the result is returned as a 
+            Same as getPixelType(), but the result is returned as a
             ImageImportInfo::PixelType enum. This is useful to implement
             a switch() on the pixel type.
 
@@ -259,29 +259,29 @@ class VolumeExportInfo
   public:
         /** Construct VolumeExportInfo object to output volume data as a multi-page tiff.
 
-            The filename must refer to a TIFF file (extension '.tif' or '.tiff'). This function 
+            The filename must refer to a TIFF file (extension '.tif' or '.tiff'). This function
             is only available when libtiff is installed.
          **/
     VIGRA_EXPORT VolumeExportInfo( const char * filename );
-    
+
         /** Construct VolumeExportInfo object to output volume data as an image stack.
 
-            The volume will be stored in a by-slice manner, where the number of slices 
+            The volume will be stored in a by-slice manner, where the number of slices
             equals the depth of the volume. The file names will be enumerated like
             <tt>name_base+"000"+name_ext</tt>, <tt>name_base+"001"+name_ext</tt> etc.
             (the actual number of zeros depends on the depth). If the target image type
-            does not support the source voxel type, all slices will be mapped 
+            does not support the source voxel type, all slices will be mapped
             simultaneously to the appropriate target range.
             The file type will be guessed from the extension unless overridden
-            by \ref setFileType(). 
-            
+            by \ref setFileType().
+
             Recognized extensions: '.bmp', '.gif',
             '.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras',
             '.tif', '.tiff', '.xv', '.hdr'.
-            
+
             JPEG support requires libjpeg, PNG support requires libpng, and
             TIFF support requires libtiff.
-            
+
             If \a name_ext is an empty string, the data is written as a multi-page tiff.
          **/
     VIGRA_EXPORT VolumeExportInfo( const char * name_base, const char * name_ext );
@@ -291,14 +291,14 @@ class VolumeExportInfo
 
         **/
     VIGRA_EXPORT VolumeExportInfo & setFileNameBase(const char * name_base);
-    
+
         /** Set volume file name extension.
 
             The file type will be guessed from the extension unless overridden
             by \ref setFileType(). Recognized extensions: '.bmp', '.gif',
             '.jpeg', '.jpg', '.p7', '.png', '.pbm', '.pgm', '.pnm', '.ppm', '.ras',
             '.tif', '.tiff', '.xv', '.hdr'.
-            
+
             JPEG support requires libjpeg, PNG support requires libpng, and
             TIFF support requires libtiff.
         **/
@@ -389,15 +389,15 @@ class VolumeExportInfo
             </DL>
          **/
     VIGRA_EXPORT const char * getPixelType() const;
-    
+
     VIGRA_EXPORT VolumeExportInfo & setForcedRangeMapping(double fromMin, double fromMax,
-                                                     double toMin, double toMax);    
+                                                     double toMin, double toMax);
     VIGRA_EXPORT bool hasForcedRangeMapping() const;
     VIGRA_EXPORT double getFromMin() const;
     VIGRA_EXPORT double getFromMax() const;
     VIGRA_EXPORT double getToMin() const;
     VIGRA_EXPORT double getToMax() const;
-    
+
         /** Set the volume resolution in horizontal direction
          **/
     VIGRA_EXPORT VolumeExportInfo & setXResolution( float );
@@ -545,10 +545,10 @@ void VolumeImportInfo::importImpl(MultiArrayView <3, T, Stride> &volume) const
         for (unsigned int i = 0; i < numbers_.size(); ++i)
         {
             // build the filename
-            std::string name = baseName_ + numbers_[i] + extension_;
+            std::string filename = baseName_ + numbers_[i] + extension_;
 
             // import the image
-            ImageImportInfo info (name.c_str ());
+            ImageImportInfo info (filename.c_str ());
 
             // generate a basic image view to the current layer
             MultiArrayView <2, T, Stride> view (volume.bindOuter (i));
@@ -594,38 +594,38 @@ VIGRA_EXPORT void findImageSequence(const std::string &name_base,
 /** \brief Function for importing a 3D volume.
 
     <b>Declarations: </b>
-    
+
     \code
     namespace vigra {
         // variant 1: read data specified by the given VolumeImportInfo object
         template <class T, class Stride>
-        void 
-        importVolume(VolumeImportInfo const & info, 
+        void
+        importVolume(VolumeImportInfo const & info,
                      MultiArrayView <3, T, Stride> &volume);
-                     
+
         // variant 2: read data using a single filename, resize volume automatically
         template <class T, class Allocator>
-        void 
+        void
         importVolume(MultiArray <3, T, Allocator> & volume,
                      const std::string &filename);
-                           
+
         // variant 3: read data from an image stack, resize volume automatically
         template <class T, class Allocator>
-        void 
+        void
         importVolume(MultiArray <3, T, Allocator> & volume,
                      const std::string &name_base,
                      const std::string &name_ext);
     }
     \endcode
 
-    Data can be read either from a single file containing 3D data (supported formats: 
-    Andor .SIF or multi-page TIFF), a ".info" text file which describes the contents of 
-    an accompanying raw data file, or a stack of 2D images (numbered according to the 
-    scheme <tt>name_base+"[0-9]+"+name_extension</tt>) each representing a slice of 
-    the volume. The decision which of these possibilities applies is taken in the 
+    Data can be read either from a single file containing 3D data (supported formats:
+    Andor .SIF or multi-page TIFF), a ".info" text file which describes the contents of
+    an accompanying raw data file, or a stack of 2D images (numbered according to the
+    scheme <tt>name_base+"[0-9]+"+name_extension</tt>) each representing a slice of
+    the volume. The decision which of these possibilities applies is taken in the
     \ref vigra::VolumeImportInfo::VolumeImportInfo(const std::string &) "VolumeImportInfo constructor",
     see there for full details.
-    
+
     Variant 1 is the basic version of this function. Here, the info object and a destination
     array of approriate size must already be constructed. The other variants are just abbreviations
     provided for your convenience:
@@ -634,46 +634,46 @@ VIGRA_EXPORT void findImageSequence(const std::string &name_base,
     VolumeImportInfo info(filename);
     volume.reshape(info.shape());
     importVolume(info, volume);    // call variant 1
-    
+
     // variant 3 is equivalent to
     VolumeImportInfo info(name_base, name_ext);
     volume.reshape(info.shape());
     importVolume(info, volume);    // call variant 1
     \endcode
-    
+
     <b> Usage:</b>
 
     <b>\#include</b> \<vigra/multi_impex.hxx\> <br/>
     Namespace: vigra
-    
+
     \code
     // read data from a multi-page TIFF file, using variant 1
     VolumeImportInfo info("multipage.tif");
     MultiArray<3, float> volume(info.shape());
     importVolume(info, volume);
-    
+
     // read data from a stack of 2D png-images, using variant 1
     VolumeImportInfo info("my_data", ".png");  // looks for files 'my_data0.png', 'my_data1.png' etc.
     MultiArray<3, float> volume(info.shape());
     importVolume(info, volume);
     \endcode
-    Notice that slice numbers in a stack need not be consecutive (i.e. gaps are allowed) and 
-    will be interpreted according to their numerical order (i.e. "009", "010", "011" 
+    Notice that slice numbers in a stack need not be consecutive (i.e. gaps are allowed) and
+    will be interpreted according to their numerical order (i.e. "009", "010", "011"
     are read in the same order as "9", "10", "11"). The number of images
     found determines the depth of the volume.
 */
 doxygen_overloaded_function(template <...> void importVolume)
 
 template <class T, class Stride>
-void 
-importVolume(VolumeImportInfo const & info, 
+void
+importVolume(VolumeImportInfo const & info,
              MultiArrayView <3, T, Stride> &volume)
 {
     info.importImpl(volume);
 }
 
 template <class T, class Allocator>
-void 
+void
 importVolume(MultiArray <3, T, Allocator> &volume,
              const std::string &filename)
 {
@@ -775,21 +775,21 @@ void setRangeMapping(MultiArrayView <3, T, Tag> const & volume,
 /** \brief Function for exporting a 3D volume.
 
     <b> Declarations:</b>
-    
+
     \code
     namespace vigra {
         // variant 1: writa data as specified in the given VolumeExportInfo object
         template <class T, class Tag>
-        void 
+        void
         exportVolume (MultiArrayView <3, T, Tag> const & volume,
                       const VolumeExportInfo & info);
-                     
+
         // variant 2: write data to a multi-page TIFF file
         template <class T, class Tag>
         void
         exportVolume (MultiArrayView <3, T, Tag> const & volume,
                       const std::string &filename);
-                           
+
         // variant 3: write data to an image stack
         template <class T, class Tag>
         void
@@ -800,24 +800,24 @@ void setRangeMapping(MultiArrayView <3, T, Tag> const & volume,
     \endcode
 
     The volume can either be exported as a multi-page TIFF file (variant 2, only available if
-    libtiff is installed), or as a stack of 2D images, one image per slice (variant 3, files are named 
+    libtiff is installed), or as a stack of 2D images, one image per slice (variant 3, files are named
     according to the scheme <tt>name_base+"000"+name_ext</tt>, <tt>name_base+"001"+name_ext</tt> etc.).
-    If the target image format does not support the source <tt>value_type</tt>, all slices will 
+    If the target image format does not support the source <tt>value_type</tt>, all slices will
     be mapped to the appropriate target range in the same way.
-    
+
     Variant 1 is the basic version of the function. It allows full control over the export via
     an already constructed \ref vigra::VolumeExportInfo object. The other two are just abbreviations
-    that construct the VolumeExportInfo object internally. 
-    
+    that construct the VolumeExportInfo object internally.
+
     <b> Usage:</b>
 
     <b>\#include</b> \<vigra/multi_impex.hxx\> <br/>
     Namespace: vigra
-    
+
     \code
     MultiArray<3, RGBValue<UInt8> > volume(shape);
     ... // fill in data
-    
+
     // export a stack named "my_data01.jpg", "my_data02.jpg" etc.
     VolumeExportInfo info("my_data", ".jpg");
     info.setCompression("JPEG QUALITY=95");
@@ -827,7 +827,7 @@ void setRangeMapping(MultiArrayView <3, T, Tag> const & volume,
 doxygen_overloaded_function(template <...> void exportVolume)
 
 template <class T, class Tag>
-void 
+void
 exportVolume (MultiArrayView <3, T, Tag> const & volume,
               const VolumeExportInfo & volinfo)
 {
@@ -837,7 +837,7 @@ exportVolume (MultiArrayView <3, T, Tag> const & volume,
         std::string compression = "LZW";
         if(volinfo.getCompression() != std::string())
             compression = volinfo.getCompression();
-            
+
         for(MultiArrayIndex k=0; k<volume.shape(2); ++k)
         {
             ImageExportInfo info(volinfo.getFileNameBase(), mode);
@@ -866,13 +866,16 @@ exportVolume (MultiArrayView <3, T, Tag> const & volume,
             stream << std::setfill ('0') << std::setw (numlen) << i;
             std::string name_num;
             stream >> name_num;
-            std::string name = std::string(volinfo.getFileNameBase()) + name_num + std::string(volinfo.getFileNameExt());
+            std::string sliceFilename =
+                std::string(volinfo.getFileNameBase()) +
+                name_num +
+                std::string(volinfo.getFileNameExt());
 
             MultiArrayView <2, T, Tag> view (volume.bindOuter (i));
 
             // export the image
-            info.setFileName(name.c_str ());
-            exportImage(srcImageRange(view), info); 
+            info.setFileName(sliceFilename.c_str ());
+            exportImage(srcImageRange(view), info);
         }
     }
 }
diff --git a/include/vigra/multi_iterator.hxx b/include/vigra/multi_iterator.hxx
index 3c29884..c6faf29 100644
--- a/include/vigra/multi_iterator.hxx
+++ b/include/vigra/multi_iterator.hxx
@@ -38,14 +38,12 @@
 #define VIGRA_MULTI_ITERATOR_HXX
 
 #include <sys/types.h>
+#include "multi_fwd.hxx"
 #include "iteratortags.hxx"
 #include "multi_iterator_coupled.hxx"
 
 namespace vigra {
 
-template<unsigned int N, class DirectedTag>
-class GridGraph;
-
 /** \addtogroup MultiIteratorGroup
 */
 //@{
@@ -123,6 +121,19 @@ class MultiCoordinateIterator
        : base_type(handle_type(g.shape()))
     {}
 
+
+    template<class DirectedTag>
+    explicit MultiCoordinateIterator(GridGraph<N, DirectedTag> const & g, const typename  GridGraph<N, DirectedTag>::Node & node) 
+       : base_type(handle_type(g.shape()))
+    {
+        if( isInside(g,node))
+            (*this)+=node;
+        else
+            *this=this->getEndIterator();
+    }
+
+
+
     // dereferencing the iterator yields the coordinate object
     // (used as vertex_descriptor)
     reference operator*()
@@ -256,18 +267,20 @@ class MultiCoordinateIterator
         <b>\#include</b> \<vigra/multi_iterator.hxx\><br/>
         Namespace: vigra
     */
-template <unsigned int N, class T, class REFERENCE, class POINTER>
+template <unsigned int N, class V, class REFERENCE, class POINTER>
 class StridedScanOrderIterator
-    : public CoupledIteratorType<N, T>::type
+    : public CoupledIteratorType<N, V>::type
 {
   public:
-    typedef typename CoupledIteratorType<N, T>::type  base_type;
+    typedef typename CoupledIteratorType<N, V>::type  base_type;
+    typedef typename base_type::value_type            handle_type;
 
     typedef typename base_type::shape_type         shape_type;
     typedef typename base_type::difference_type    difference_type;
-    typedef StridedScanOrderIterator              iterator;
+    typedef StridedScanOrderIterator               iterator;
     typedef std::random_access_iterator_tag        iterator_category;
 
+    typedef typename detail::ResolveChunkedMemory<V>::type T;
     typedef T                                      value_type;
     typedef REFERENCE                              reference;
     typedef T const &                              const_reference;
@@ -287,6 +300,10 @@ class StridedScanOrderIterator
         : base_type(createCoupledIterator(MultiArrayView<N, T, StridedArrayTag>(shape, strides, const_cast<T *>(p))))
     {}
 
+    StridedScanOrderIterator(handle_type const & handle) 
+        : base_type(handle)
+    {}
+
     reference operator*()
     {
         return this->template get<1>();
@@ -317,6 +334,16 @@ class StridedScanOrderIterator
         return *(StridedScanOrderIterator(*this) += i);
     }
 
+    reference operator[](const shape_type& coordOffset)
+    {
+        return *(StridedScanOrderIterator(*this) += coordOffset);
+    }
+
+    const_reference operator[](const shape_type& coordOffset) const
+    {
+        return *(StridedScanOrderIterator(*this) += coordOffset);
+    }
+
     StridedScanOrderIterator & operator++()
     {
         base_type::operator++();
@@ -399,6 +426,13 @@ class StridedScanOrderIterator
     {
         return this->scanOrderIndex();
     }
+
+    StridedScanOrderIterator & 
+    restrictToSubarray(shape_type const & start, shape_type const & stop)
+    {
+        base_type::restrictToSubarray(start, stop);
+        return *this;
+    }
     
   protected:
     StridedScanOrderIterator(base_type const & base) 
@@ -709,12 +743,6 @@ struct MultiIteratorStrideTraits
     }
 };
 
-template <unsigned int N, class T, class REFERENCE = T &, class POINTER = T *>
-class MultiIterator;
-
-template <unsigned int N, class T, class REFERENCE = T &, class POINTER = T *>
-class StridedMultiIterator;
-
 /********************************************************/
 /*                                                      */
 /*                      MultiIterator                   */
diff --git a/include/vigra/multi_iterator_coupled.hxx b/include/vigra/multi_iterator_coupled.hxx
index 0458aba..3b1d91a 100644
--- a/include/vigra/multi_iterator_coupled.hxx
+++ b/include/vigra/multi_iterator_coupled.hxx
@@ -36,8 +36,10 @@
 #ifndef MULTI_ITERATOR_COUPLED_HXX
 #define MULTI_ITERATOR_COUPLED_HXX
 
-#include "metaprogramming.hxx"
+#include "multi_fwd.hxx"
 #include "multi_shape.hxx"
+#include "multi_handle.hxx"
+#include "metaprogramming.hxx"
 
 namespace vigra {
 
@@ -45,443 +47,107 @@ namespace vigra {
 */
 //@{
 
-  /**
-     Handle class, used by CoupledScanOrderIterator as the value type to simultaneously itearate over multiple images.
-  */
-template <class T, class NEXT>
-class CoupledHandle
-: public NEXT
-{
-public:
-    typedef NEXT                            base_type;
-    typedef CoupledHandle<T, NEXT>          self_type;
-    
-    static const int index =                NEXT::index + 1;    // index of this member of the chain
-    static const unsigned int dimensions =  NEXT::dimensions;
-
-    typedef T                               value_type;
-    typedef T *                             pointer;
-    typedef T const *                       const_pointer;
-    typedef T &                             reference;
-    typedef T const &                       const_reference;
-    typedef typename base_type::shape_type  shape_type;
-
-    CoupledHandle()
-    : base_type(),
-      pointer_(), 
-      strides_()
-    {}
-
-    CoupledHandle(const_pointer p, shape_type const & strides, NEXT const & next)
-    : base_type(next),
-      pointer_(const_cast<pointer>(p)), 
-      strides_(strides)
-    {}
-
-    template <class Stride>
-    CoupledHandle(MultiArrayView<dimensions, T, Stride> const & v, NEXT const & next)
-    : base_type(next),
-      pointer_(const_cast<pointer>(v.data())), 
-      strides_(v.stride())
-    {
-        vigra_precondition(v.shape() == this->shape(), "createCoupledIterator(): shape mismatch.");
-    }
-
-    template<int DIMENSION>
-    inline void increment() 
-    {
-        pointer_ += strides_[DIMENSION];
-        base_type::template increment<DIMENSION>();
-    }
-    
-    template<int DIMENSION>
-    inline void decrement() 
-    {
-        pointer_ -= strides_[DIMENSION];
-        base_type::template decrement<DIMENSION>();
-    }
-    
-    // TODO: test if making the above a default case of the this hurts performance
-    template<int DIMENSION>
-    inline void increment(MultiArrayIndex offset) 
-    {
-        pointer_ += offset*strides_[DIMENSION];
-        base_type::template increment<DIMENSION>(offset);
-    }
-    
-    template<int DIMENSION>
-    inline void decrement(MultiArrayIndex offset) 
-    {
-        pointer_ -= offset*strides_[DIMENSION];
-        base_type::template decrement<DIMENSION>(offset);
-    }
-    
-    void restrictToSubarray(shape_type const & start, shape_type const & end)
-    {
-        pointer_ += dot(start, strides_);
-        base_type::restrictToSubarray(start, end);
-    }
-
-    // ptr access
-    reference operator*()
-    {
-        return *pointer_;
-    }
-
-    const_reference operator*() const
-    {
-        return *pointer_;
-    }
-
-    pointer operator->()
-    {
-        return pointer_;
-    }
-
-    const_pointer operator->() const
-    {
-        return pointer_;
-    }
-
-    pointer ptr()
-    {
-        return pointer_;
-    }
-
-    const_pointer ptr() const
-    {
-        return pointer_;
-    }
-
-    shape_type const & strides() const
-    {
-        return strides_;
-    }
-
-    pointer pointer_;
-    shape_type strides_;
-};
-
+/********************************************************/
+/*                                                      */
+/*               CoupledScanOrderIterator<N>            */
+/*                                                      */
+/********************************************************/
 
-template <int N>
-class CoupledHandle<TinyVector<MultiArrayIndex, N>, void>
+template <class Iterator>
+class CoupledDimensionProxy
+: public Iterator
 {
-public:
-    static const int index = 0;                   // index of this member of the chain
-    static const unsigned int dimensions = N;
-
-    typedef typename MultiArrayShape<N>::type   value_type;
-    typedef value_type const *                  pointer;
-    typedef value_type const *                  const_pointer;
-    typedef value_type const &                  reference;
-    typedef value_type const &                  const_reference;
-    typedef value_type                          shape_type;
-    typedef CoupledHandle<value_type, void>     self_type;
-
-    CoupledHandle()
-    : point_(),
-      shape_(),
-      scanOrderIndex_()
-    {}
-
-    CoupledHandle(value_type const & shape)
-    : point_(),
-      shape_(shape),
-      scanOrderIndex_()
-    {}
-
-    CoupledHandle(typename MultiArrayShape<N+1>::type const & shape)
-    : point_(),
-      shape_(shape.begin()),
-      scanOrderIndex_()
-    {}
-
-    template<int DIMENSION>
-    inline void increment() 
-    {
-        ++point_[DIMENSION];
-    }
-    
-    template<int DIMENSION>
-    inline void decrement() 
-    {
-        --point_[DIMENSION];
-    }
-    
-    // TODO: test if making the above a default case of the this hurts performance
-    template<int DIMENSION>
-    inline void increment(MultiArrayIndex offset) 
-    {
-        point_[DIMENSION] += offset;
+  public:
+    typedef typename Iterator::value_type          value_type;
+    typedef typename Iterator::difference_type     difference_type;
+    typedef typename Iterator::reference           reference;
+    typedef typename Iterator::const_reference     const_reference;
+    typedef typename Iterator::pointer             pointer;
+    typedef CoupledDimensionProxy                  iterator;
+    typedef std::random_access_iterator_tag        iterator_category;
+    
+    static const int dimension = Iterator::dimension;
+ 
+    CoupledDimensionProxy & operator++()
+    {
+        this->incDim(dimension);
+        return *this;
     }
     
-    template<int DIMENSION>
-    inline void decrement(MultiArrayIndex offset) 
+    CoupledDimensionProxy operator++(int)
     {
-        point_[DIMENSION] -= offset;
+        CoupledDimensionProxy ret(*this);
+        this->incDim(dimension);
+        return ret;
     }
     
-    void restrictToSubarray(shape_type const & start, shape_type const & end)
-    {
-        point_ = shape_type();
-        shape_ = end - start;
-        scanOrderIndex_ = 0;
-    }
-
-    inline void incrementIndex() 
+    CoupledDimensionProxy & operator--()
     {
-        ++scanOrderIndex_;
+        this->decDim(dimension);
+        return *this;
     }
     
-    inline void decrementIndex() 
+    CoupledDimensionProxy operator--(int)
     {
-        --scanOrderIndex_;
+        CoupledDimensionProxy ret(*this);
+        this->decDim(dimension);
+        return ret;
     }
     
-    inline void incrementIndex(MultiArrayIndex offset) 
+    CoupledDimensionProxy & operator+=(MultiArrayIndex d)
     {
-        scanOrderIndex_ += offset;
+        this->addDim(dimension, d);
+        return *this;
     }
     
-    inline void decrementIndex(MultiArrayIndex offset) 
+    CoupledDimensionProxy & operator-=(MultiArrayIndex d)
     {
-        scanOrderIndex_ -= offset;
-    }
-
-    // access
-    MultiArrayIndex scanOrderIndex() const
-    {
-        return scanOrderIndex_;
+        this->addDim(dimension, -d);
+        return *this;
     }
     
-    // access
-    const_reference point() const
+    value_type operator[](MultiArrayIndex d) const
     {
-        return point_;
+        return *(CoupledDimensionProxy(*this) += d);
     }
     
-    // access
-    const_reference shape() const
-    {
-        return shape_;
-    }
-
-    const_reference operator*() const
-    {
-        return point_;
-    }
-
-    const_pointer operator->() const
+    CoupledDimensionProxy & operator=(MultiArrayIndex d)
     {
-        return &point_;
-    }
-
-    const_pointer ptr() const
-    {
-        return &point_;
+        this->setDim(dimension, d);
+        return *this;
     }
     
-    unsigned int borderType() const
+    bool operator==(MultiArrayIndex d) const
     {
-        return detail::BorderTypeImpl<N>::exec(point_, shape_);
+        return this->point(dimension) == d;
     }
-
-    value_type point_, shape_;
-    MultiArrayIndex scanOrderIndex_;
-};
-
-template <unsigned int N, class T, class StrideTag>
-class MultiArrayView<N, Multiband<T>, StrideTag>
-: public MultiArrayView<N, T, StrideTag>
-{
-  public:
-    MultiArrayView(MultiArrayView<N, T, StrideTag> const & v)
-    : MultiArrayView<N, T, StrideTag>(v)
-    {}
-};
-
-template <class T, class NEXT>
-class CoupledHandle<Multiband<T>, NEXT>
-: public NEXT
-{
-public:
-    typedef NEXT                                  base_type;
-    typedef CoupledHandle<Multiband<T>, NEXT>     self_type;
     
-    static const int index =                      NEXT::index + 1;    // index of this member of the chain
-    static const unsigned int dimensions =        NEXT::dimensions;
-
-    typedef MultiArrayView<1, T, StridedArrayTag> value_type;
-    typedef value_type *                          pointer;
-    typedef value_type const *                    const_pointer;
-    typedef value_type &                          reference;
-    typedef value_type const &                    const_reference;
-    typedef typename base_type::shape_type        shape_type;
-
-    CoupledHandle()
-    : base_type(),
-      view_(), 
-      strides_()
-    {}
-
-    CoupledHandle(const_reference p, shape_type const & strides, NEXT const & next)
-    : base_type(next),
-      view_(p), 
-      strides_(strides)
-    {}
-
-    template <class Stride>
-    CoupledHandle(MultiArrayView<dimensions+1, Multiband<T>, Stride> const & v, NEXT const & next)
-    : base_type(next),
-      view_(v.bindInner(shape_type())), 
-      strides_(v.bindOuter(0).stride())
-    {
-        vigra_precondition(v.bindOuter(0).shape() == this->shape(), "createCoupledIterator(): shape mismatch.");
-    }
-
-    template<int DIMENSION>
-    inline void increment() 
+    bool operator!=(MultiArrayIndex d) const
     {
-        view_.unsafePtr() += strides_[DIMENSION];
-        base_type::template increment<DIMENSION>();
+        return this->point(dimension) != d;
     }
     
-    template<int DIMENSION>
-    inline void decrement() 
+    bool operator<(MultiArrayIndex d) const
     {
-        view_.unsafePtr() -= strides_[DIMENSION];
-        base_type::template decrement<DIMENSION>();
+        return this->point(dimension) < d;
     }
     
-    // TODO: test if making the above a default case of the this hurts performance
-    template<int DIMENSION>
-    inline void increment(MultiArrayIndex offset) 
+    bool operator<=(MultiArrayIndex d) const
     {
-        view_.unsafePtr() += offset*strides_[DIMENSION];
-        base_type::template increment<DIMENSION>(offset);
+        return this->point(dimension) <= d;
     }
     
-    template<int DIMENSION>
-    inline void decrement(MultiArrayIndex offset) 
+    bool operator>(MultiArrayIndex d) const
     {
-        view_.unsafePtr() -= offset*strides_[DIMENSION];
-        base_type::template decrement<DIMENSION>(offset);
+        return this->point(dimension) > d;
     }
     
-    void restrictToSubarray(shape_type const & start, shape_type const & end)
-    {
-        view_.unsafePtr() += dot(start, strides_);
-        base_type::restrictToSubarray(start, end);
-    }
-
-    // ptr access
-    reference operator*()
+    bool operator>=(MultiArrayIndex d) const
     {
-        return view_;
+        return this->point(dimension) >= d;
     }
-
-    const_reference operator*() const
-    {
-        return view_;
-    }
-
-    pointer operator->()
-    {
-        return &view_;
-    }
-
-    const_pointer operator->() const
-    {
-        return &view_;
-    }
-
-    pointer ptr()
-    {
-        return &view_;
-    }
-
-    const_pointer ptr() const
-    {
-        return &view_;
-    }
-
-    shape_type const & strides() const
-    {
-        return strides_;
-    }
-
-    value_type view_;
-    shape_type strides_;
 };
 
-template <unsigned TARGET_INDEX>
-struct Error__CoupledHandle_index_out_of_range;
-
-namespace detail {
-
-template <unsigned TARGET_INDEX, class Handle, bool isValid, unsigned int INDEX=Handle::index>
-struct CoupledHandleCastImpl
-{
-    typedef typename CoupledHandleCastImpl<TARGET_INDEX, typename Handle::base_type, isValid>::type type;
-};
-
-template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX>
-struct CoupledHandleCastImpl<TARGET_INDEX, Handle, false, INDEX>
-{
-    typedef Error__CoupledHandle_index_out_of_range<TARGET_INDEX> type;
-};
-
-template <unsigned TARGET_INDEX, class Handle>
-struct CoupledHandleCastImpl<TARGET_INDEX, Handle, true, TARGET_INDEX>
-{
-    typedef Handle type;
-};
-
-} // namespace detail
-
-template <unsigned TARGET_INDEX, class Handle, unsigned int INDEX=Handle::index>
-struct CoupledHandleCast
-: public detail::CoupledHandleCastImpl<TARGET_INDEX, Handle, (TARGET_INDEX <= INDEX), INDEX>
-{};
-
-template <unsigned int TARGET_INDEX, class Handle>
-typename CoupledHandleCast<TARGET_INDEX, Handle>::type &
-cast(Handle & handle)
-{
-    return handle;
-};
-
-template <unsigned int TARGET_INDEX, class Handle>
-typename CoupledHandleCast<TARGET_INDEX, Handle>::type const &
-cast(Handle const & handle)
-{
-    return handle;
-};
-
-  /** Returns reference to the element in the band of the handle with index TARGET_INDEX.
-   */
-template <unsigned int TARGET_INDEX, class Handle>
-typename CoupledHandleCast<TARGET_INDEX, Handle>::type::reference
-get(Handle & handle)
-{
-    return *cast<TARGET_INDEX>(handle);
-};
-
-  /** Returns a constant reference to the element in the band of the handle with index TARGET_INDEX.
-   */
-template <unsigned int TARGET_INDEX, class Handle>
-typename CoupledHandleCast<TARGET_INDEX, Handle>::type::const_reference
-get(Handle const & handle)
-{
-    return *cast<TARGET_INDEX>(handle);
-};
-
-/********************************************************/
-/*                                                      */
-/*               CoupledScanOrderIterator<N>            */
-/*                                                      */
-/********************************************************/
-
 /** \brief Iterate over multiple images simultaneously in scan order. 
 
     The value type of this iterator is an instance of the handle class CoupledHandle. This allows to iterate over multiple arrays simultaneously. The coordinates can be accessed as a special band (index 0) in the handle. The scan-order is defined such that dimensions are iterated from front to back (first to last).
@@ -521,19 +187,18 @@ get(Handle const & handle)
 */
 
 template <unsigned int N,
-          class HANDLES=CoupledHandle<TinyVector<MultiArrayIndex, N>, void>,
-          int DIMENSION = N-1>
+          class HANDLES,
+          int DIMENSION>  // NOTE: default template arguments are defined in multi_fwd.hxx
 class CoupledScanOrderIterator
 #ifndef DOXYGEN  // doxygen doesn't understand this inheritance
-: protected CoupledScanOrderIterator<N, HANDLES, DIMENSION-1>
+: public CoupledScanOrderIterator<N, HANDLES, DIMENSION-1>
 #endif
 {
     typedef CoupledScanOrderIterator<N, HANDLES, DIMENSION-1> base_type;
-    static const int dimension = DIMENSION;
 
   public:
-
-    typedef typename MultiArrayShape<dimension+1>::type        shape_type;
+     static const int dimension = DIMENSION;
+ 
     typedef MultiArrayIndex                   difference_type;
     typedef CoupledScanOrderIterator          iterator;
     typedef std::random_access_iterator_tag   iterator_category;
@@ -546,26 +211,22 @@ class CoupledScanOrderIterator
     typedef HANDLES value_type;
 #endif
 
+    typedef typename base_type::shape_type      shape_type;
     typedef typename base_type::reference       reference;
     typedef typename base_type::const_reference const_reference; // FIXME: do we need both?
     typedef typename base_type::pointer         pointer;
+    typedef CoupledDimensionProxy<iterator>     dimension_proxy;
 
     explicit CoupledScanOrderIterator(value_type const & handles = value_type())
     : base_type(handles)
     {}
 
-    value_type operator[](MultiArrayIndex i) const
-    {
-        return *(CoupledScanOrderIterator(*this) += i);
-    }
-
     CoupledScanOrderIterator & operator++()
     {
         base_type::operator++();
         if(this->point()[dimension-1] == this->shape()[dimension-1])
         {
-            base_type::reset();
-            this->handles_.template increment<dimension>();
+            resetAndIncrement();
         }
         return *this;
     }
@@ -579,19 +240,13 @@ class CoupledScanOrderIterator
 
     CoupledScanOrderIterator & operator+=(MultiArrayIndex i)
     {
-        // FIXME: this looks very expensive
-        shape_type coordOffset;
-        detail::ScanOrderToCoordinate<N>::exec(i+scanOrderIndex(), this->shape(), coordOffset);
-        coordOffset -= point();
-        moveRelative(coordOffset);
-        this->handles_.scanOrderIndex_ += i;
+        base_type::operator+=(i);
         return *this;
     }
 
     CoupledScanOrderIterator & operator+=(const shape_type &coordOffset)
     {
-        moveRelative(coordOffset);
-        this->handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>::exec(this->shape(), coordOffset);
+        base_type::operator+=(coordOffset);
         return *this;
     }
 
@@ -600,8 +255,7 @@ class CoupledScanOrderIterator
         base_type::operator--();
         if(this->point()[dimension-1] == -1)
         {
-            base_type::inverseReset();
-            this->handles_.template decrement<dimension>();
+            resetAndDecrement();
         }
         return *this;
     }
@@ -623,8 +277,8 @@ class CoupledScanOrderIterator
         return operator+=(-coordOffset);
     }
 
-    /** Returns CoupledScanOrderIterator pointing beyond the last element.
-    */
+        /** Returns CoupledScanOrderIterator pointing beyond the last element.
+        */
     CoupledScanOrderIterator getEndIterator() const
     {
         return operator+(prod(this->shape()) - this->scanOrderIndex());
@@ -655,63 +309,23 @@ class CoupledScanOrderIterator
         return base_type::operator-(r);
     }
 
-    bool operator==(CoupledScanOrderIterator const & r) const
-    {
-        return base_type::operator==(r);
-    }
-
-    bool operator!=(CoupledScanOrderIterator const & r) const
-    {
-        return base_type::operator!=(r);
-    }
-
-    bool operator<(CoupledScanOrderIterator const & r) const
-    {
-        return base_type::operator<(r);
-    }
-
-    bool operator<=(CoupledScanOrderIterator const & r) const
+    CoupledScanOrderIterator & 
+    restrictToSubarray(shape_type const & start, shape_type const & end)
     {
-        return base_type::operator<=(r);
-    }
-
-    bool operator>(CoupledScanOrderIterator const & r) const
-    {
-        return base_type::operator>(r);
-    }
-
-    bool operator>=(CoupledScanOrderIterator const & r) const
-    {
-        return base_type::operator>=(r);
-    }
-
-    CoupledScanOrderIterator & restrictToSubarray(shape_type const & start, shape_type const & end)
-    {
-        this->operator+=(-point());
-        this->handles_.restrictToSubarray(start, end);
+        base_type::restrictToSubarray(start, end);
         return *this;
     }
 
-    using base_type::operator*;
-    using base_type::point;
-    using base_type::shape;
-    using base_type::scanOrderIndex;
-    using base_type::atBorder;
-    using base_type::borderType;
-    using base_type::get;
-    using base_type::isValid;
-    using base_type::atEnd;
-
 #ifdef DOXYGEN
   
-    /** Returns reference to the element in the band with index TARGET_INDEX.
-    */
+        /** Returns reference to the element in the band with index TARGET_INDEX.
+        */
     template<unsigned int TARGET_INDEX> 
     typename CoupledHandleCast<TARGET_INDEX, value_type>::type::reference
     get();
 
-    /** Returns constant reference to the element in the band with index TARGET_INDEX.
-    */
+        /** Returns constant reference to the element in the band with index TARGET_INDEX.
+        */
     template<unsigned int TARGET_INDEX> 
     typename CoupledHandleCast<TARGET_INDEX, value_type>::type::const_reference
     get() const;
@@ -719,6 +333,11 @@ class CoupledScanOrderIterator
 #endif
 
   protected:
+        // placing these functions out-of-line prevents MSVC
+        // from stupid optimizations
+    void resetAndIncrement();
+    void resetAndDecrement();
+
     void reset()
     {
         this->handles_.template decrement<dimension>(this->shape()[dimension]);
@@ -728,36 +347,106 @@ class CoupledScanOrderIterator
     {
         this->handles_.template increment<dimension>(this->shape()[dimension]);
     }
-
-    void moveRelative(typename value_type::shape_type const & coordOffset)
-    {
-        base_type::moveRelative(coordOffset);
-        this->handles_.template increment<dimension>(coordOffset[dimension]);
-    }
 };
 
+template <unsigned int N, class HANDLES, int DIMENSION>
+void CoupledScanOrderIterator<N, HANDLES, DIMENSION>::resetAndIncrement()
+{
+    base_type::reset();
+    this->handles_.template increment<dimension>();
+}
 
+template <unsigned int N, class HANDLES, int DIMENSION>
+void CoupledScanOrderIterator<N, HANDLES, DIMENSION>::resetAndDecrement()
+{
+    base_type::inverseReset();
+    this->handles_.template decrement<dimension>();
+}
 
 template <unsigned int N, class HANDLES>
 class CoupledScanOrderIterator<N, HANDLES, 0>
 {
-    static const int dimension = 0;
-
   public:
 
+    static const int dimension = 0;
+
     typedef CoupledScanOrderIterator<N, HANDLES, 0>  self_type;
     typedef HANDLES                                  value_type;
     typedef MultiArrayIndex                          difference_type;
     typedef value_type &                             reference;
     typedef value_type const &                       const_reference; 
     typedef value_type *                             pointer;
-    typedef typename MultiArrayShape<1>::type        shape_type;
+    typedef typename MultiArrayShape<N>::type        shape_type;
     typedef CoupledScanOrderIterator                 iterator;
     typedef std::random_access_iterator_tag          iterator_category;
-
+    typedef CoupledDimensionProxy<iterator>          dimension_proxy;
+    
+    template <unsigned int TARGET_INDEX>
+    struct Reference
+    {
+        typedef typename CoupledHandleCast<TARGET_INDEX, HANDLES>::reference type;
+    };
+    
+    template <unsigned int TARGET_INDEX>
+    struct ConstReference
+    {
+        typedef typename CoupledHandleCast<TARGET_INDEX, HANDLES>::const_reference type;
+    };
+    
     explicit CoupledScanOrderIterator(value_type const & handles = value_type())
-    : handles_(handles)
+    : handles_(handles),
+      strides_(detail::defaultStride(handles_.shape()))
     {}
+    
+    template <unsigned int DIM>
+    typename CoupledScanOrderIterator<N, HANDLES, DIM>::dimension_proxy & 
+    dim()
+    {
+        typedef CoupledScanOrderIterator<N, HANDLES, DIM> Iter;
+        typedef typename Iter::dimension_proxy Proxy;
+        return static_cast<Proxy &>(static_cast<Iter &>(*this));
+    }
+    
+    template <unsigned int DIM>
+    typename CoupledScanOrderIterator<N, HANDLES, DIM>::dimension_proxy const & 
+    dim() const
+    {
+        typedef CoupledScanOrderIterator<N, HANDLES, DIM> Iter;
+        typedef typename Iter::dimension_proxy Proxy;
+        return static_cast<Proxy const &>(static_cast<Iter const &>(*this));
+    }
+
+    void incDim(int dim)
+    {
+        handles_.incDim(dim);
+        handles_.incrementIndex(strides_[dim]);
+    }
+
+    void decDim(int dim)
+    {
+        handles_.decDim(dim);
+        handles_.decrementIndex(strides_[dim]);
+    }
+
+    void addDim(int dim, MultiArrayIndex d)
+    {
+        handles_.addDim(dim, d);
+        handles_.incrementIndex(d*strides_[dim]);
+    }
+
+    void setDim(int dim, MultiArrayIndex d)
+    {
+        d -= point(dim);
+        handles_.addDim(dim, d);
+        handles_.incrementIndex(d*strides_[dim]);
+    }
+
+    void resetDim(int dim)
+    {
+        MultiArrayIndex d = -point(dim);
+        handles_.addDim(dim, d);
+        handles_.incrementIndex(d*strides_[dim]);
+    }
 
     CoupledScanOrderIterator & operator++()
     {
@@ -775,25 +464,22 @@ class CoupledScanOrderIterator<N, HANDLES, 0>
 
     CoupledScanOrderIterator & operator+=(MultiArrayIndex i)
     {
+        // FIXME: this looks very expensive
         shape_type coordOffset;
-        detail::ScanOrderToCoordinate<N>::exec(i, shape(), coordOffset);
-        moveRelative(coordOffset);
+        detail::ScanOrderToCoordinate<N>::exec(i+scanOrderIndex(), shape(), coordOffset);
+        coordOffset -= point();
+        handles_.add(coordOffset);
         handles_.scanOrderIndex_ += i;
         return *this;
     }
 
     CoupledScanOrderIterator & operator+=(const shape_type &coordOffset)
     {
-        moveRelative(coordOffset);
+        handles_.add(coordOffset);
         handles_.scanOrderIndex_ += detail::CoordinateToScanOrder<N>::exec(shape(), coordOffset);
         return *this;
     }
 
-    CoupledScanOrderIterator & operator-=(const shape_type &coordOffset)
-    {
-        return operator+=(-coordOffset);
-    }
-
     CoupledScanOrderIterator & operator--()
     {
         handles_.template decrement<dimension>();
@@ -813,11 +499,21 @@ class CoupledScanOrderIterator<N, HANDLES, 0>
         return operator+=(-i);
     }
 
+    CoupledScanOrderIterator & operator-=(const shape_type &coordOffset)
+    {
+        return operator+=(-coordOffset);
+    }
+
     value_type operator[](MultiArrayIndex i) const
     {
         return *(CoupledScanOrderIterator(*this) += i);
     }
 
+    value_type operator[](const shape_type& coordOffset) const
+    {
+        return *(CoupledScanOrderIterator(*this) += coordOffset);
+    }
+
     CoupledScanOrderIterator
     operator+(MultiArrayIndex d) const
     {
@@ -891,16 +587,36 @@ class CoupledScanOrderIterator<N, HANDLES, 0>
         return handles_.scanOrderIndex();
     }
 
-    typename value_type::shape_type const & point() const
+    shape_type const & coord() const
+    {
+        return handles_.point();
+    }
+
+    MultiArrayIndex coord(unsigned int dim) const
+    {
+        return coord()[dim];
+    }
+
+    shape_type const & point() const
     {
         return handles_.point();
     }
 
-    typename value_type::shape_type const & shape() const
+    MultiArrayIndex point(unsigned int dim) const
+    {
+        return point()[dim];
+    }
+
+    shape_type const & shape() const
     {
         return handles_.shape();
     }
 
+    MultiArrayIndex shape(unsigned int dim) const
+    {
+        return handles_.shape()[dim];
+    }
+
     reference operator*()
     {
         return handles_;
@@ -911,10 +627,12 @@ class CoupledScanOrderIterator<N, HANDLES, 0>
         return handles_;
     }
 
-    CoupledScanOrderIterator & restrictToSubarray(shape_type const & start, shape_type const & end)
+    CoupledScanOrderIterator & 
+    restrictToSubarray(shape_type const & start, shape_type const & end)
     {
         operator+=(-point());
         handles_.restrictToSubarray(start, end);
+        strides_ = detail::defaultStride(shape());
         return *this;
     }
 
@@ -934,18 +652,28 @@ class CoupledScanOrderIterator<N, HANDLES, 0>
     }
 
     template<unsigned int TARGET_INDEX> 
-    typename CoupledHandleCast<TARGET_INDEX, value_type>::type::reference
+    typename Reference<TARGET_INDEX>::type
     get() 
     {
         return vigra::get<TARGET_INDEX>(handles_);
     }
 
     template<unsigned int TARGET_INDEX> 
-    typename CoupledHandleCast<TARGET_INDEX, value_type>::type::const_reference
+    typename ConstReference<TARGET_INDEX>::type
     get() const
     {
         return vigra::get<TARGET_INDEX>(handles_);
     }
+    
+    reference handles()
+    {
+        return handles_;
+    }
+    
+    const_reference handles() const
+    {
+        return handles_;
+    }
 
   protected:
     void reset()
@@ -957,73 +685,30 @@ class CoupledScanOrderIterator<N, HANDLES, 0>
     {
         handles_.template increment<dimension>(shape()[dimension]);
     }
-
-    void moveRelative(typename value_type::shape_type const & coordOffset)
-    {
-        handles_.template increment<dimension>(coordOffset[dimension]);
-    }   
     
     value_type handles_;
+    shape_type strides_;
 };
 
-
-template <unsigned int N, class List>
-struct ComposeCoupledHandle;
-
-template <unsigned int N, class T, class TAIL>
-struct ComposeCoupledHandle<N, TypeList<T, TAIL> >
-{
-    typedef typename ComposeCoupledHandle<N, TAIL>::type  BaseType;
-    typedef typename MultiArrayShape<N>::type             shape_type;
-    typedef CoupledHandle<T, BaseType>                    type;
-    
-    template <class S>
-    type exec(MultiArrayView<N, T, S> const & m, 
-              shape_type const & start, shape_type const & end,
-              BaseType const & base)
-    {
-        return type(m.subarray(start, end).data(), m.stride(), base);
-    }
-    
-    template <class S>
-    type exec(MultiArrayView<N, T, S> const & m, BaseType const & base)
-    {
-        return type(m.data(), m.stride(), base);
-    }
-};
-
-template <unsigned int N>
-struct ComposeCoupledHandle<N, void>
-{
-    typedef typename MultiArrayShape<N>::type  shape_type;
-    typedef CoupledHandle<shape_type, void>    type;
-    
-    type exec(shape_type const & shape)
-    {
-        return type(shape);
-    }
-    
-    type exec(shape_type const & start, shape_type const & end)
-    {
-        return type(end-start);
-    }
-};
-
-template <unsigned int N, class T1=void, class T2=void, class T3=void, class T4=void, class T5=void>
-struct CoupledHandleType
+template <unsigned int TARGET_INDEX, 
+          unsigned int N,
+          class HANDLES,
+          int DIM>
+typename CoupledScanOrderIterator<N, HANDLES, DIM>::template Reference<TARGET_INDEX>::type
+get(CoupledScanOrderIterator<N, HANDLES, DIM> & i)
 {
-    // reverse the order to get the desired index order
-    typedef typename MakeTypeList<T5, T4, T3, T2, T1>::type TypeList;
-    typedef typename ComposeCoupledHandle<N, TypeList>::type type;
-};
+    return vigra::get<TARGET_INDEX>(*i);
+}
 
-template <unsigned int N, class T1, class T2, class T3, class T4, class T5>
-struct CoupledHandleType<N, Multiband<T1>, T2, T3, T4, T5>
+template <unsigned int TARGET_INDEX, 
+          unsigned int N,
+          class HANDLES,
+          int DIM>
+typename CoupledScanOrderIterator<N, HANDLES, DIM>::template ConstReference<TARGET_INDEX>::type
+get(CoupledScanOrderIterator<N, HANDLES, DIM> const & i)
 {
-    // reverse the order to get the desired index order
-    typedef typename MakeTypeList<T5, T4, T3, T2, Multiband<T1> >::type TypeList;
-    typedef typename ComposeCoupledHandle<N-1, TypeList>::type type;
-};
+    return vigra::get<TARGET_INDEX>(*i);
+}
 
 /** Helper class to easliy get the type of a CoupledScanOrderIterator (and corresponding CoupledHandle) for up to five arrays of dimension N with element types T1,...,T5.
  */
@@ -1167,6 +852,18 @@ createCoupledIterator(MultiArrayView<N1, T1, S1> const & m1,
                         P0(m1.shape())))))));
 }
 
+template <unsigned int N, class A, class B>
+CoupledScanOrderIterator<N, typename ZipCoupledHandles<A, B>::type>
+zip(CoupledScanOrderIterator<N, A> const & a, CoupledScanOrderIterator<N, B> const & b)
+{
+    vigra_precondition(a.shape() == b.shape() && a.scanOrderIndex() == b.scanOrderIndex(),
+         "zip(CoupledScanOrderIterator): iterators must have identical shape and position.");
+         
+    typedef typename ZipCoupledHandles<A, B>::type Handle;
+    typedef CoupledScanOrderIterator<N, Handle> IteratorType;
+    return IteratorType(ZipCoupledHandles<A, B>::construct(*a, *b));
+}
+
 //@}
 
 } // namespace vigra
diff --git a/include/vigra/multi_labeling.hxx b/include/vigra/multi_labeling.hxx
index a74ca5e..7e7a90d 100644
--- a/include/vigra/multi_labeling.hxx
+++ b/include/vigra/multi_labeling.hxx
@@ -29,7 +29,7 @@
 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
-/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
 
@@ -39,18 +39,76 @@
 #include "multi_array.hxx"
 #include "multi_gridgraph.hxx"
 #include "union_find.hxx"
+#include "any.hxx"
 
 namespace vigra{
 
+namespace labeling_equality{
+
+struct Yes
+{
+    char d[100];
+};
+struct No
+{
+    char d[1];
+};
+
+template <size_t>
+struct SizeToType;
+template <>
+struct SizeToType<sizeof(Yes)>
+{
+    typedef VigraTrueType type;
+};
+template <>
+struct SizeToType<sizeof(No)>
+{
+    typedef VigraFalseType type;
+};
+
+template <class Equal>
+class TakesThreeArguments
+{
+public:
+    template <class T>
+    static Yes check(typename T::WithDiffTag*);
+    template <class T>
+    static No check(...);
+
+    typedef typename SizeToType<sizeof(check<Equal>(0))>::type type;
+    static const unsigned int value = type::asBool;
+};
+
+template <class Equal, class Data, class Shape>
+bool callEqualImpl(Equal& equal, const Data& u_data, const Data& v_data, const Shape& diff, VigraTrueType)
+{
+    return equal(u_data, v_data, diff);
+}
+template <class Equal, class Data, class Shape>
+bool callEqualImpl(Equal& equal, const Data& u_data, const Data& v_data, const Shape& diff, VigraFalseType)
+{
+    return equal(u_data, v_data);
+}
+
+template< class Equal, class Data, class Shape>
+bool callEqual(Equal& equal, const Data& u_data, const Data& v_data, const Shape& diff)
+{
+    return callEqualImpl(equal, u_data, v_data, diff, typename TakesThreeArguments<Equal>::type());
+}
+
+}
+
+
 /** \addtogroup Labeling
 */
 //@{
 
-namespace lemon_graph { 
+namespace lemon_graph {
 
 template <class Graph, class T1Map, class T2Map, class Equal>
 typename T2Map::value_type
-labelGraph(Graph const & g, 
+labelGraph(Graph const & g,
            T1Map const & data,
            T2Map & labels,
            Equal const & equal)
@@ -59,42 +117,88 @@ labelGraph(Graph const & g,
     typedef typename Graph::OutBackArcIt  neighbor_iterator;
     typedef typename T2Map::value_type    LabelType;
 
-    vigra::detail::UnionFindArray<LabelType>  regions;
+    vigra::UnionFindArray<LabelType>  regions;
 
     // pass 1: find connected components
-    for (graph_scanner node(g); node != INVALID; ++node) 
+    for (graph_scanner node(g); node != INVALID; ++node)
     {
         typename T1Map::value_type center = data[*node];
-        
+
         // define tentative label for current node
-        LabelType currentLabel = regions.nextFreeLabel();
-        
+        LabelType currentIndex = regions.nextFreeIndex();
+
         for (neighbor_iterator arc(g, node); arc != INVALID; ++arc)
         {
             // merge regions if colors are equal
             if(equal(center, data[g.target(*arc)]))
             {
-                LabelType neighborLabel = regions[labels[g.target(*arc)]];
-                currentLabel = regions.makeUnion(neighborLabel, currentLabel);
+                currentIndex = regions.makeUnion(labels[g.target(*arc)], currentIndex);
+            }
+        }
+        // set label of current node
+        labels[*node] = regions.finalizeIndex(currentIndex);
+    }
+
+    LabelType count = regions.makeContiguous();
+
+    // pass 2: make component labels contiguous
+    for (graph_scanner node(g); node != INVALID; ++node)
+    {
+        labels[*node] = regions.findLabel(labels[*node]);
+    }
+    return count;
+}
+
+template <unsigned int N, class DirectedTag, class T1Map, class T2Map, class Equal>
+typename T2Map::value_type
+labelGraph(GridGraph<N, DirectedTag> const & g,
+           T1Map const & data,
+           T2Map & labels,
+           Equal const & equal)
+{
+    typedef GridGraph<N, DirectedTag>     Graph;
+    typedef typename Graph::NodeIt        graph_scanner;
+    typedef typename Graph::OutBackArcIt  neighbor_iterator;
+    typedef typename T2Map::value_type    LabelType;
+    typedef typename Graph::shape_type    Shape;
+
+    vigra::UnionFindArray<LabelType>  regions;
+
+    // pass 1: find connected components
+    for (graph_scanner node(g); node != INVALID; ++node)
+    {
+        typename T1Map::value_type center = data[*node];
+
+        // define tentative label for current node
+        LabelType currentIndex = regions.nextFreeIndex();
+
+        for (neighbor_iterator arc(g, node); arc != INVALID; ++arc)
+        {
+            Shape diff = g.neighborOffset(arc.neighborIndex());
+            // merge regions if colors are equal
+            if(labeling_equality::callEqual(equal, center, data[g.target(*arc)], diff))
+            {
+                currentIndex = regions.makeUnion(labels[g.target(*arc)], currentIndex);
             }
         }
         // set label of current node
-        labels[*node] = regions.finalizeLabel(currentLabel);
+        labels[*node] = regions.finalizeIndex(currentIndex);
     }
-    
+
     LabelType count = regions.makeContiguous();
 
     // pass 2: make component labels contiguous
-    for (graph_scanner node(g); node != INVALID; ++node) 
+    for (graph_scanner node(g); node != INVALID; ++node)
     {
-        labels[*node] = regions[labels[*node]];
+        labels[*node] = regions.findLabel(labels[*node]);
     }
     return count;
 }
 
+
 template <class Graph, class T1Map, class T2Map, class Equal>
 typename T2Map::value_type
-labelGraphWithBackground(Graph const & g, 
+labelGraphWithBackground(Graph const & g,
                          T1Map const & data,
                          T2Map & labels,
                          typename T1Map::value_type backgroundValue,
@@ -104,48 +208,175 @@ labelGraphWithBackground(Graph const & g,
     typedef typename Graph::OutBackArcIt  neighbor_iterator;
     typedef typename T2Map::value_type    LabelType;
 
-    vigra::detail::UnionFindArray<LabelType>  regions;
+    vigra::UnionFindArray<LabelType>  regions;
 
     // pass 1: find connected components
-    for (graph_scanner node(g); node != INVALID; ++node) 
+    for (graph_scanner node(g); node != INVALID; ++node)
     {
         typename T1Map::value_type center = data[*node];
-        
+
         // background always gets label zero
         if(equal(center, backgroundValue))
         {
             labels[*node] = 0;
             continue;
         }
-        
+
         // define tentative label for current node
-        LabelType currentLabel = regions.nextFreeLabel();
-        
+        LabelType currentIndex = regions.nextFreeIndex();
+
         for (neighbor_iterator arc(g, node); arc != INVALID; ++arc)
         {
             // merge regions if colors are equal
             if(equal(center, data[g.target(*arc)]))
             {
-                LabelType neighborLabel = regions[labels[g.target(*arc)]];
-                currentLabel = regions.makeUnion(neighborLabel, currentLabel);
+                currentIndex = regions.makeUnion(labels[g.target(*arc)], currentIndex);
             }
         }
         // set label of current node
-        labels[*node] = regions.finalizeLabel(currentLabel);
+        labels[*node] = regions.finalizeIndex(currentIndex);
     }
-    
+
     LabelType count = regions.makeContiguous();
 
     // pass 2: make component labels contiguous
-    for (graph_scanner node(g); node != INVALID; ++node) 
+    for (graph_scanner node(g); node != INVALID; ++node)
     {
-        labels[*node] = regions[labels[*node]];
+        labels[*node] = regions.findLabel(labels[*node]);
     }
     return count;
 }
 
+template <unsigned int N, class DirectedTag, class T1Map, class T2Map, class Equal>
+typename T2Map::value_type
+labelGraphWithBackground(GridGraph<N, DirectedTag> const & g,
+                         T1Map const & data,
+                         T2Map & labels,
+                         typename T1Map::value_type backgroundValue,
+                         Equal const & equal)
+{
+    typedef GridGraph<N, DirectedTag>     Graph;
+    typedef typename Graph::NodeIt        graph_scanner;
+    typedef typename Graph::OutBackArcIt  neighbor_iterator;
+    typedef typename T2Map::value_type    LabelType;
+    typedef typename Graph::shape_type    Shape;
+
+    vigra::UnionFindArray<LabelType>  regions;
+
+    // pass 1: find connected components
+    for (graph_scanner node(g); node != INVALID; ++node)
+    {
+        typename T1Map::value_type center = data[*node];
+
+        // background always gets label zero
+        if(labeling_equality::callEqual(equal, center, backgroundValue, Shape()))
+        {
+            labels[*node] = 0;
+            continue;
+        }
+
+        // define tentative label for current node
+        LabelType currentIndex = regions.nextFreeIndex();
+
+        for (neighbor_iterator arc(g, node); arc != INVALID; ++arc)
+        {
+            // merge regions if colors are equal
+            Shape diff = g.neighborOffset(arc.neighborIndex());
+            if(labeling_equality::callEqual(equal, center, data[g.target(*arc)], diff))
+            {
+                currentIndex = regions.makeUnion(labels[g.target(*arc)], currentIndex);
+            }
+        }
+        // set label of current node
+        labels[*node] = regions.finalizeIndex(currentIndex);
+    }
+
+    LabelType count = regions.makeContiguous();
+
+    // pass 2: make component labels contiguous
+    for (graph_scanner node(g); node != INVALID; ++node)
+    {
+        labels[*node] = regions.findLabel(labels[*node]);
+    }
+    return count;
+}
+
+
 } // namespace lemon_graph
 
+    /** \brief Option object for labelMultiArray().
+    */
+class LabelOptions
+{
+    Any background_value_;
+    NeighborhoodType neighborhood_;
+
+  public:
+
+        /** \brief Set default options.
+        */
+    LabelOptions()
+    : neighborhood_(DirectNeighborhood)
+    {}
+
+        /** \brief Choose direct or indirect neighborhood.
+
+            Default: <tt>DirectNeighborhood</tt>
+        */
+    LabelOptions & neighborhood(NeighborhoodType n)
+    {
+        neighborhood_ = n;
+        return *this;
+    }
+
+        /** \brief Query the neighborhood type (direct or indirect).
+        */
+    NeighborhoodType getNeighborhood() const
+    {
+        return neighborhood_;
+    }
+
+        /** \brief Set background value.
+
+            If specified, labelMultiArray() will internally call
+            labelMultiArrayWithBackground() with the given value
+            considered as background and thus ignored. If no
+            background value is set, the array gets labeled completely.
+            Note that the type <tt>T</tt> must correspond to the element
+            type of the data array to be labeled.
+
+            Default: don't ignore any value.
+        */
+    template <class T>
+    LabelOptions & ignoreBackgroundValue(T const & t)
+    {
+        background_value_ = t;
+        return *this;
+    }
+
+        /** \brief Check if some background value is to be ignored.
+        */
+    bool hasBackgroundValue() const
+    {
+        return bool(background_value_);
+    }
+
+        /** \brief Get the background value to be ignored.
+
+            Throws an exception if the stored background value type
+            is incompatible to the data array's value type.
+        */
+    template <class T>
+    T getBackgroundValue() const
+    {
+        if(background_value_.empty())
+            return T();
+        vigra_precondition(background_value_.template is_readable<T>(),
+            "LabelOptions::getBackgroundValue<T>(): stored background value is not convertible to T.");
+        return background_value_.template read<T>();
+    }
+};
+
 /********************************************************/
 /*                                                      */
 /*                     labelMultiArray                  */
@@ -154,39 +385,55 @@ labelGraphWithBackground(Graph const & g,
 
 /** \brief Find the connected components of a MultiArray with arbitrary many dimensions.
 
+    See also \ref labelMultiArrayBlockwise() for a parallel version of this algorithm.
+
+    By specifying a background value in the \ref vigra::LabelOptions, this function
+    can also realize the behavior of \ref labelMultiArrayWithBackground().
+
     <b> Declaration:</b>
 
     \code
     namespace vigra {
 
+        // specify parameters directly
         template <unsigned int N, class T, class S1,
                                   class Label, class S2,
                   class EqualityFunctor = std::equal_to<T> >
-        Label 
+        Label
         labelMultiArray(MultiArrayView<N, T, S1> const & data,
                         MultiArrayView<N, Label, S2> labels,
                         NeighborhoodType neighborhood = DirectNeighborhood,
                         EqualityFunctor equal = std::equal_to<T>())
 
+        // specify parameters via LabelOptions
+        template <unsigned int N, class T, class S1,
+                                  class Label, class S2,
+                  class Equal = std::equal<T> >
+        Label
+        labelMultiArray(MultiArrayView<N, T, S1> const & data,
+                        MultiArrayView<N, Label, S2> labels,
+                        LabelOptions const & options,
+                        Equal equal = std::equal<T>());
+
     }
     \endcode
 
-    Connected components are defined as regions with uniform values. 
-    Thus, the value type <tt>T</tt> of the input array \a data either 
+    Connected components are defined as regions with uniform values.
+    Thus, the value type <tt>T</tt> of the input array \a data either
     must be equality comparable, or an EqualityFunctor must be
-    provided that realizes the desired predicate. The destination 
-    array's value type <tt>Label</tt> should be large enough to hold 
-    the labels without overflow. Region numbers will form a consecutive 
-    sequence starting at <b>one</b> and ending with the region number 
+    provided that realizes the desired predicate. The destination
+    array's value type <tt>Label</tt> should be large enough to hold
+    the labels without overflow. Region numbers will form a consecutive
+    sequence starting at <b>one</b> and ending with the region number
     returned by the function (inclusive).
-    
+
     Argument \a neighborhood specifies the type of connectivity used. It can
     take the values <tt>DirectNeighborhood</tt> (which corresponds to
     4-neighborhood in 2D and 6-neighborhood in 3D, default) or
     <tt>IndirectNeighborhood</tt> (which corresponds to
     8-neighborhood in 2D and 26-neighborhood in 3D).
 
-    Return:  the number of regions found (= highest region label, because labeling starts at 1)
+    Return:  the highest region label used
 
     <b> Usage:</b>
 
@@ -196,12 +443,18 @@ labelGraphWithBackground(Graph const & g,
     \code
     MultiArray<3,int> src(Shape3(w,h,d));
     MultiArray<3,int> dest(Shape3(w,h,d));
-    
+
     // find 6-connected regions
     int max_region_label = labelMultiArray(src, dest);
 
     // find 26-connected regions
     max_region_label = labelMultiArray(src, dest, IndirectNeighborhood);
+
+    // find 6-connected regions, ignore the background value 0
+    // (i.e. call labelMultiArrayWithBackground() internally)
+    max_region_label = labelMultiArray(src, dest,
+                                       LabelOptions().neighborhood(DirectNeighborhood)
+                                                     .ignoreBackgroundValue(0));
     \endcode
 
     <b> Required Interface:</b>
@@ -219,7 +472,7 @@ doxygen_overloaded_function(template <...> unsigned int labelMultiArray)
 template <unsigned int N, class T, class S1,
                           class Label, class S2,
           class Equal>
-inline Label 
+inline Label
 labelMultiArray(MultiArrayView<N, T, S1> const & data,
                 MultiArrayView<N, Label, S2> labels,
                 NeighborhoodType neighborhood,
@@ -227,14 +480,14 @@ labelMultiArray(MultiArrayView<N, T, S1> const & data,
 {
     vigra_precondition(data.shape() == labels.shape(),
         "labelMultiArray(): shape mismatch between input and output.");
-        
+
     GridGraph<N, undirected_tag> graph(data.shape(), neighborhood);
     return lemon_graph::labelGraph(graph, data, labels, equal);
 }
 
 template <unsigned int N, class T, class S1,
                           class Label, class S2>
-inline Label 
+inline Label
 labelMultiArray(MultiArrayView<N, T, S1> const & data,
                 MultiArrayView<N, Label, S2> labels,
                 NeighborhoodType neighborhood = DirectNeighborhood)
@@ -242,6 +495,37 @@ labelMultiArray(MultiArrayView<N, T, S1> const & data,
     return labelMultiArray(data, labels, neighborhood, std::equal_to<T>());
 }
 
+template <unsigned int N, class T, class S1,
+                          class Label, class S2>
+inline Label
+labelMultiArray(MultiArrayView<N, T, S1> const & data,
+                MultiArrayView<N, Label, S2> labels,
+                LabelOptions const & options)
+{
+    if(options.hasBackgroundValue())
+        return labelMultiArrayWithBackground(data, labels, options.getNeighborhood(),
+                                             options.template getBackgroundValue<T>());
+    else
+        return labelMultiArray(data, labels, options.getNeighborhood());
+}
+
+template <unsigned int N, class T, class S1,
+                          class Label, class S2,
+          class Equal>
+inline Label
+labelMultiArray(MultiArrayView<N, T, S1> const & data,
+                MultiArrayView<N, Label, S2> labels,
+                LabelOptions const & options,
+                Equal equal)
+{
+    if(options.hasBackgroundValue())
+        return labelMultiArrayWithBackground(data, labels, options.getNeighborhood(),
+                                             options.template getBackgroundValue<T>(),
+                                             equal);
+    else
+        return labelMultiArray(data, labels, options.getNeighborhood(), equal);
+}
+
 /********************************************************/
 /*                                                      */
 /*           labelMultiArrayWithBackground              */
@@ -251,6 +535,11 @@ labelMultiArray(MultiArrayView<N, T, S1> const & data,
 /** \brief Find the connected components of a MultiArray with arbitrary many dimensions,
      excluding the background from labeling.
 
+    From a user's point of view, this function is no longer needed because
+    \ref labelMultiArray() can realizes the same behavior when an appropriate
+    background value is specified in its \ref vigra::LabelOptions. Similarly,
+    \ref labelMultiArrayBlockwise() implements a parallel version of this algorithm.
+
     <b> Declaration:</b>
 
     \code
@@ -259,7 +548,7 @@ labelMultiArray(MultiArrayView<N, T, S1> const & data,
         template <unsigned int N, class T, class S1,
                                   class Label, class S2
                   class Equal = std::equal<T> >
-        Label 
+        Label
         labelMultiArrayWithBackground(MultiArrayView<N, T, S1> const & data,
                                       MultiArrayView<N, Label, S2> labels,
                                       NeighborhoodType neighborhood = DirectNeighborhood,
@@ -269,16 +558,16 @@ labelMultiArray(MultiArrayView<N, T, S1> const & data,
     }
     \endcode
 
-    This function is the same as \ref labelMultiArray(), except for 
+    This function is the same as \ref labelMultiArray(), except for
     the additional parameter \a backgroundValue. Points in the input
-    array \a data with this value (which default to zero) are ignored 
-    during labeling, and  their output label is automatically set to 
-    zero. Region numbers will be a consecutive sequence starting at 
-    zero (when background was present) or at one (when no background 
-    was present) and ending with the region number returned by the 
+    array \a data with this value (which default to zero) are ignored
+    during labeling, and  their output label is automatically set to
+    zero. Region numbers will be a consecutive sequence starting at
+    zero (when background was present) or at one (when no background
+    was present) and ending with the region number returned by the
     function (inclusive).
 
-    Return: the number of non-background regions found (= highest region label, 
+    Return: the number of non-background regions found (= highest region label,
     because background has label 0)
 
     <b> Usage:</b>
@@ -289,7 +578,7 @@ labelMultiArray(MultiArrayView<N, T, S1> const & data,
     \code
     MultiArray<3, int> src(Shape3(w,h,d));
     MultiArray<3, int> dest(Shape3(w,h,d));
-    
+
     // find 6-connected regions, ignoring background value zero (the default)
     int max_region_label = labelMultiArrayWithBackground(src, dest);
 
@@ -312,7 +601,7 @@ doxygen_overloaded_function(template <...> unsigned int labelMultiArrayWithBackg
 template <unsigned int N, class T, class S1,
                           class Label, class S2,
           class Equal>
-inline Label 
+inline Label
 labelMultiArrayWithBackground(MultiArrayView<N, T, S1> const & data,
                               MultiArrayView<N, Label, S2> labels,
                               NeighborhoodType neighborhood,
@@ -321,14 +610,14 @@ labelMultiArrayWithBackground(MultiArrayView<N, T, S1> const & data,
 {
     vigra_precondition(data.shape() == labels.shape(),
         "labelMultiArrayWithBackground(): shape mismatch between input and output.");
-        
+
     GridGraph<N, undirected_tag> graph(data.shape(), neighborhood);
     return lemon_graph::labelGraphWithBackground(graph, data, labels, backgroundValue, equal);
 }
 
 template <unsigned int N, class T, class S1,
                           class Label, class S2>
-inline Label 
+inline Label
 labelMultiArrayWithBackground(MultiArrayView<N, T, S1> const & data,
                               MultiArrayView<N, Label, S2> labels,
                               NeighborhoodType neighborhood = DirectNeighborhood,
diff --git a/include/vigra/multi_localminmax.hxx b/include/vigra/multi_localminmax.hxx
index eddbab0..ebc8fe9 100644
--- a/include/vigra/multi_localminmax.hxx
+++ b/include/vigra/multi_localminmax.hxx
@@ -47,10 +47,31 @@
 
 namespace vigra {
 
+
+namespace detail_local_minima{
+    template<class G>
+    struct NodeAtBorder{
+        template<class NODE_ITER>
+        static bool atBorder(const NODE_ITER & node ){
+            return false;
+        }
+    };
+
+    template<unsigned int DIM,class DTAG>
+    struct NodeAtBorder< GridGraph<DIM,DTAG> >{
+        template<class NODE_ITER>
+        static bool atBorder(const NODE_ITER & node ){
+            return node.atBorder();
+        }
+    }; 
+
+};
+
+
 namespace boost_graph {
 
-  // Attempt without LValue propmaps, using only the free functions
-  // to access ReadablePropertyMap (input) and WritablePropertyMap (label)
+// Attempt without LValue propmaps, using only the free functions
+// to access ReadablePropertyMap (input) and WritablePropertyMap (label)
 template <class Graph, class T1Map, class T2Map, class Compare>
 unsigned int
 localMinMaxGraph(Graph const &g, 
@@ -119,11 +140,11 @@ localMinMaxGraph(Graph const &g,
 
         if (!compare(current, threshold))
             continue;
-          
-        if(!allowAtBorder && node.atBorder())
+        
+        if(!allowAtBorder && vigra::detail_local_minima::NodeAtBorder<Graph>::atBorder(node))
             continue;
         
-        neighbor_iterator arc(g, node);
+        neighbor_iterator arc(g, *node);
         for (; arc != INVALID; ++arc) 
             if (!compare(current, src[g.target(*arc)])) 
                 break;
@@ -137,6 +158,7 @@ localMinMaxGraph(Graph const &g,
     return count;
 }
 
+
 template <class Graph, class T1Map, class T2Map, class Compare, class Equal>
 unsigned int
 extendedLocalMinMaxGraph(Graph const &g, 
@@ -169,14 +191,14 @@ extendedLocalMinMaxGraph(Graph const &g,
         typename T1Map::value_type current = src[*node];
 
         if (!compare(current, threshold) ||
-            (!allowAtBorder && node.atBorder()))
+            (!allowAtBorder &&  vigra::detail_local_minima::NodeAtBorder<Graph>::atBorder(node) ))
         {
             isExtremum[label] = 0;
             --count;
             continue;
         }
         
-        for (neighbor_iterator arc(g, node); arc != INVALID; ++arc) 
+        for (neighbor_iterator arc(g, *node); arc != INVALID; ++arc) 
         {
             if (label != regions[g.target(*arc)] && compare(src[g.target(*arc)], current)) 
             {
diff --git a/include/vigra/multi_morphology.hxx b/include/vigra/multi_morphology.hxx
index 1ca747f..fa9302a 100644
--- a/include/vigra/multi_morphology.hxx
+++ b/include/vigra/multi_morphology.hxx
@@ -85,7 +85,7 @@ struct MultiBinaryMorphologyImpl
                                  : NumericTraits<DestType>::zero();
         transformMultiArray( tmpArray.traverser_begin(), shape, StandardValueAccessor<double>(), 
                              d, dest, 
-                             ifThenElse( Arg1() >= Param(radius2),
+                             ifThenElse( Arg1() > Param(radius2),
                                          Param(foreground), Param(background) ) );
     }
 };
diff --git a/include/vigra/multi_pointoperators.hxx b/include/vigra/multi_pointoperators.hxx
index e94debd..21b713c 100644
--- a/include/vigra/multi_pointoperators.hxx
+++ b/include/vigra/multi_pointoperators.hxx
@@ -235,6 +235,7 @@ initMultiArray(MultiArrayView<N, T, S> s, VALUETYPE const & v)
     pass arbitrary-dimensional array views:
     \code
     namespace vigra {
+            // init equal borders on all array sides
         template <unsigned int N, class T, class S, 
                   class VALUETYPE>
         void 
@@ -246,6 +247,15 @@ initMultiArray(MultiArrayView<N, T, S> s, VALUETYPE const & v)
         void 
         initMultiArrayBorder( MultiArrayView<N, T, S> array, 
                               MultiArrayIndex border_width, FUNCTOR const & v);
+        
+            // specify border width individually for all array sides
+        template <unsigned int N, class T, class S, 
+                  class VALUETYPE>
+        void 
+        initMultiArrayBorder( MultiArrayView<N, T, S> array, 
+                              typename MultiArrayShape<N>::type const & lower_border, 
+                              typename MultiArrayShape<N>::type const & upper_border, 
+                              VALUETYPE const & v);
     }
     \endcode
     
@@ -293,30 +303,41 @@ template <class Iterator, class Diff_type, class Accessor,
           class VALUETYPE>
 void
 initMultiArrayBorder(Iterator upperleft, Diff_type shape, Accessor a,
-                     MultiArrayIndex border_width, VALUETYPE const & v)
+                     Diff_type lower_border, Diff_type upper_border, 
+                     VALUETYPE const & v)
 {
-    Diff_type border(shape);
     for(unsigned int dim=0; dim<shape.size(); dim++)
     {
-        border[dim] = (border_width > shape[dim]) ? shape[dim] : border_width;
+        lower_border[dim] = (lower_border[dim] > shape[dim]) ? shape[dim] : lower_border[dim];
+        upper_border[dim] = (upper_border[dim] > shape[dim]) ? shape[dim] : upper_border[dim];
     }
 
     for(unsigned int dim=0; dim<shape.size(); dim++)
     {
-        Diff_type  start(shape),
+        Diff_type  start,
                    offset(shape);
-        start = start-shape;
-        offset[dim]=border[dim];
+        offset[dim] = lower_border[dim];
 
         initMultiArray(upperleft+start, offset, a, v);
  
-        start[dim]=shape[dim]-border[dim];
+        start[dim]  = shape[dim] - upper_border[dim];
+        offset[dim] = upper_border[dim];
         initMultiArray(upperleft+start, offset, a, v);
     }
 }
     
 template <class Iterator, class Diff_type, class Accessor, 
           class VALUETYPE>
+inline void
+initMultiArrayBorder(Iterator upperleft, Diff_type shape, Accessor a,
+                     MultiArrayIndex border_width, VALUETYPE const & v)
+{
+    initMultiArrayBorder(upperleft, shape, a,
+                         Diff_type(border_width), Diff_type(border_width), v);
+}
+    
+template <class Iterator, class Diff_type, class Accessor, 
+          class VALUETYPE>
 inline void 
 initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray, 
                       MultiArrayIndex border_width, VALUETYPE const & v)
@@ -324,6 +345,17 @@ initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray,
     initMultiArrayBorder(multiArray.first, multiArray.second, multiArray.third, border_width, v);
 }
 
+template <class Iterator, class Diff_type, class Accessor, 
+          class VALUETYPE>
+inline void 
+initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray, 
+                      Diff_type const & lower_border, Diff_type const & upper_border, 
+                      VALUETYPE const & v)
+{
+    initMultiArrayBorder(multiArray.first, multiArray.second, multiArray.third, 
+                         lower_border, upper_border, v);
+}
+
 template <unsigned int N, class T, class S, 
           class VALUETYPE>
 inline void 
@@ -333,6 +365,17 @@ initMultiArrayBorder( MultiArrayView<N, T, S> array,
     initMultiArrayBorder(destMultiArrayRange(array), border_width, v);
 }
 
+template <unsigned int N, class T, class S, 
+          class VALUETYPE>
+inline void 
+initMultiArrayBorder( MultiArrayView<N, T, S> array, 
+                      typename MultiArrayShape<N>::type const & lower_border, 
+                      typename MultiArrayShape<N>::type const & upper_border, 
+                      VALUETYPE const & v)
+{
+    initMultiArrayBorder(destMultiArrayRange(array), lower_border, upper_border, v);
+}
+
 /********************************************************/
 /*                                                      */
 /*                    copyMultiArray                    */
@@ -711,7 +754,7 @@ transformMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
 /** \brief Transform a multi-dimensional array with a unary function or functor.
 
     Note: The effect of this function can often be achieved in a simpler and
-    more readable way by means of \ref MultiMathModule "array experessions".
+    more readable way by means of \ref MultiMathModule "array expressions".
     
     This function can be applied in three modes:
     
@@ -983,7 +1026,7 @@ inline void
 transformMultiArray(MultiArrayView<N, T1, S1> const & source,
                     MultiArrayView<N, T2, S2> dest, Functor const & f)
 {
-    for(int k=0; k<N; ++k)
+    for(unsigned int k=0; k<N; ++k)
         vigra_precondition(source.shape(k) == dest.shape(k) || source.shape(k) == 1 || 1 == dest.shape(k),
             "transformMultiArray(): shape mismatch between input and output.");
 
@@ -1158,7 +1201,7 @@ combineTwoMultiArraysImpl(
 /** \brief Combine two multi-dimensional arrays into one using a binary function or functor.
 
     Note: The effect of this function can often be achieved in a simpler and
-    more readable way by means of \ref MultiMathModule "array experessions".
+    more readable way by means of \ref MultiMathModule "array expressions".
     
     This function can be applied in three modes:
     
@@ -1482,7 +1525,7 @@ combineTwoMultiArrays(MultiArrayView<N, T11, S11> const & source1,
                       MultiArrayView<N, T2, S2> dest, 
                       Functor const & f)
 {
-    for(int k=0; k<N; ++k)
+    for(unsigned int k=0; k<N; ++k)
         vigra_precondition((source1.shape(k) == source2.shape(k) || source1.shape(k) == 1 || 1 == source2.shape(k)) &&
                            (source1.shape(k) == dest.shape(k) || source1.shape(k) == 1 || 1 == dest.shape(k)),
             "combineTwoMultiArrays(): shape mismatch between inputs and/or output.");
@@ -1540,7 +1583,7 @@ combineThreeMultiArraysImpl(SrcIterator1 s1, SrcShape const & shape, SrcAccessor
            ternary function or functor.
 
     Note: The effect of this function can often be achieved in a simpler and
-    more readable way by means of \ref MultiMathModule "array experessions".
+    more readable way by means of \ref MultiMathModule "array expressions".
     
     Except for the fact that it operates on three input arrays, this function is
     identical to the standard mode of \ref combineTwoMultiArrays() (reduce and expand 
diff --git a/include/vigra/multi_shape.hxx b/include/vigra/multi_shape.hxx
index ffc592b..6f5f1da 100644
--- a/include/vigra/multi_shape.hxx
+++ b/include/vigra/multi_shape.hxx
@@ -36,6 +36,7 @@
 #ifndef VIGRA_MULTI_SHAPE_HXX
 #define VIGRA_MULTI_SHAPE_HXX
 
+#include "multi_fwd.hxx"
 #include <sys/types.h>
 #include "tinyvector.hxx"
 #include "array_vector.hxx"
@@ -43,17 +44,10 @@
 
 namespace vigra {
 
-/** \addtogroup MultiIteratorGroup  Multi-dimensional Shapes and Array Iterators
-
-    \brief Shape objects and general iterators for arrays of arbitrary dimension.
+/** \addtogroup MultiIteratorGroup
 */
 //@{
 
-    /** Index type for a single dimension of a MultiArrayView or
-        MultiArray.
-    */
-typedef std::ptrdiff_t MultiArrayIndex;
-
 /********************************************************/
 /*                                                      */
 /*              Singleband and Multiband                */
@@ -73,6 +67,21 @@ struct Multiband  // the last axis is explicitly designated as channel axis
     typedef T value_type;
 };
 
+// check if a type is a multiband type
+template<class T>
+struct IsMultiband : VigraFalseType{
+};
+
+template<class T>
+struct IsMultiband<Multiband<T> > : VigraTrueType{
+};
+
+template <class T>
+struct ChunkedMemory  // the array is organised in chunks
+{
+    typedef T value_type;
+};
+
 template<class T>
 struct NumericTraits<Singleband<T> >
 : public NumericTraits<T>
@@ -165,7 +174,7 @@ defaultMultibandStride(const TinyVector <MultiArrayIndex, N> &shape)
 
 /********************************************************/
 /*                                                      */
-/*                  ResolveMultiband                    */
+/*       resolve Multiband and ChunkedMemory tags       */
 /*                                                      */
 /********************************************************/
 
@@ -214,15 +223,19 @@ struct ResolveMultiband<Multiband<T> >
     }
 };
 
-} // namespace detail
-
-template <unsigned int N, class T, class C = StridedArrayTag>
-class MultiArrayView;
+template <class T>
+struct ResolveChunkedMemory
+{
+    typedef T type;
+};
 
-template <unsigned int N, class T, 
-          class A = std::allocator<typename vigra::detail::ResolveMultiband<T>::type> >
-class MultiArray;
+template <class T>
+struct ResolveChunkedMemory<ChunkedMemory<T> >
+{
+    typedef T type;
+};
 
+} // namespace detail
 
     /** Traits class for the difference type of all MultiIterator, MultiArrayView, and
         MultiArray variants.
@@ -243,17 +256,83 @@ typedef MultiArrayShape<3>::type Shape3; ///< shape type for MultiArray<3, T>
 typedef MultiArrayShape<4>::type Shape4; ///< shape type for MultiArray<4, T>
 typedef MultiArrayShape<5>::type Shape5; ///< shape type for MultiArray<5, T>
 
-    /** \brief Choose the neighborhood system in a dimension-independent way.  
-    
-        DirectNeighborhood corresponds to 4-neighborhood in 2D and 6-neighborhood in 3D, whereas
-        IndirectNeighborhood means 8-neighborhood in 2D and 26-neighborhood in 3D. The general
-        formula for N dimensions are 2*N for direct neighborhood and 3^N-1 for indirect neighborhood. 
-    */
-enum NeighborhoodType { 
-        DirectNeighborhood=0,   ///< use only direct neighbors
-        IndirectNeighborhood=1  ///< use direct and indirect neighbors
+namespace detail
+{
+
+/********************************************************/
+/*                                                      */
+/*                default chunk shapes                  */
+/*                                                      */
+/********************************************************/
+
+template <unsigned int N, class T = int>
+struct ChunkShape
+{
+    typedef typename MultiArrayShape<N>::type Shape;
+    static Shape defaultShape()
+    {
+        Shape res(1);
+        res.template subarray<0,5>() = ChunkShape<5,T>::defaultShape();
+        return res;
+    }
 };
 
+template <class T>
+struct ChunkShape<0, T>
+{
+    static Shape1 defaultShape()
+    {
+        return Shape1(1);
+    }
+};
+
+template <class T>
+struct ChunkShape<1, T>
+{
+    static Shape1 defaultShape()
+    {
+        return Shape1(1 << 18);
+    }
+};
+
+template <class T>
+struct ChunkShape<2, T>
+{
+    static Shape2 defaultShape()
+    {
+        return Shape2(1 << 9, 1 << 9);
+    }
+};
+
+template <class T>
+struct ChunkShape<3, T>
+{
+    static Shape3 defaultShape()
+    {
+        return Shape3(1 << 6, 1 << 6, 1 << 6);
+    }
+};
+
+template <class T>
+struct ChunkShape<4, T>
+{
+    static Shape4 defaultShape()
+    {
+        return Shape4(1 << 6, 1 << 6, 1 << 4, 1 << 2);
+    }
+};
+
+template <class T>
+struct ChunkShape<5, T>
+{
+    static Shape5 defaultShape()
+    {
+        return Shape5(1 << 6, 1 << 6, 1 << 4, 1 << 2, 1 << 2);
+    }
+};
+
+} // namespace detail
+
 // Helper functions
 
 namespace detail {
@@ -450,7 +529,7 @@ struct RelativeToAbsoluteCoordinate<0>
 template <unsigned int N, unsigned int DIMENSION=N-1>
 struct BorderTypeImpl
 {
-    typedef typename MultiArrayShape<N>::type shape_type;
+    typedef TinyVectorView<MultiArrayIndex, N> shape_type;
     
     static unsigned int exec(shape_type const & point, shape_type const & shape)
     {
@@ -466,7 +545,7 @@ struct BorderTypeImpl
 template <unsigned int N>
 struct BorderTypeImpl<N, 0>
 {
-    typedef typename MultiArrayShape<N>::type shape_type;
+    typedef TinyVectorView<MultiArrayIndex, N> shape_type;
     static const unsigned int DIMENSION = 0;
     
     static unsigned int exec(shape_type const & point, shape_type const & shape)
diff --git a/include/vigra/multi_watersheds.hxx b/include/vigra/multi_watersheds.hxx
index 5e1d24c..50ec7c1 100644
--- a/include/vigra/multi_watersheds.hxx
+++ b/include/vigra/multi_watersheds.hxx
@@ -37,6 +37,7 @@
 #define VIGRA_MULTI_WATERSHEDS_HXX
 
 #include <functional>
+#include <limits>
 #include "mathutil.hxx"
 #include "multi_array.hxx"
 #include "multi_math.hxx"
@@ -56,123 +57,163 @@ namespace lemon_graph {
 
 namespace graph_detail {
 
+    // select the neighbor ID for union-find watersheds
+    // standard behavior: use global node ID
+template <class Graph>
+struct NeighborIndexFunctor
+{
+    typedef typename Graph::index_type index_type;
+
+    template <class NodeIter, class ArcIter>
+    static index_type get(Graph const & g, NodeIter const &, ArcIter const & a)
+    {
+        return g.id(g.target(*a));
+    }
+
+    template <class NodeIter, class ArcIter>
+    static index_type getOpposite(Graph const & g, NodeIter const & n, ArcIter const &)
+    {
+        return g.id(*n);
+    }
+
+    static index_type invalidIndex(Graph const & g)
+    {
+        return std::numeric_limits<index_type>::max();
+    }
+};
+
+    // select the neighbor ID for union-find watersheds
+    // GridGraph optimization: use local neighbor index (needs only 1/4 of the memory)
+template<unsigned int N, class DirectedTag>
+struct NeighborIndexFunctor<GridGraph<N, DirectedTag> >
+{
+    typedef GridGraph<N, DirectedTag> Graph;
+    typedef UInt16 index_type;
+
+    template <class NodeIter, class ArcIter>
+    static index_type get(Graph const & g, NodeIter const &, ArcIter const & a)
+    {
+        return a.neighborIndex();
+    }
+
+    template <class NodeIter, class ArcIter>
+    static index_type getOpposite(Graph const & g, NodeIter const &, ArcIter const & a)
+    {
+        return g.oppositeIndex(a.neighborIndex());
+    }
+    static index_type invalidIndex(Graph const & g)
+    {
+        return std::numeric_limits<index_type>::max();
+    }
+};
+
 template <class Graph, class T1Map, class T2Map>
 void
-prepareWatersheds(Graph const & g, 
+prepareWatersheds(Graph const & g,
                   T1Map const & data,
                   T2Map & lowestNeighborIndex)
 {
     typedef typename Graph::NodeIt    graph_scanner;
     typedef typename Graph::OutArcIt  neighbor_iterator;
+    typedef NeighborIndexFunctor<Graph> IndexFunctor;
 
-    for (graph_scanner node(g); node != INVALID; ++node) 
+    for (graph_scanner node(g); node != INVALID; ++node)
     {
         typename T1Map::value_type lowestValue  = data[*node];
-        typename T2Map::value_type lowestIndex  = -1;
+        typename T2Map::value_type lowestIndex  = IndexFunctor::invalidIndex(g);
 
-        for(neighbor_iterator arc(g, node); arc != INVALID; ++arc) 
+        for(neighbor_iterator arc(g, *node); arc != INVALID; ++arc)
         {
-            if(data[g.target(*arc)] <= lowestValue)
+            if(data[g.target(*arc)] < lowestValue)
             {
                 lowestValue = data[g.target(*arc)];
-                lowestIndex = arc.neighborIndex();
+                lowestIndex = IndexFunctor::get(g, node, arc);
             }
         }
         lowestNeighborIndex[*node] = lowestIndex;
     }
 }
 
+
 template <class Graph, class T1Map, class T2Map, class T3Map>
 typename T2Map::value_type
 unionFindWatersheds(Graph const & g,
-                    T1Map const & data, 
+                    T1Map const & data,
                     T2Map const & lowestNeighborIndex,
                     T3Map & labels)
 {
-    typedef typename Graph::NodeIt        graph_scanner;
-    typedef typename Graph::OutBackArcIt  neighbor_iterator;
-    typedef typename T3Map::value_type    LabelType;
+    typedef typename Graph::NodeIt       graph_scanner;
+    typedef typename Graph::OutBackArcIt neighbor_iterator;
+    typedef typename T3Map::value_type   LabelType;
+    typedef NeighborIndexFunctor<Graph>  IndexFunctor;
 
-    vigra::detail::UnionFindArray<LabelType>  regions;
+    vigra::UnionFindArray<LabelType>  regions;
 
     // pass 1: find connected components
-    for (graph_scanner node(g); node != INVALID; ++node) 
+    for (graph_scanner node(g); node != INVALID; ++node)
     {
         // define tentative label for current node
-        LabelType currentLabel = regions.nextFreeLabel();
-        bool hasPlateauNeighbor = false;
-        
+        LabelType currentIndex = regions.nextFreeIndex();
+
         for (neighbor_iterator arc(g, node); arc != INVALID; ++arc)
         {
             // merge regions if current target is center's lowest neighbor or vice versa
-            if(lowestNeighborIndex[*node] == arc.neighborIndex() || 
-               lowestNeighborIndex[g.target(*arc)] == g.oppositeIndex(arc.neighborIndex()))
+            if((lowestNeighborIndex[*node] == IndexFunctor::invalidIndex(g) &&
+                lowestNeighborIndex[g.target(*arc)] == IndexFunctor::invalidIndex(g)) ||
+               (lowestNeighborIndex[*node] == IndexFunctor::get(g, node, arc)) ||
+               (lowestNeighborIndex[g.target(*arc)] == IndexFunctor::getOpposite(g, node, arc)))
             {
-                if(data[*node] == data[g.target(*arc)])
-                    hasPlateauNeighbor = true;
-                LabelType neighborLabel = regions[labels[g.target(*arc)]];
-                currentLabel = regions.makeUnion(neighborLabel, currentLabel);
-            }
-        }
-        
-        if(hasPlateauNeighbor)
-        {
-            // we are on a plateau => link all plateau points
-            for (neighbor_iterator arc(g, node); arc != INVALID; ++arc)
-            {
-                if(data[*node] == data[g.target(*arc)])
-                {
-                    LabelType neighborLabel = regions[labels[g.target(*arc)]];
-                    currentLabel = regions.makeUnion(neighborLabel, currentLabel);
-                }
+                currentIndex = regions.makeUnion(labels[g.target(*arc)], currentIndex);
             }
         }
-        
+
         // set label of current node
-        labels[*node] = regions.finalizeLabel(currentLabel);
+        labels[*node] = regions.finalizeIndex(currentIndex);
     }
-    
+
     LabelType count = regions.makeContiguous();
 
     // pass 2: make component labels contiguous
-    for (graph_scanner node(g); node != INVALID; ++node) 
+    for (graph_scanner node(g); node != INVALID; ++node)
     {
-        labels[*node] = regions[labels[*node]];
+        labels[*node] = regions.findLabel(labels[*node]);
     }
     return count;
 }
 
 template <class Graph, class T1Map, class T2Map>
 typename T2Map::value_type
-generateWatershedSeeds(Graph const & g, 
+generateWatershedSeeds(Graph const & g,
                        T1Map const & data,
                        T2Map & seeds,
                        SeedOptions const & options = SeedOptions())
 {
     typedef typename T1Map::value_type DataType;
     typedef unsigned char MarkerType;
-    
+
     typename Graph::template NodeMap<MarkerType>  minima(g);
-    
+
     if(options.mini == SeedOptions::LevelSets)
     {
         vigra_precondition(options.thresholdIsValid<DataType>(),
             "generateWatershedSeeds(): SeedOptions.levelSets() must be specified with threshold.");
-    
+
         using namespace multi_math;
-        minima = data <= DataType(options.thresh);
+        for(typename Graph::NodeIt iter(g);iter!=lemon::INVALID;++iter){
+            minima[*iter]= data[*iter] <= DataType(options.thresh);
+        }
     }
     else
     {
         DataType threshold = options.thresholdIsValid<DataType>()
                                 ? options.thresh
                                 : NumericTraits<DataType>::max();
-        
+
         if(options.mini == SeedOptions::ExtendedMinima)
-            extendedLocalMinMaxGraph(g, data, minima, MarkerType(1), threshold, 
+            extendedLocalMinMaxGraph(g, data, minima, MarkerType(1), threshold,
                                      std::less<DataType>(), std::equal_to<DataType>(), true);
         else
-            localMinMaxGraph(g, data, minima, MarkerType(1), threshold, 
+            lemon_graph::localMinMaxGraph(g, data, minima, MarkerType(1), threshold,
                              std::less<DataType>(), true);
     }
     return labelGraphWithBackground(g, minima, seeds, MarkerType(0), std::equal_to<MarkerType>());
@@ -180,8 +221,8 @@ generateWatershedSeeds(Graph const & g,
 
 
 template <class Graph, class T1Map, class T2Map>
-typename T2Map::value_type 
-seededWatersheds(Graph const & g, 
+typename T2Map::value_type
+seededWatersheds(Graph const & g,
                  T1Map const & data,
                  T2Map & labels,
                  WatershedOptions const & options)
@@ -193,19 +234,19 @@ seededWatersheds(Graph const & g,
     typedef typename T2Map::value_type  LabelType;
 
     PriorityQueue<Node, CostType, true> pqueue;
-    
+
     bool keepContours = ((options.terminate & KeepContours) != 0);
     LabelType maxRegionLabel = 0;
-    
-    for (graph_scanner node(g); node != INVALID; ++node) 
+
+    for (graph_scanner node(g); node != INVALID; ++node)
     {
         LabelType label = labels[*node];
         if(label != 0)
         {
             if(maxRegionLabel < label)
                 maxRegionLabel = label;
-                
-            for (neighbor_iterator arc(g, node); arc != INVALID; ++arc)
+
+            for (neighbor_iterator arc(g, *node); arc != INVALID; ++arc)
             {
                 if(labels[g.target(*arc)] == 0)
                 {
@@ -219,21 +260,21 @@ seededWatersheds(Graph const & g,
             }
         }
     }
-    
+
     LabelType contourLabel = maxRegionLabel + 1;  // temporary contour label
-    
+
     // perform region growing
     while(!pqueue.empty())
     {
         Node node = pqueue.top();
         CostType cost = pqueue.topPriority();
         pqueue.pop();
-        
+
         if((options.terminate & StopAtThreshold) && (cost > options.max_cost))
             break;
 
         LabelType label = labels[node];
-        
+
         if(label == contourLabel)
             continue;
 
@@ -263,43 +304,50 @@ seededWatersheds(Graph const & g,
             }
         }
     }
-    
+
     if(keepContours)
     {
         // Replace the temporary contour label with label 0.
-        typename T2Map::iterator k   = labels.begin(),
-                                 end = labels.end();
-        for(; k != end; ++k)
-            if(*k == contourLabel)
-                *k = 0;
+        ///typename T2Map::iterator k   = labels.begin(),
+        ///                         end = labels.end();
+        ///for(; k != end; ++k)
+        ///    if(*k == contourLabel)
+        ///        *k = 0;
+
+        for(typename Graph::NodeIt iter(g);iter!=lemon::INVALID;++iter){
+            if(labels[*iter]==contourLabel)
+                labels[*iter]=0;
+        }
     }
-    
+
     return maxRegionLabel;
 }
 
 } // namespace graph_detail
 
 template <class Graph, class T1Map, class T2Map>
-typename T2Map::value_type 
-watershedsGraph(Graph const & g, 
+typename T2Map::value_type
+watershedsGraph(Graph const & g,
                 T1Map const & data,
                 T2Map & labels,
                 WatershedOptions const & options)
 {
     if(options.method == WatershedOptions::UnionFind)
     {
-        vigra_precondition(g.maxDegree() <= NumericTraits<unsigned short>::max(),
+        typedef typename graph_detail::NeighborIndexFunctor<Graph>::index_type index_type;
+
+        vigra_precondition((index_type)g.maxDegree() <= NumericTraits<index_type>::max(),
             "watershedsGraph(): cannot handle nodes with degree > 65535.");
-            
-        typename Graph::template NodeMap<unsigned short>  lowestNeighborIndex(g);
-        
+
+        typename Graph::template NodeMap<index_type>  lowestNeighborIndex(g);
+
         graph_detail::prepareWatersheds(g, data, lowestNeighborIndex);
         return graph_detail::unionFindWatersheds(g, data, lowestNeighborIndex, labels);
     }
     else if(options.method == WatershedOptions::RegionGrowing)
     {
         SeedOptions seed_options;
-        
+
         // check if the user has explicitly requested seed computation
         if(options.seed_options.mini != SeedOptions::Unspecified)
         {
@@ -307,7 +355,7 @@ watershedsGraph(Graph const & g,
         }
         else
         {
-            // otherwise, don't compute seeds if 'labels' already contains them 
+            // otherwise, don't compute seeds if 'labels' already contains them
             if(labels.any())
                 seed_options.mini = SeedOptions::Unspecified;
         }
@@ -316,7 +364,7 @@ watershedsGraph(Graph const & g,
         {
             graph_detail::generateWatershedSeeds(g, data, labels, seed_options);
         }
-        
+
         return graph_detail::seededWatersheds(g, data, labels, options);
     }
     else
@@ -341,7 +389,7 @@ generateWatershedSeeds(MultiArrayView<N, T, S1> const & data,
 {
     vigra_precondition(data.shape() == seeds.shape(),
         "generateWatershedSeeds(): Shape mismatch between input and output.");
-    
+
     GridGraph<N, undirected_tag> graph(data.shape(), neighborhood);
     return lemon_graph::graph_detail::generateWatershedSeeds(graph, data, seeds, options);
 }
@@ -349,6 +397,9 @@ generateWatershedSeeds(MultiArrayView<N, T, S1> const & data,
 
 /** \brief Watershed segmentation of an arbitrary-dimensional array.
 
+    See also \ref unionFindWatershedsBlockwise() for a parallel version of the
+    watershed algorithm.
+
     This function implements variants of the watershed algorithms
     described in
 
@@ -361,41 +412,41 @@ generateWatershedSeeds(MultiArrayView<N, T, S1> const & data,
     The source array \a data is a boundary indicator such as the gaussianGradientMagnitude()
     or the trace of the \ref boundaryTensor(), and the destination \a labels is a label array
     designating membership of each point in one of the regions found. Plateaus in the boundary
-    indicator are handled via simple tie breaking strategies. Argument \a neighborhood 
-    specifies the connectivity between points and can be <tt>DirectNeighborhood</tt> (meaning 
-    4-neighborhood in 2D and 6-neighborhood in 3D, default) or <tt>IndirectNeighborhood</tt> 
+    indicator are handled via simple tie breaking strategies. Argument \a neighborhood
+    specifies the connectivity between points and can be <tt>DirectNeighborhood</tt> (meaning
+    4-neighborhood in 2D and 6-neighborhood in 3D, default) or <tt>IndirectNeighborhood</tt>
     (meaning 8-neighborhood in 2D and 26-neighborhood in 3D).
-    
+
     The watershed variant to be applied can be selected in the \ref WatershedOptions
     object: When you call <tt>WatershedOptions::regionGrowing()</tt> (default), the flooding
     algorithm from [1] is used. Alternatively, <tt>WatershedOptions::unionFind()</tt> uses
-    the scan-line algorithm 4.7 from [2]. The latter is faster, but does not support any options 
+    the scan-line algorithm 4.7 from [2]. The latter is faster, but does not support any options
     (if you pass options nonetheless, they are silently ignored).
-    
+
     The region growing algorithm needs a seed for each region. Seeds can either be provided in
     the destination array \a labels (which will then be overwritten with the result) or computed
-    automatically by an internal call to generateWatershedSeeds(). In the former case you have 
-    full control over seed placement, while the latter is more convenient. Automatic seed 
-    computation is performed when you provide seeding options via <tt>WatershedOptions::seedOptions()</tt> 
-    or when the array \a labels is empty (all zeros), in which case default seeding options 
+    automatically by an internal call to generateWatershedSeeds(). In the former case you have
+    full control over seed placement, while the latter is more convenient. Automatic seed
+    computation is performed when you provide seeding options via <tt>WatershedOptions::seedOptions()</tt>
+    or when the array \a labels is empty (all zeros), in which case default seeding options
     are chosen. The destination image should be zero-initialized for automatic seed computation.
-    
+
     Further options to be specified via \ref WatershedOptions are:
-    
+
     <ul>
-    <li> <tt>keepContours()</tt>: Whether to keep a 1-pixel-wide contour (with label 0) between 
+    <li> <tt>keepContours()</tt>: Whether to keep a 1-pixel-wide contour (with label 0) between
          regions (otherwise, a complete grow is performed, i.e. all pixels are assigned to a region).
-    <li> <tt>stopAtThreshold()</tt>: Whether to stop growing when the boundaryness exceeds a threshold 
+    <li> <tt>stopAtThreshold()</tt>: Whether to stop growing when the boundaryness exceeds a threshold
          (remaining pixels keep label 0).
-    <li> <tt>biasLabel()</tt>: Whether one region (label) is to be preferred or discouraged by biasing its cost 
+    <li> <tt>biasLabel()</tt>: Whether one region (label) is to be preferred or discouraged by biasing its cost
          with a given factor (smaller than 1 for preference, larger than 1 for discouragement).
     </ul>
-    
+
     The option <tt>turboAlgorithm()</tt> is implied by method <tt>regionGrowing()</tt> (this is
     in contrast to watershedsRegionGrowing(), which supports an additional algorithm in 2D only).
 
-    watershedsMultiArray() returns the number of regions found (= the highest region label, because 
-    labels start at 1). 
+    watershedsMultiArray() returns the number of regions found (= the highest region label, because
+    labels start at 1).
 
     <b> Declaration:</b>
 
@@ -421,7 +472,7 @@ generateWatershedSeeds(MultiArrayView<N, T, S1> const & data,
     \code
     MultiArray<2, unsigned char> src(Shape2(w, h));
     ... // read input data
-    
+
     // compute gradient magnitude at scale 1.0 as a boundary indicator
     MultiArray<2, float> gradMag(src.shape());
     gaussianGradientMagnitude(srcImageRange(src), destImage(gradMag), 1.0);
@@ -431,54 +482,54 @@ generateWatershedSeeds(MultiArrayView<N, T, S1> const & data,
         // the pixel type of the destination image must be large enough to hold
         // numbers up to 'max_region_label' to prevent overflow
         MultiArray<2, unsigned int> labeling(src.shape());
-        
-        // call region-growing algorithm for 4-neighborhood, leave a 1-pixel boundary between 
-        // regions, and autogenerate seeds from all gradient minima where the magnitude is 
+
+        // call region-growing algorithm for 4-neighborhood, leave a 1-pixel boundary between
+        // regions, and autogenerate seeds from all gradient minima where the magnitude is
         // less than 2.0.
-        unsigned int max_region_label = 
+        unsigned int max_region_label =
               watershedsMultiArray(gradMag, labeling, DirectNeighborhood,
                                    WatershedOptions().keepContours()
                                       .seedOptions(SeedOptions().minima().threshold(2.0)));
     }
-    
+
     // example 2
     {
         MultiArray<2, unsigned int> labeling(src.shape());
-        
-        // compute seeds beforehand (use connected components of all pixels 
+
+        // compute seeds beforehand (use connected components of all pixels
         // where the gradient is below 4.0)
         unsigned int max_region_label = generateWatershedSeeds(gradMag, labeling,
                                                        SeedOptions().levelSets(4.0));
-        
+
         // quantize the gradient image to 256 gray levels
         float m, M;
         gradMag.minmax(&m, &M);
-        
+
         using namespace multi_math;
         MultiArray<2, unsigned char> gradMag256(255.0 / (M - m) * (gradMag - m));
-        
+
         // call region-growing algorithm with 8-neighborhood,
         // since the data are 8-bit, a faster priority queue will be used
         watershedsMultiArray(gradMag256, labeling, IndirectNeighborhood);
     }
-    
+
     // example 3
     {
         MultiArray<2, unsigned int> labeling(src.shape());
-        
+
         .. // put seeds in 'labeling', e.g. from an interactive labeling program,
            // make sure that label 1 corresponds to the background
-        
+
         // bias the watershed algorithm so that the background is preferred
         // by reducing the cost for label 1 to 90%
-        watershedsMultiArray(gradMag, labeling, 
+        watershedsMultiArray(gradMag, labeling,
                              WatershedOptions().biasLabel(1, 0.9));
     }
-    
+
     // example 4
     {
         MultiArray<2, unsigned int> labeling(src.shape());
-        
+
         // use the fast union-find algorithm with 4-neighborhood
         watershedsMultiArray(gradMag, labeling, WatershedOptions().unionFind());
     }
@@ -496,7 +547,7 @@ watershedsMultiArray(MultiArrayView<N, T, S1> const & data,
 {
     vigra_precondition(data.shape() == labels.shape(),
         "watershedsMultiArray(): Shape mismatch between input and output.");
-    
+
     GridGraph<N, undirected_tag> graph(data.shape(), neighborhood);
     return lemon_graph::watershedsGraph(graph, data, labels, options);
 }
diff --git a/include/vigra/non_local_mean.hxx b/include/vigra/non_local_mean.hxx
new file mode 100644
index 0000000..d48316b
--- /dev/null
+++ b/include/vigra/non_local_mean.hxx
@@ -0,0 +1,952 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2014 by Thorsten Beier and Ullrich Koethe              */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+/* RE-IMPLEMENTAION OF THE WORK OF:                                     */
+/* Pierrick Coupe - pierrick.coupe at gmail.com                            */
+/* Jose V. Manjon - jmanjon at fis.upv.es                                  */
+/* Brain Imaging Center, Montreal Neurological Institute.               */
+/* Mc Gill University                                                   */
+/*                                                                      */
+/************************************************************************/
+/* The ONLM filter is described in:                                     */
+/*                                                                      */
+/* P. Coup���, P. Yger, S. Prima, P. Hellier, C. Kervrann, C. Barillot.   */
+/* An Optimized Blockwise Non Local Means Denoising Filter              */ 
+/* for 3D Magnetic Resonance Images                                     */
+/* . IEEE Transactions on Medical Imaging, 27(4):425-441,               */
+/* Avril 2008                                                           */
+/************************************************************************/
+
+
+#ifndef VIGRA_NON_LOCAL_MEAN
+#define VIGRA_NON_LOCAL_MEAN
+
+
+/*std*/
+#include <iomanip>
+
+/*vigra*/
+#include "multi_array.hxx"
+#include "multi_convolution.hxx"
+#include "error.hxx"
+#include "threading.hxx"
+#include "gaussians.hxx"
+
+namespace vigra{
+
+struct NonLocalMeanParameter{
+
+    NonLocalMeanParameter(
+        const double sigmaSpatial = 2.0,
+        const int searchRadius = 3,
+        const int patchRadius = 1,
+        const double sigmaMean = 1.0,
+        const int stepSize = 2,
+        const int iterations=1,
+        const int nThreads = 8,
+        const bool verbose = true
+    ):
+    sigmaSpatial_(sigmaSpatial),
+    searchRadius_(searchRadius),
+    patchRadius_(patchRadius),
+    sigmaMean_(sigmaMean),
+    stepSize_(stepSize),
+    iterations_(iterations),
+    nThreads_(nThreads),
+    verbose_(verbose){
+    }
+    double sigmaSpatial_;
+    int searchRadius_;
+    int patchRadius_;
+    double sigmaMean_;
+    int stepSize_;
+    int iterations_;
+    int nThreads_;
+    bool verbose_;
+};
+
+
+// this has no template since this should
+// be the same class for different dimensions 
+// and pixel types
+class RatioPolicyParameter{
+public:
+    RatioPolicyParameter(
+        const double sigma     = 5.0,
+        const double meanRatio = 0.95,
+        const double varRatio  = 0.5,
+        const double epsilon   = 0.00001
+    ):
+    sigma_(sigma),
+    meanRatio_(meanRatio),
+    varRatio_(varRatio),
+    epsilon_(epsilon){
+    }
+    double sigma_;
+    double meanRatio_;
+    double varRatio_;
+    double epsilon_;
+};
+
+
+template<class PIXEL_TYPE_IN>
+class RatioPolicy{
+
+    public:
+        typedef RatioPolicyParameter ParameterType;
+        typedef typename NumericTraits<PIXEL_TYPE_IN>::RealPromote PixelType;
+        typedef typename NumericTraits<PIXEL_TYPE_IN>::ValueType   ValueType;
+
+
+        RatioPolicy(const ParameterType & param)
+        :   meanRatio_(static_cast<ValueType>(param.meanRatio_)),
+            varRatio_(static_cast<ValueType>(param.varRatio_)),
+            epsilon_(static_cast<ValueType>(param.epsilon_)),
+            sigmaSquared_(param.sigma_*param.sigma_){
+
+        }
+
+        bool usePixel(const PixelType & meanA, const PixelType & varA)const{
+            return sum(meanA) > epsilon_  &&  sum(varA) > epsilon_;
+        }
+
+
+        bool usePixelPair(
+            const PixelType & meanA, const PixelType & varA,
+            const PixelType & meanB, const PixelType & varB
+        )const{
+            // Compute mean ratio of mean and variance
+            const ValueType m = mean(meanA/meanB);
+            const ValueType v = mean(varA/varB);          
+            return (m > meanRatio_ && m < (1.0 / meanRatio_) && v > varRatio_ && v < (1.0 / varRatio_));
+        }
+
+        ValueType distanceToWeight(const PixelType & meanA, const PixelType & varA, const ValueType distance){
+            return  exp(-distance /sigmaSquared_);
+        }
+
+    private:
+        ValueType meanRatio_;
+        ValueType varRatio_;
+        ValueType epsilon_;
+        ValueType sigmaSquared_;
+};
+
+
+
+// this has no template since this should
+// be the same class for different dimensions 
+// and pixel types
+class NormPolicyParameter{
+public:
+    NormPolicyParameter(
+        const double sigma     = 5.0,
+        const double meanDist  = 0.95,
+        const double varRatio   = 0.5,
+        const double epsilon   = 0.00001
+    ):
+    sigma_(sigma),
+    meanDist_(meanDist),
+    varRatio_(varRatio),
+    epsilon_(epsilon){
+    }
+    double sigma_;
+    double meanDist_;
+    double varRatio_;
+    double epsilon_;
+};
+
+
+
+template<class V,int SIZE>
+inline bool equal(const TinyVector<V,SIZE> & a,const TinyVector<V,SIZE> b){
+    for(int i=0;i<SIZE;++i)
+        if(a[i]!=b[i])
+            return false;
+    return true;
+}
+
+
+
+template<int DIM, bool ALWAYS_INSIDE>
+struct BorderHelper;
+
+template< int DIM>
+struct BorderHelper<DIM,true>{
+    template<class COORD,class IMAGE>
+    static bool isInside(const COORD & ,const IMAGE &  ){
+        return true;
+    }
+    template<class COORD,class IMAGE>
+    static bool isOutside(const COORD & ,const IMAGE &  ){
+        return false;
+    }
+
+    template<class COORD,class IMAGE>
+    static void mirrorIfIsOutsidePoint(COORD & ,IMAGE & ){
+    }
+
+};
+
+template< int DIM>
+struct BorderHelper<DIM,false>{
+    template<class COORD,class IMAGE>
+    static bool isInside(const COORD & c,const IMAGE &  img){
+        return img.isInside(c);
+    }
+    template<class COORD,class IMAGE>
+    static bool isOutside(const COORD & c,const IMAGE &  img){
+        return img.isOutside(c);
+    }
+
+    template<class COORD,class IMAGE>
+    static void mirrorIfIsOutsidePoint(COORD & coord,const IMAGE & img){
+        for(int c=0;c<DIM;++c){
+            if(coord[c]<0)
+                coord[c]=-1*coord[c];
+            else if(coord[c]>= img.shape(c))
+                coord[c] = 2 * img.shape(c) - coord[c] - 1;
+        }
+    }
+};
+
+
+
+
+
+
+template<class PIXEL_TYPE_IN>
+class NormPolicy{
+
+    public:
+        typedef NormPolicyParameter ParameterType;
+        typedef typename NumericTraits<PIXEL_TYPE_IN>::RealPromote PixelType;
+        typedef typename NumericTraits<PIXEL_TYPE_IN>::ValueType   ValueType;
+
+
+        NormPolicy(const ParameterType & param)
+        :   meanDist_(static_cast<ValueType>(param.meanDist_)),
+            varRatio_(static_cast<ValueType>(param.varRatio_)),
+            epsilon_(static_cast<ValueType>(param.epsilon_)),
+            sigmaSquared_(param.sigma_*param.sigma_){
+
+        }
+
+        bool usePixel(const PixelType & meanA, const PixelType & varA)const{
+            return sum(varA)>epsilon_;
+        }
+
+
+        bool usePixelPair(
+            const PixelType & meanA, const PixelType & varA,
+            const PixelType & meanB, const PixelType & varB
+        )const{
+            // Compute mean ratio of mean and variance
+            const ValueType m = squaredNorm(meanA-meanB);
+            const ValueType v = mean(varA/varB); 
+            //std::cout<<"norms  "<<m<<" v "<<v<<"\n";
+            return (m < meanDist_ && v > varRatio_ && v < (1.0 / varRatio_));
+        }
+
+        ValueType distanceToWeight(const PixelType & meanA, const PixelType & varA, const ValueType distance){
+            return  exp(-distance /sigmaSquared_);
+        }
+
+    private:
+        ValueType meanDist_;
+        ValueType varRatio_;
+        ValueType epsilon_;
+        ValueType sigmaSquared_;
+};
+
+
+// UnstridedArrayTag
+
+template<int DIM, class PIXEL_TYPE_IN, class SMOOTH_POLICY>
+class BlockWiseNonLocalMeanThreadObject{
+    typedef PIXEL_TYPE_IN       PixelTypeIn;
+    typedef typename NumericTraits<PixelTypeIn>::RealPromote        RealPromotePixelType;  
+    typedef typename NumericTraits<RealPromotePixelType>::ValueType RealPromoteScalarType;
+    
+    typedef typename MultiArray<DIM,int>::difference_type Coordinate;
+    typedef NonLocalMeanParameter ParameterType;
+
+public:
+    typedef void result_type;
+    typedef MultiArrayView<DIM,PixelTypeIn>           InArrayView;
+    typedef MultiArrayView<DIM,RealPromotePixelType>  MeanArrayView;
+    typedef MultiArrayView<DIM,RealPromotePixelType>  VarArrayView;
+    typedef MultiArrayView<DIM,RealPromotePixelType>  EstimateArrayView;
+    typedef MultiArrayView<DIM,RealPromoteScalarType> LabelArrayView;
+    typedef std::vector<RealPromotePixelType>         BlockAverageVectorType;
+    typedef std::vector<RealPromoteScalarType>        BlockGaussWeightVectorType;
+    typedef SMOOTH_POLICY                             SmoothPolicyType;
+    // range type
+    typedef TinyVector<int,2> RangeType;
+    //typedef boost::mutex      MutexType;
+
+    typedef threading::thread  ThreadType;
+    typedef threading::mutex   MutexType;
+
+    BlockWiseNonLocalMeanThreadObject(
+        const InArrayView &         inImage,
+        MeanArrayView &             meanImage,
+        VarArrayView &              varImage,
+        EstimateArrayView &         estimageImage,
+        LabelArrayView &            labelImage,
+        const SmoothPolicyType  &   smoothPolicy,
+        const ParameterType &       param,
+        const size_t                nThreads,
+        MutexType &                 estimateMutex,
+        MultiArray<1,int> &         progress
+    )
+    : 
+    inImage_(inImage),
+    meanImage_(meanImage),
+    varImage_(varImage),
+    estimageImage_(estimageImage),
+    labelImage_(labelImage),
+    smoothPolicy_(smoothPolicy),
+    param_(param),
+    lastAxisRange_(),
+    threadIndex_(),
+    nThreads_(nThreads),
+    estimateMutexPtr_(&estimateMutex),
+    progress_(progress),
+    average_(std::pow( (double)(2*param.patchRadius_+1), DIM) ),
+    gaussWeight_(std::pow( (double)(2*param.patchRadius_+1), DIM) ),
+    shape_(inImage.shape()),
+    totalSize_()
+    {
+        totalSize_ = 1;
+        for(int dim=0;dim<DIM;++dim)
+            totalSize_*=(shape_[dim]/param.stepSize_);
+    }
+
+    void setRange(const RangeType & lastAxisRange){
+        lastAxisRange_=lastAxisRange;
+    }
+    void setThreadIndex(const size_t threadIndex){
+        threadIndex_=threadIndex;
+    }
+
+
+    void operator()();
+
+private:
+
+    template<bool ALWAYS_INSIDE>
+    void processSinglePixel(const Coordinate & xyz);
+
+    template<bool ALWAYS_INSIDE>
+    void processSinglePair( const Coordinate & xyz,const Coordinate & nxyz,RealPromoteScalarType & wmax,RealPromoteScalarType & totalweight);
+
+    template<bool ALWAYS_INSIDE>
+    RealPromoteScalarType patchDistance(const Coordinate & xyz,const Coordinate & nxyz);
+
+    template<bool ALWAYS_INSIDE>
+    void patchExtractAndAcc(const Coordinate & xyz,const RealPromoteScalarType weight);
+
+    template<bool ALWAYS_INSIDE>
+    void patchAccMeanToEstimate(const Coordinate & xyz,const RealPromoteScalarType globalSum);
+
+
+    bool isAlwaysInside(const Coordinate & coord)const{
+        const Coordinate r = (Coordinate(param_.searchRadius_) + Coordinate(param_.patchRadius_) +1 );
+        const Coordinate test1 = coord - r;
+        const Coordinate test2 = coord + r;
+        return inImage_.isInside(test1) && inImage_.isInside(test2);
+    }
+
+    void initalizeGauss();
+
+    void progressPrinter(const int counter);
+
+
+    // array views
+    InArrayView         inImage_;
+    MeanArrayView       meanImage_;
+    VarArrayView        varImage_;
+    EstimateArrayView   estimageImage_;
+    LabelArrayView      labelImage_;
+
+    // policy object 
+    SmoothPolicyType smoothPolicy_;
+
+    // param obj.
+    ParameterType param_;
+
+    // thread related; 
+    RangeType lastAxisRange_;
+    size_t threadIndex_;
+    size_t nThreads_;
+    MutexType * estimateMutexPtr_;
+    MultiArrayView<1,int>  progress_;
+
+
+    // computations
+    BlockAverageVectorType average_;
+    BlockGaussWeightVectorType gaussWeight_;
+    Coordinate shape_;
+    size_t totalSize_;
+};
+
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY>
+inline void BlockWiseNonLocalMeanThreadObject<DIM, PIXEL_TYPE_IN, SMOOTH_POLICY>::initalizeGauss(){
+    Coordinate xyz;
+    const int pr = param_.patchRadius_;
+    Gaussian<RealPromoteScalarType> gaussian(param_.sigmaSpatial_);
+    int c=0;
+    RealPromoteScalarType sum = RealPromoteScalarType(0.0);
+    if(DIM==2){
+        for (xyz[1] = -pr; xyz[1]  <=pr; ++xyz[1])
+        for (xyz[0] = -pr; xyz[0]  <=pr; ++xyz[0],++c){
+            const RealPromoteScalarType distance = norm(xyz);
+            const RealPromoteScalarType w =gaussian(distance);
+            sum+=w;
+            gaussWeight_[c]=w;   
+        }
+    }
+    if(DIM==3){
+        for (xyz[2] = -pr; xyz[2]  <=pr; ++xyz[2])
+        for (xyz[1] = -pr; xyz[1]  <=pr; ++xyz[1])
+        for (xyz[0] = -pr; xyz[0]  <=pr; ++xyz[0],++c){
+            const RealPromoteScalarType distance = norm(xyz);
+            const RealPromoteScalarType w =gaussian(distance);
+            sum+=w;
+            gaussWeight_[c]=w;     
+        }
+    }
+    if(DIM==4){
+        for (xyz[3] = -pr; xyz[3]  <=pr; ++xyz[3])
+        for (xyz[2] = -pr; xyz[2]  <=pr; ++xyz[2])
+        for (xyz[1] = -pr; xyz[1]  <=pr; ++xyz[1])
+        for (xyz[0] = -pr; xyz[0]  <=pr; ++xyz[0],++c){
+            const RealPromoteScalarType distance = norm(xyz);
+            const RealPromoteScalarType w =gaussian(distance);
+            sum+=w;
+            gaussWeight_[c]=w;   
+        }
+    }
+    // normalize
+    for(size_t i=0;i<gaussWeight_.size();++i){
+        gaussWeight_[i]/=sum;
+    }
+}
+
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY>
+inline void BlockWiseNonLocalMeanThreadObject<DIM, PIXEL_TYPE_IN, SMOOTH_POLICY>::progressPrinter(const int counter){
+    progress_[threadIndex_] = counter;
+    if(threadIndex_==nThreads_-1){
+        if(counter%100 == 0){
+            int c=0;
+            for(size_t ti=0;ti<nThreads_;++ti)
+                c+=progress_[ti];
+            double pr=c;
+            pr/=totalSize_;
+            pr*=100.0;
+            std::cout<<"\rprogress "<<std::setw(10)<<pr<<" %%"<<std::flush;
+        }
+    }
+}
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY>
+void BlockWiseNonLocalMeanThreadObject<DIM, PIXEL_TYPE_IN, SMOOTH_POLICY>::operator()(){
+    const int start = lastAxisRange_[0];
+    const int end = lastAxisRange_[1];
+    const int stepSize = param_.stepSize_;
+
+    this->initalizeGauss();
+
+    Coordinate xyz; 
+    int c=0;
+    if(param_.verbose_ && threadIndex_==nThreads_-1){
+        std::cout<<"progress"; 
+    }
+
+    if(DIM==2){
+        for (xyz[1] = start; xyz[1]  < end;    xyz[1]  += stepSize)
+        for (xyz[0] = 0;      xyz[0]  < shape_[0]; xyz[0]  += stepSize){
+
+            if(isAlwaysInside(xyz))
+                this->processSinglePixel<true>(xyz);
+            else
+                this->processSinglePixel<false>(xyz);
+            if(param_.verbose_)
+                this->progressPrinter(c);
+            ++c;
+        }
+    }
+    if(DIM==3){
+        for (xyz[2] = start; xyz[2]  < end;    xyz[2]  += stepSize)
+        for (xyz[1] = 0;   xyz[1]  < shape_[1]; xyz[1]  += stepSize)
+        for (xyz[0] = 0;   xyz[0]  < shape_[0]; xyz[0]  += stepSize){
+            if(isAlwaysInside(xyz))
+                this->processSinglePixel<true>(xyz);
+            else
+                this->processSinglePixel<false>(xyz);
+            if(param_.verbose_)
+                this->progressPrinter(c);
+            ++c;
+        }
+    }
+    if(DIM==4){
+        for (xyz[3] = start; xyz[3]  < end;    xyz[3]  += stepSize)
+        for (xyz[2] = 0;   xyz[2]  < shape_[2]; xyz[2]  += stepSize)
+        for (xyz[1] = 0;   xyz[1]  < shape_[1]; xyz[1]  += stepSize)
+        for (xyz[0] = 0;   xyz[0]  < shape_[0]; xyz[0]  += stepSize){
+            if(isAlwaysInside(xyz))
+                this->processSinglePixel<true>(xyz);
+            else
+                this->processSinglePixel<false>(xyz);
+            if(param_.verbose_)
+                this->progressPrinter(c);
+            ++c;
+        }
+    }
+    if(param_.verbose_ && threadIndex_==nThreads_-1){
+        std::cout<<"\rprogress "<<std::setw(10)<<"100"<<" %%"<<"\n";
+    }
+}
+
+
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY>
+template<bool ALWAYS_INSIDE>
+inline void BlockWiseNonLocalMeanThreadObject<DIM, PIXEL_TYPE_IN, SMOOTH_POLICY>::processSinglePixel(
+    const Coordinate & xyz
+){
+        Coordinate nxyz(SkipInitialization);
+        const int searchRadius = param_.searchRadius_;
+        std::fill(average_.begin(),average_.end(),RealPromotePixelType(0.0));
+        RealPromoteScalarType totalweight = 0.0;
+
+        if(smoothPolicy_.usePixel(meanImage_[xyz],varImage_[xyz])){
+
+            RealPromoteScalarType wmax = 0.0;
+            const Coordinate start = xyz- Coordinate(param_.searchRadius_);
+            const Coordinate end   = xyz+ Coordinate(param_.searchRadius_);
+
+            if(DIM==2){
+                for (nxyz[1] = start[1]; nxyz[1] <= end[1]; nxyz[1]++)
+                for (nxyz[0] = start[0]; nxyz[0] <= end[0]; nxyz[0]++){
+                    //nxyz = xyz  + nxyz;
+                    if(equal(nxyz,xyz))
+                        continue;
+                    this->processSinglePair<ALWAYS_INSIDE>(xyz,nxyz,wmax,totalweight);
+                }
+            }
+            else if(DIM==3){
+                for (nxyz[2] = start[2]; nxyz[2] <= end[2]; nxyz[2]++)
+                for (nxyz[1] = start[1]; nxyz[1] <= end[1]; nxyz[1]++)
+                for (nxyz[0] = start[0]; nxyz[0] <= end[0]; nxyz[0]++){
+                    if(equal(nxyz,xyz))
+                        continue;
+                    this->processSinglePair<ALWAYS_INSIDE>(xyz,nxyz,wmax,totalweight);
+                }
+            }
+            else if(DIM==4){
+                for (nxyz[3] = start[3]; nxyz[3] <= end[3]; nxyz[3]++)
+                for (nxyz[2] = start[2]; nxyz[2] <= end[2]; nxyz[2]++)
+                for (nxyz[1] = start[1]; nxyz[1] <= end[1]; nxyz[1]++)
+                for (nxyz[0] = start[0]; nxyz[0] <= end[0]; nxyz[0]++){
+                    if(equal(nxyz,xyz))
+                        continue;
+                    this->processSinglePair<ALWAYS_INSIDE>(xyz,nxyz,wmax,totalweight);
+                }
+            }
+
+
+            if (wmax == 0.0){
+                wmax = 1.0;
+            }
+            // give pixel xyz  as much weight as
+            // the maximum weighted other patch
+            this->patchExtractAndAcc<ALWAYS_INSIDE>(xyz,wmax);
+            totalweight += wmax;
+
+            // this if seems total useless to me
+            if (totalweight != 0.0){
+                this->patchAccMeanToEstimate<ALWAYS_INSIDE>(xyz,totalweight);
+            }
+
+        }
+        else{
+            const double wmax = 1.0;
+            this->patchExtractAndAcc<ALWAYS_INSIDE>(xyz,wmax);
+            totalweight += wmax;
+            this->patchAccMeanToEstimate<ALWAYS_INSIDE>(xyz,totalweight);
+        }
+}
+
+
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY>
+template<bool ALWAYS_INSIDE>
+inline void BlockWiseNonLocalMeanThreadObject<DIM, PIXEL_TYPE_IN, SMOOTH_POLICY>::processSinglePair(
+    const Coordinate & xyz,
+    const Coordinate & nxyz,
+    RealPromoteScalarType & wmax,
+    RealPromoteScalarType & totalweight
+){
+    
+    if(BorderHelper<DIM,ALWAYS_INSIDE>::isInside(nxyz,inImage_)){
+    //if(ALWAYS_INSIDE || inImage_.isInside(nxyz)){
+        if(smoothPolicy_.usePixel(meanImage_[nxyz],varImage_[nxyz])){
+            // here we check if to patches fit to each other
+            // one patch is around xyz 
+            // other patch is arround nxyz
+            if(smoothPolicy_.usePixelPair(meanImage_[xyz],varImage_[xyz],meanImage_[nxyz],varImage_[nxyz])){                
+                const RealPromoteScalarType distance =this->patchDistance<ALWAYS_INSIDE>(xyz,nxyz);
+                const RealPromoteScalarType w = smoothPolicy_.distanceToWeight(meanImage_[xyz],varImage_[xyz],distance);
+                wmax = std::max(w,wmax);
+                this->patchExtractAndAcc<ALWAYS_INSIDE>(nxyz,w);
+                totalweight+=  w;
+            }
+        }
+    }
+}
+
+
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY>
+template<bool ALWAYS_INSIDE>
+inline typename BlockWiseNonLocalMeanThreadObject<DIM, PIXEL_TYPE_IN, SMOOTH_POLICY>::RealPromoteScalarType 
+BlockWiseNonLocalMeanThreadObject<DIM,PIXEL_TYPE_IN,SMOOTH_POLICY>::patchDistance(
+    const Coordinate & pA,
+    const Coordinate & pB
+){
+
+    // TODO : use a acculator like think to make this more beautiful ?
+    const int f = param_.patchRadius_;
+    Coordinate offset(SkipInitialization),nPa(SkipInitialization),nPb(SkipInitialization);
+    int acu = 0;
+    RealPromoteScalarType distancetotal = 0;
+    int c =0 ;
+    //this->mirrorIfIsOutsidePoint<ALWAYS_INSIDE>(nPa);       
+   // this->mirrorIfIsOutsidePoint<ALWAYS_INSIDE>(nPb);       
+    #define VIGRA_NLM_IN_LOOP_CODE                              \
+        nPa = pA+offset;                                        \
+        nPb = pB+offset;                                        \
+        BorderHelper<DIM,ALWAYS_INSIDE>::mirrorIfIsOutsidePoint(nPa,inImage_); \
+        BorderHelper<DIM,ALWAYS_INSIDE>::mirrorIfIsOutsidePoint(nPb,inImage_); \
+        const RealPromoteScalarType gaussWeight = gaussWeight_[c]; \
+        const RealPromotePixelType vA = inImage_[nPa];          \
+        const RealPromotePixelType vB = inImage_[nPb];          \
+        distancetotal += gaussWeight*vigra::sizeDividedSquaredNorm(vA-vB);  \
+        ++acu;
+
+    if(DIM==2){
+        for (offset[1] = -f; offset[1] <= f; ++offset[1])
+        for (offset[0] = -f; offset[0] <= f; ++offset[0],++c){
+            VIGRA_NLM_IN_LOOP_CODE;
+        }
+    }
+    else if(DIM==3){
+        for (offset[2] = -f; offset[2] <= f; ++offset[2])
+        for (offset[1] = -f; offset[1] <= f; ++offset[1])
+        for (offset[0] = -f; offset[0] <= f; ++offset[0],++c){
+            VIGRA_NLM_IN_LOOP_CODE;
+        }
+    }
+    else if(DIM==4){
+        for (offset[3] = -f; offset[3] <= f; ++offset[3])
+        for (offset[2] = -f; offset[2] <= f; ++offset[2])
+        for (offset[1] = -f; offset[1] <= f; ++offset[1])
+        for (offset[0] = -f; offset[0] <= f; ++offset[0],++c){
+            VIGRA_NLM_IN_LOOP_CODE;
+        }
+    }
+    #undef VIGRA_NLM_IN_LOOP_CODE
+    return distancetotal / acu;
+}
+
+
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY>
+template<bool ALWAYS_INSIDE>
+inline void 
+BlockWiseNonLocalMeanThreadObject<DIM,PIXEL_TYPE_IN,SMOOTH_POLICY>::patchExtractAndAcc(
+    const Coordinate & xyz,
+    const RealPromoteScalarType weight
+){
+    Coordinate xyzPos(SkipInitialization),abc(SkipInitialization);
+    Coordinate nhSize3(param_.patchRadius_);
+    const int ns = 2 * param_.patchRadius_ + 1;
+    int count = 0;
+
+    // todo: remove abc vector
+
+    #define VIGRA_NLM_IN_LOOP_CODE                                          \
+        xyzPos = xyz + abc - nhSize3;                                       \
+        if(BorderHelper<DIM,ALWAYS_INSIDE>::isOutside(xyzPos,inImage_))     \
+            average_[count] += inImage_[xyz]* weight;                       \
+        else                                                                \
+            average_[count] += inImage_[xyzPos]* weight;                    \
+        count++
+
+    if(DIM==2){
+        for (abc[1] = 0; abc[1] < ns; abc[1]++)
+        for (abc[0] = 0; abc[0] < ns; abc[0]++){
+            VIGRA_NLM_IN_LOOP_CODE;
+        }
+    }
+    else if(DIM==3){
+        for (abc[2] = 0; abc[2] < ns; abc[2]++)
+        for (abc[1] = 0; abc[1] < ns; abc[1]++)
+        for (abc[0] = 0; abc[0] < ns; abc[0]++){
+            VIGRA_NLM_IN_LOOP_CODE;
+        }
+    }
+    else if(DIM==4){
+        for (abc[3] = 0; abc[3] < ns; abc[3]++)
+        for (abc[2] = 0; abc[2] < ns; abc[2]++)
+        for (abc[1] = 0; abc[1] < ns; abc[1]++)
+        for (abc[0] = 0; abc[0] < ns; abc[0]++){
+            VIGRA_NLM_IN_LOOP_CODE;
+        }
+    }
+
+    #undef VIGRA_NLM_IN_LOOP_CODE
+}
+
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY>
+template<bool ALWAYS_INSIDE>
+inline void 
+BlockWiseNonLocalMeanThreadObject<DIM,PIXEL_TYPE_IN,SMOOTH_POLICY>::patchAccMeanToEstimate(
+    const Coordinate & xyz,
+    const RealPromoteScalarType globalSum
+){
+    Coordinate abc(SkipInitialization),xyzPos(SkipInitialization),nhSize(param_.patchRadius_);        
+    int count = 0 ;
+    const int ns = 2 * param_.patchRadius_ + 1;
+
+    #define VIGRA_NLM_IN_LOOP_CODE                                              \
+            xyzPos = xyz + abc - nhSize;                                        \
+            if(BorderHelper<DIM,ALWAYS_INSIDE>::isInside(xyzPos,inImage_)){     \
+                estimateMutexPtr_->lock();                                      \
+                RealPromotePixelType value = estimageImage_[xyzPos];            \
+                const RealPromoteScalarType gw = gaussWeight_[count];           \
+                RealPromotePixelType tmp =(average_[count] / globalSum);        \
+                tmp*=gw;                                                        \
+                value +=tmp;                                                    \
+                estimageImage_[xyzPos] = value;                                 \
+                labelImage_[xyzPos]+=gw;                                        \
+                estimateMutexPtr_->unlock();                                    \
+            }                                                                   \
+            count++
+
+    if(DIM==2){
+        for (abc[1] = 0; abc[1] < ns; abc[1]++)
+        for (abc[0] = 0; abc[0] < ns; abc[0]++){
+            VIGRA_NLM_IN_LOOP_CODE;
+        }
+    }
+    if(DIM==3){
+        for (abc[2] = 0; abc[2] < ns; abc[2]++)
+        for (abc[1] = 0; abc[1] < ns; abc[1]++)
+        for (abc[0] = 0; abc[0] < ns; abc[0]++){
+            VIGRA_NLM_IN_LOOP_CODE;
+        }
+    }
+    if(DIM==4){
+        for (abc[3] = 0; abc[3] < ns; abc[3]++)
+        for (abc[2] = 0; abc[2] < ns; abc[2]++)
+        for (abc[1] = 0; abc[1] < ns; abc[1]++)
+        for (abc[0] = 0; abc[0] < ns; abc[0]++){
+            VIGRA_NLM_IN_LOOP_CODE;
+        }
+    }
+    #undef VIGRA_NLM_IN_LOOP_CODE
+}
+
+
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY,class PIXEL_TYPE_OUT>
+inline void gaussianMeanAndVariance(
+    const vigra::MultiArrayView<DIM,PIXEL_TYPE_IN> & inArray,
+    const double sigma,
+    vigra::MultiArrayView<DIM,PIXEL_TYPE_OUT> & meanArray,
+    vigra::MultiArrayView<DIM,PIXEL_TYPE_OUT> & varArray,
+    vigra::MultiArrayView<DIM,PIXEL_TYPE_OUT> & tmpArray
+){
+
+    // compute mean and variance 
+    vigra::gaussianSmoothMultiArray(inArray, meanArray, sigma);
+    // square raw data (use estimate Image to store temp. results)
+    for(int scanOrderIndex=0;scanOrderIndex<inArray.size();++scanOrderIndex){
+        tmpArray[scanOrderIndex]=vigra::pow(inArray[scanOrderIndex],2);
+    }
+    vigra::gaussianSmoothMultiArray(tmpArray,varArray, sigma);
+    for(int scanOrderIndex=0;scanOrderIndex<inArray.size();++scanOrderIndex){
+        PIXEL_TYPE_OUT var = varArray[scanOrderIndex] - vigra::pow(meanArray[scanOrderIndex],2);
+        var  = clipLower(var);
+        //makeNegtiveValuesZero(var);  // callbyref
+        varArray[scanOrderIndex] = var;
+    }      
+}
+
+template<int DIM,class PIXEL_TYPE_IN, class SMOOTH_POLICY,class PIXEL_TYPE_OUT>
+inline void gaussianMeanAndVariance(
+    const vigra::MultiArrayView<DIM,PIXEL_TYPE_IN> & inArray,
+    const double sigma,
+    vigra::MultiArrayView<DIM,PIXEL_TYPE_OUT> & meanArray,
+    vigra::MultiArrayView<DIM,PIXEL_TYPE_OUT> & varArray
+){
+    vigra::MultiArray<DIM,PIXEL_TYPE_OUT>  tmpArray(inArray.shape());
+    gaussianMeanAndVariance<DIM,PIXEL_TYPE_IN,PIXEL_TYPE_OUT>(inArray,sigma,meanArray,varArray,tmpArray);   
+}
+
+namespace detail_non_local_means{
+
+template<int DIM, class PIXEL_TYPE_IN,class PIXEL_TYPE_OUT,class SMOOTH_POLICY>
+void nonLocalMean1Run(
+    const vigra::MultiArrayView<DIM,PIXEL_TYPE_IN> & image,
+    const SMOOTH_POLICY & smoothPolicy,
+    const NonLocalMeanParameter param,
+    vigra::MultiArrayView<DIM,PIXEL_TYPE_OUT> outImage
+){
+
+    typedef PIXEL_TYPE_IN       PixelTypeIn;
+    typedef typename vigra::NumericTraits<PixelTypeIn>::RealPromote         RealPromotePixelType;  
+     typedef typename vigra::NumericTraits<RealPromotePixelType>::ValueType RealPromoteScalarType;  
+    typedef SMOOTH_POLICY SmoothPolicyType;
+
+    typedef BlockWiseNonLocalMeanThreadObject<DIM,PixelTypeIn,SmoothPolicyType> ThreadObjectType;
+
+
+    // inspect parameter
+    vigra_precondition(param.stepSize_>=1,"NonLocalMean Parameter: \"stepSize>=1\" violated");
+    vigra_precondition(param.searchRadius_>=1, "NonLocalMean Parameter: \"searchRadius >=1\" violated");
+    vigra_precondition(param.patchRadius_>=1,"NonLocalMean Parameter: \"searchRadius >=1\" violated");
+    vigra_precondition(param.stepSize_-1<=param.patchRadius_,"NonLocalMean Parameter: \"stepSize -1 <= patchRadius\"  violated");
+
+    // allocate arrays
+    vigra::MultiArray<DIM,RealPromotePixelType> meanImage(image.shape());
+    vigra::MultiArray<DIM,RealPromotePixelType> varImage(image.shape());
+    vigra::MultiArray<DIM,RealPromotePixelType> estimageImage(image.shape());
+    vigra::MultiArray<DIM,RealPromoteScalarType> labelImage(image.shape());
+
+    // compute mean and variance 
+    // last argument is a "buffer" since within "gaussianMeanAndVariance" another array is needed
+    // ==> to avoid an unnecessary allocation we use the estimageImage as a buffer
+    //gaussianMeanAndVariance<DIM,PixelTypeIn,RealPromotePixelType>(image,param.sigmaMean_,meanImage,varImage,estimageImage);
+    gaussianMeanAndVariance<DIM,PixelTypeIn,RealPromotePixelType>(image,param.sigmaMean_,meanImage,varImage);
+
+    // initialize
+    labelImage = RealPromoteScalarType(0.0);
+    estimageImage = RealPromotePixelType(0.0);
+
+    ///////////////////////////////////////////////////////////////
+    {   // MULTI THREAD CODE STARTS HERE
+
+
+
+        typedef threading::thread  ThreadType;
+        typedef threading::mutex   MutexType;
+
+        MutexType estimateMutex;
+        //typedef boost::thread ThreadType;
+
+        const size_t nThreads =  param.nThreads_;
+        MultiArray<1,int> progress = MultiArray<1,int>(typename  MultiArray<1,int>::difference_type(nThreads));
+
+        // allocate all thread objects
+        // each thread object works on a portion of the data
+        std::vector<ThreadObjectType> threadObjects(nThreads, 
+            ThreadObjectType(image, meanImage, varImage, estimageImage, labelImage, 
+                smoothPolicy, param, nThreads, estimateMutex,progress)
+        );
+
+        // thread ptr
+        std::vector<ThreadType *> threadPtrs(nThreads);
+        for(size_t i=0; i<nThreads; ++i){
+            ThreadObjectType & threadObj = threadObjects[i];
+            threadObj.setThreadIndex(i);
+            typename ThreadObjectType::RangeType lastAxisRange;
+            lastAxisRange[0]=(i * image.shape(DIM-1)) / nThreads;
+            lastAxisRange[1]=((i+1) * image.shape(DIM-1)) / nThreads;
+            threadObj.setRange(lastAxisRange);
+            // this will start the threads and cal operator() 
+            // of the threadObjects
+            threadPtrs[i] = new ThreadType(threadObjects[i]);
+        }
+        for(size_t i=0; i<nThreads; ++i)
+            threadPtrs[i]->join();
+        for(size_t i=0; i<nThreads; ++i)
+            delete threadPtrs[i];
+
+    }   // MULTI THREAD CODE ENDS HERE
+    ///////////////////////////////////////////////////////////////
+
+    // normalize estimates by the number of labels
+    // and write that in output
+    for(int scanOrderIndex=0; scanOrderIndex<labelImage.size(); ++scanOrderIndex){
+        if (labelImage[scanOrderIndex] <= RealPromoteScalarType(0.00001))
+            outImage[scanOrderIndex]=image[scanOrderIndex];
+        else
+            outImage[scanOrderIndex]=estimageImage[scanOrderIndex] / labelImage[scanOrderIndex];
+    }
+}
+
+}
+
+template<int DIM, class PIXEL_TYPE_IN,class PIXEL_TYPE_OUT,class SMOOTH_POLICY>
+void nonLocalMean(
+    const vigra::MultiArrayView<DIM,PIXEL_TYPE_IN> & image,
+    const SMOOTH_POLICY & smoothPolicy,
+    const NonLocalMeanParameter param,
+    vigra::MultiArrayView<DIM,PIXEL_TYPE_OUT> outImage
+){
+    detail_non_local_means::nonLocalMean1Run<DIM,PIXEL_TYPE_IN,PIXEL_TYPE_OUT,SMOOTH_POLICY>(image,smoothPolicy,param,outImage);
+    if(param.iterations_>1){
+
+        vigra::MultiArray<DIM,PIXEL_TYPE_OUT> tmp(outImage.shape());        
+        for(size_t i=0;i<param.iterations_-1;++i){
+            tmp=outImage;
+            detail_non_local_means::nonLocalMean1Run<DIM,PIXEL_TYPE_OUT,PIXEL_TYPE_OUT,SMOOTH_POLICY>(tmp,smoothPolicy,param,outImage);
+        }
+    }
+}
+
+
+
+
+} // end namespace vigra
+
+
+#endif
diff --git a/include/vigra/numerictraits.hxx b/include/vigra/numerictraits.hxx
index 994353c..c6eacc6 100644
--- a/include/vigra/numerictraits.hxx
+++ b/include/vigra/numerictraits.hxx
@@ -152,14 +152,12 @@
     <tr><td>
     <b> <TT>typedef ... Type;</TT></b>
     </td><td>
-    
             the type itself 
         
     </td></tr>
     <tr><td>
     <b> <TT>typedef ... Promote;</TT></b>
     </td><td>
-    
             promote type for addition and subtraction 
         
     </td></tr>
@@ -174,14 +172,12 @@
     <tr><td>
     <b> <TT>typedef ... ComplexPromote;</TT></b>
     </td><td>
-    
             promote type for complex arithmetic 
         
     </td></tr>
     <tr><td>
     <b> <TT>typedef ... ValueType;</TT></b>
     </td><td>
-    
             for scalar types: the type itself<br>
             otherwise: typename Type::value_type (if defined)
         
diff --git a/include/vigra/numpy_array.hxx b/include/vigra/numpy_array.hxx
index d8264bc..f94f73d 100644
--- a/include/vigra/numpy_array.hxx
+++ b/include/vigra/numpy_array.hxx
@@ -153,6 +153,76 @@ constructArray(TaggedShape tagged_shape, TYPECODE typeCode, bool init,
                python_ptr arraytype = python_ptr());
 
 /********************************************************/
+
+template <class Shape>
+void numpyParseSlicing(Shape const & shape, PyObject * idx, Shape & start, Shape & stop)
+{
+    int N = shape.size();
+    for(int k=0; k<N; ++k)
+    {
+        start[k] = 0;
+        stop[k] = shape[k];
+    }
+    
+    python_ptr index(idx);
+    if(!PySequence_Check(index))
+    {
+        index = python_ptr(PyTuple_Pack(1, index.ptr()), python_ptr::new_nonzero_reference);
+    }
+    int lindex = PyTuple_Size(index);
+    int kindex = 0;
+    for(; kindex<lindex; ++kindex)
+    {
+        if(PyTuple_GET_ITEM((PyTupleObject *)index.ptr(), kindex) == Py_Ellipsis)
+            break;
+    }
+    if(kindex == lindex && lindex < N)
+    {
+        python_ptr ellipsis = python_ptr(PyTuple_Pack(1, Py_Ellipsis), python_ptr::new_nonzero_reference);
+        index = python_ptr(PySequence_Concat(index, ellipsis), python_ptr::new_nonzero_reference);
+        ++lindex;
+    }
+    kindex = 0;
+    for(int k=0; k < N; ++k)
+    {
+        PyObject * item = PyTuple_GET_ITEM((PyTupleObject *)index.ptr(), kindex);
+        if(PyInt_Check(item))
+        {
+            MultiArrayIndex i = PyInt_AsLong(item);
+            start[k] = i;
+            if(start[k] < 0)
+                start[k] += shape[k];
+            stop[k] = start[k];
+            ++kindex;
+        }
+        else if(PySlice_Check(item))
+        {
+            Py_ssize_t sstart, sstop, step;
+            if(PySlice_GetIndices((PySliceObject *)item, shape[k], &sstart, &sstop, &step) != 0)
+                pythonToCppException(0);
+            vigra_precondition(step == 1,
+                "numpyParseSlicing(): only unit steps are supported.");
+            start[k] = sstart;
+            stop[k] = sstop;
+            ++kindex;
+        }
+        else if(item == Py_Ellipsis)
+        {
+            if(lindex == N)
+                ++kindex;
+            else
+                ++lindex;
+        }
+        else
+        {
+            vigra_precondition(false,
+                "numpyParseSlicing(): unsupported index object.");
+        }
+    }
+}
+
+
+/********************************************************/
 /*                                                      */
 /*                    NumpyAnyArray                     */
 /*                                                      */
@@ -400,6 +470,50 @@ class NumpyAnyArray
             return PyArray_DESCR(pyArray())->type_num;
         return -1;
     }
+    
+        /**
+         Constructs a slicing from the given shape objects and calls '__getitem__'.
+         */
+    template <class Shape>
+    NumpyAnyArray
+    getitem(Shape start, Shape stop) const
+    {
+        unsigned int size = ndim();
+        vigra_precondition(start.size() == size && stop.size() == size,
+            "NumpyAnyArray::getitem(): shape has wrong dimension.");
+        
+        difference_type s(this->shape());
+        
+        python_ptr index(PyTuple_New(size), python_ptr::new_nonzero_reference);
+        for(unsigned int k=0; k<size; ++k)
+        {
+            if(start[k] < 0)
+                start[k] += s[k];
+            if(stop[k] < 0)
+                stop[k] += s[k];
+            vigra_precondition(0 <= start[k] && start[k] <= stop[k] && stop[k] <= s[k],
+                "NumpyAnyArray::getitem(): slice out of bounds.");
+            PyObject * item = 0;
+            if(start[k] == stop[k])
+            {
+                item = PyInt_FromLong(start[k]);
+            }
+            else
+            {
+                python_ptr s0(PyInt_FromLong(start[k]), python_ptr::new_nonzero_reference);
+                python_ptr s1(PyInt_FromLong(stop[k]), python_ptr::new_nonzero_reference);
+                item = PySlice_New(s0, s1, 0);
+            }
+            pythonToCppException(item);
+            PyTuple_SET_ITEM((PyTupleObject *)index.ptr(), k, item); // steals reference to item
+        }
+        
+        python_ptr func(PyString_FromString("__getitem__"), python_ptr::new_nonzero_reference);
+        python_ptr res(PyObject_CallMethodObjArgs(pyObject(), func.ptr(), index.ptr(), NULL),
+                       python_ptr::new_nonzero_reference);
+        return NumpyAnyArray(res.ptr());
+    }
+
 
         /**
          * Return the AxisTags of this array or a NULL pointer when the attribute
@@ -584,7 +698,7 @@ python_ptr constructNumpyArrayFromData(
 /** Provide the MultiArrayView interface for a Python array.
 
     This class inherits from both \ref vigra::MultiArrayView and \ref vigra::NumpyAnyArray
-    in order to support easy and save application of VIGRA functions to Python arrays.
+    in order to support easy and safe application of VIGRA functions to Python arrays.
 
     <b>\#include</b> \<vigra/numpy_array.hxx\><br>
     Namespace: vigra
diff --git a/include/vigra/numpy_array_converters.hxx b/include/vigra/numpy_array_converters.hxx
index c27716b..02825b1 100644
--- a/include/vigra/numpy_array_converters.hxx
+++ b/include/vigra/numpy_array_converters.hxx
@@ -65,13 +65,13 @@ struct NumpyArrayConverter<NumpyArray<N, T, Stride> >
 {
     typedef NumpyArray<N, T, Stride> ArrayType;
     typedef typename ArrayType::ArrayTraits ArrayTraits;
-    
+
     NumpyArrayConverter();
-        
+
     static void* convertible(PyObject* obj);
 
     // from Python
-    static void construct(PyObject* obj, 
+    static void construct(PyObject* obj,
         boost::python::converter::rvalue_from_python_stage1_data* data);
 
     // to Python
@@ -85,9 +85,9 @@ template <unsigned int N, class T, class Stride>
 NumpyArrayConverter<NumpyArray<N, T, Stride> >::NumpyArrayConverter()
 {
     using namespace boost::python;
-    
+
     converter::registration const * reg = converter::registry::query(type_id<ArrayType>());
-    
+
     // register the to_python_converter only once
     // FIXME: I'm not sure if this is correct.
     if(!reg || !reg->rvalue_chain)
@@ -96,7 +96,7 @@ NumpyArrayConverter<NumpyArray<N, T, Stride> >::NumpyArrayConverter()
     }
     converter::registry::insert(&convertible, &construct, type_id<ArrayType>());
 }
-    
+
 template <unsigned int N, class T, class Stride>
 void * NumpyArrayConverter<NumpyArray<N, T, Stride> >::convertible(PyObject* obj)
 {
@@ -109,10 +109,10 @@ void * NumpyArrayConverter<NumpyArray<N, T, Stride> >::convertible(PyObject* obj
 
 // from Python
 template <unsigned int N, class T, class Stride>
-void NumpyArrayConverter<NumpyArray<N, T, Stride> >::construct(PyObject* obj, 
+void NumpyArrayConverter<NumpyArray<N, T, Stride> >::construct(PyObject* obj,
                    boost::python::converter::rvalue_from_python_stage1_data* data)
 {
-    void* const storage =   
+    void* const storage =
         ((boost::python::converter::rvalue_from_python_storage<ArrayType>* ) data)->storage.bytes;
 
     ArrayType * array = new (storage) ArrayType();
@@ -128,11 +128,11 @@ struct NumpyArrayConverter<MultiArrayView<N, T, Stride> >
 {
     typedef NumpyArrayConverter<NumpyArray<N, T, Stride> > BaseType;
     typedef MultiArrayView<N, T, Stride> ArrayType;
-    
+
     NumpyArrayConverter()
     {
         using namespace boost::python;
-        converter::registry::insert(&BaseType::convertible, &BaseType::construct, 
+        converter::registry::insert(&BaseType::convertible, &BaseType::construct,
                                     type_id<ArrayType>());
     }
 };
@@ -158,7 +158,7 @@ struct RegisterNumpyArrayConverters<End, End>
 template <class Typelist>
 void registerNumpyArrayConverters(Typelist)
 {
-    RegisterNumpyArrayConverters<typename boost::mpl::begin<Typelist>::type, 
+    RegisterNumpyArrayConverters<typename boost::mpl::begin<Typelist>::type,
                                  typename boost::mpl::end<Typelist>::type >::exec();
 }
 
@@ -238,6 +238,71 @@ struct functor_name \
          boost::python::TypeList<void, void> > > > > > > > > > > > > \
 {};
 
+#define VIGRA_PYTHON_MULTITYPE_FUNCTOR_NDIM(functor_name, function) \
+template <class T, int N> \
+struct functor_name##Impl \
+{ \
+    typedef functor_name##Impl type; \
+     \
+    static void def(const char * pythonName) \
+    { \
+        boost::python::def(pythonName, vigra::registerConverters(&function<T, N>)); \
+    } \
+     \
+    template <class A1> \
+    static void def(const char * pythonName, A1 const & a1) \
+    { \
+        boost::python::def(pythonName, vigra::registerConverters(&function<T, N>), a1); \
+    } \
+     \
+    template <class A1, class A2> \
+    static void def(const char * pythonName, A1 const & a1, A2 const & a2) \
+    { \
+        boost::python::def(pythonName, vigra::registerConverters(&function<T, N>), a1, a2); \
+    } \
+     \
+    template <class A1, class A2, class A3> \
+    static void def(const char * pythonName, A1 const & a1, A2 const & a2, A3 const & a3) \
+    { \
+        boost::python::def(pythonName, vigra::registerConverters(&function<T, N>), a1, a2, a3); \
+    } \
+}; \
+ \
+template <int N> \
+struct functor_name##Impl<void, N> \
+{ \
+    typedef void type; \
+}; \
+ \
+template <int N, \
+          class T1, \
+          class T2 = void, \
+          class T3 = void, \
+          class T4 = void, \
+          class T5 = void, \
+          class T6 = void, \
+          class T7 = void, \
+          class T8 = void, \
+          class T9 = void, \
+          class T10 = void, \
+          class T11 = void, \
+          class T12 = void> \
+struct functor_name \
+: public boost::python::TypeList<typename functor_name##Impl<T1, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T2, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T3, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T4, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T5, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T6, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T7, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T8, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T9, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T10, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T11, N>::type, \
+         boost::python::TypeList<typename functor_name##Impl<T12, N>::type, \
+         boost::python::TypeList<void, void> > > > > > > > > > > > > \
+{};
+
 template <class Head, class Tail>
 struct TypeList
 {
diff --git a/include/vigra/numpy_array_taggedshape.hxx b/include/vigra/numpy_array_taggedshape.hxx
index f328bd0..44a9ae0 100644
--- a/include/vigra/numpy_array_taggedshape.hxx
+++ b/include/vigra/numpy_array_taggedshape.hxx
@@ -574,57 +574,74 @@ class TaggedShape
     template <class U, int N>
     TaggedShape & transposeShape(TinyVector<U, N> const & p)
     {
-        int ntags = axistags.size();
-        ArrayVector<npy_intp> permute = axistags.permutationToNormalOrder();
-        
-        int tstart = (axistags.channelIndex(ntags) < ntags)
-                        ? 1
-                        : 0;
-        int sstart = (channelAxis == first)
-                        ? 1
-                        : 0;
-        int ndim = ntags - tstart;
-
-        vigra_precondition(N == ndim,
-             "TaggedShape.transposeShape(): size mismatch.");
-             
-        PyAxisTags newAxistags(axistags.axistags); // force copy
-        for(int k=0; k<ndim; ++k)
+        if(axistags)
+        {
+            int ntags = axistags.size();
+            ArrayVector<npy_intp> permute = axistags.permutationToNormalOrder();
+            
+            int tstart = (axistags.channelIndex(ntags) < ntags)
+                            ? 1
+                            : 0;
+            int sstart = (channelAxis == first)
+                            ? 1
+                            : 0;
+            int ndim = ntags - tstart;
+
+            vigra_precondition(N == ndim,
+                 "TaggedShape.transposeShape(): size mismatch.");
+                 
+            PyAxisTags newAxistags(axistags.axistags); // force copy
+            for(int k=0; k<ndim; ++k)
+            {
+                original_shape[k+sstart] = shape[p[k]+sstart];
+                newAxistags.setResolution(permute[k+tstart], axistags.resolution(permute[p[k]+tstart]));
+            }
+            axistags = newAxistags;
+        }
+        else
         {
-            original_shape[k+sstart] = shape[p[k]+sstart];
-            newAxistags.setResolution(permute[k+tstart], axistags.resolution(permute[p[k]+tstart]));
+            for(int k=0; k<N; ++k)
+            {
+                original_shape[k] = shape[p[k]];
+            }
         }
         shape = original_shape;
-        axistags = newAxistags;
         
         return *this;
     }
 
     TaggedShape & toFrequencyDomain(int sign = 1)
     {
-        int ntags = axistags.size();
-        
-        ArrayVector<npy_intp> permute = axistags.permutationToNormalOrder();
-        
-        int tstart = (axistags.channelIndex(ntags) < ntags)
-                        ? 1
-                        : 0;
-        int sstart = (channelAxis == first)
-                        ? 1
-                        : 0;
-        int send  = (channelAxis == last)
-                        ? (int)size()-1
-                        : (int)size();
-        int size = send - sstart;
-        
-        for(int k=0; k<size; ++k)
+        if(axistags)
         {
-            axistags.toFrequencyDomain(permute[k+tstart], shape[k+sstart], sign);
+            int ntags = axistags.size();
+            
+            ArrayVector<npy_intp> permute = axistags.permutationToNormalOrder();
+            
+            int tstart = (axistags.channelIndex(ntags) < ntags)
+                            ? 1
+                            : 0;
+            int sstart = (channelAxis == first)
+                            ? 1
+                            : 0;
+            int send  = (channelAxis == last)
+                            ? (int)size()-1
+                            : (int)size();
+            int size = send - sstart;
+            
+            for(int k=0; k<size; ++k)
+            {
+                axistags.toFrequencyDomain(permute[k+tstart], shape[k+sstart], sign);
+            }
         }
-        
         return *this;
     }
 
+    bool hasChannelAxis() const
+    {
+        return channelAxis !=none;
+    }
+
     TaggedShape & fromFrequencyDomain()
     {
         return toFrequencyDomain(-1);
diff --git a/include/vigra/numpy_array_traits.hxx b/include/vigra/numpy_array_traits.hxx
index 1352d21..6b56249 100644
--- a/include/vigra/numpy_array_traits.hxx
+++ b/include/vigra/numpy_array_traits.hxx
@@ -43,7 +43,6 @@
 #include "numerictraits.hxx"
 #include "multi_array.hxx"
 #include "numpy_array_taggedshape.hxx"
-
 namespace vigra {
 
 /********************************************************/
@@ -112,6 +111,7 @@ struct NumpyArrayValuetypeTraits<type > \
     } \
 };
 
+
 VIGRA_NUMPY_VALUETYPE_TRAITS(bool,           NPY_BOOL, bool, "UINT8")
 VIGRA_NUMPY_VALUETYPE_TRAITS(signed char,    NPY_INT8, int8, "INT16")
 VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned char,  NPY_UINT8, uint8, "UINT8")
diff --git a/include/vigra/overlapped_blocks.hxx b/include/vigra/overlapped_blocks.hxx
new file mode 100644
index 0000000..0f1c470
--- /dev/null
+++ b/include/vigra/overlapped_blocks.hxx
@@ -0,0 +1,213 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_OVERLAPPED_BLOCKS_HXX
+#define VIGRA_OVERLAPPED_BLOCKS_HXX
+
+#include <utility>
+#include <algorithm>
+
+#include <vigra/multi_array.hxx>
+#include <vigra/multi_array_chunked.hxx>
+
+namespace vigra
+{
+
+namespace overlapped_blocks_detail
+{
+
+template <class Shape>
+std::pair<Shape, Shape> blockBoundsAt(const Shape& coordinates, const Shape& global_shape, const Shape& block_shape)
+{
+    Shape block_begin;
+    for(int i = 0; i != Shape::static_size; ++i)
+    {
+        block_begin[i] = coordinates[i] * block_shape[i];
+        vigra_assert(block_begin[i] < global_shape[i], "block coordinates out of bounds");
+    }
+    Shape block_end;
+    for(int i = 0; i != Shape::static_size; ++i)
+    {
+        block_end[i] = std::min(block_begin[i] + block_shape[i], global_shape[i]);
+    }
+    return std::make_pair(block_begin, block_end);
+}
+
+template <class Shape>
+std::pair<Shape, Shape> overlapBoundsAt(const std::pair<Shape, Shape>& block_bounds, const Shape& global_shape,
+                                        const Shape& overlap_before, const Shape& overlap_after)
+{
+    Shape overlapped_block_begin = block_bounds.first;
+    Shape overlapped_block_end = block_bounds.second;
+    for(int i = 0; i != Shape::static_size; ++i)
+    {
+        if(overlapped_block_begin[i] >= overlap_before[i])
+            overlapped_block_begin[i] -= overlap_before[i];
+        else
+            overlapped_block_begin[i] = 0;
+
+        if(overlapped_block_end[i] <= global_shape[i] - overlap_after[i])
+            overlapped_block_end[i] += overlap_after[i];
+        else
+            overlapped_block_end[i] = global_shape[i];
+    }
+    return std::make_pair(overlapped_block_begin, overlapped_block_end);
+}
+
+template <class Shape>
+Shape blocksShape(const Shape& global_shape, const Shape& block_shape)
+{
+    Shape result;
+    for(int i = 0; i != Shape::static_size; ++i)
+    {
+        result[i] = global_shape[i] / block_shape[i];
+        if(block_shape[i] * result[i] != global_shape[i])
+            ++result[i];
+    }
+    return result;
+
+}
+
+} // namespace overlapped_blocks_detail
+
+template <class Shape>
+inline bool 
+within(const Shape& coordinates, const std::pair<Shape, Shape>& bounds)
+{
+    return allLessEqual(bounds.first, coordinates) && allLess(coordinates, bounds.second);
+}
+
+template <class ArrayType>
+struct OverlappingBlock;
+
+template <class ArrayType>
+class Overlaps;
+
+template <unsigned int N, class T, class S>
+struct OverlappingBlock<MultiArrayView<N, T, S> >
+{
+    typedef typename MultiArrayView<N, T, S>::difference_type Shape;
+
+    MultiArrayView<N, T, S> block;
+    std::pair<Shape, Shape> inner_bounds;
+};
+
+template <unsigned int N, class T, class S>
+class Overlaps<MultiArrayView<N, T, S> >
+{
+private:
+    typedef MultiArrayView<N, T, S> View;
+    typedef typename View::difference_type Shape;
+
+    View view;
+    Shape block_shape;
+    Shape overlap_before;
+    Shape overlap_after;
+public:
+    Overlaps(View view, const Shape& block_shape, const Shape& overlap_before, const Shape& overlap_after)
+    : view(view),
+      block_shape(block_shape),
+      overlap_before(overlap_before),
+      overlap_after(overlap_after)
+    {}
+    OverlappingBlock<View> operator[](const Shape& coordinates) const
+    {
+        using namespace overlapped_blocks_detail;
+        std::pair<Shape, Shape> block_bounds = blockBoundsAt(coordinates, view.shape(), block_shape);
+        std::pair<Shape, Shape> overlap_bounds = overlapBoundsAt(block_bounds, view.shape(), overlap_before, overlap_after);
+
+        OverlappingBlock<View> result;
+        result.block = view.subarray(overlap_bounds.first, overlap_bounds.second);
+        result.inner_bounds = std::make_pair(block_bounds.first - overlap_bounds.first, block_bounds.second - overlap_bounds.first);
+        return result;
+    }
+    Shape shape() const
+    {
+        using namespace overlapped_blocks_detail;
+        return blocksShape(view.shape(), block_shape);
+    }
+};
+
+template <unsigned int N, class T>
+struct OverlappingBlock<ChunkedArray<N, T> >
+{
+    typedef typename MultiArrayShape<N>::type Shape;
+
+    MultiArray<N, T> block;
+    std::pair<Shape, Shape> inner_bounds;
+};
+
+template <unsigned int N, class T>
+class Overlaps<ChunkedArray<N, T> >
+{
+private:
+    typedef ChunkedArray<N, T> Array;
+    typedef typename MultiArrayShape<N>::type Shape;
+
+    const Array& array;
+    Shape block_shape;
+    Shape overlap_before;
+    Shape overlap_after;
+public:
+    Overlaps(const Array& array, const Shape& block_shape, const Shape& overlap_before, const Shape& overlap_after)
+    : array(array),
+      block_shape(block_shape),
+      overlap_before(overlap_before),
+      overlap_after(overlap_after)
+    {}
+
+    OverlappingBlock<Array> operator[](const Shape& coordinates) const
+    {
+        using namespace overlapped_blocks_detail;
+        std::pair<Shape, Shape> block_bounds = blockBoundsAt(coordinates, array.shape(), block_shape);
+        std::pair<Shape, Shape> overlap_bounds = overlapBoundsAt(block_bounds, array.shape(), overlap_before, overlap_after);
+
+        OverlappingBlock<Array> result;
+        result.block.reshape(overlap_bounds.second - overlap_bounds.first);
+        array.checkoutSubarray(overlap_bounds.first, result.block);
+        result.inner_bounds = std::make_pair(block_bounds.first - overlap_bounds.first, block_bounds.second - overlap_bounds.first);
+
+        return result;
+    }
+    Shape shape() const
+    {
+        using namespace overlapped_blocks_detail;
+        return blocksShape(array.shape(), block_shape);
+    }
+};
+
+} // namespace vigra
+
+#endif // VIGRA_OVERLAPPED_BLOCKS_HXX
diff --git a/include/vigra/pixelneighborhood.hxx b/include/vigra/pixelneighborhood.hxx
index b4d8f85..72b26d6 100644
--- a/include/vigra/pixelneighborhood.hxx
+++ b/include/vigra/pixelneighborhood.hxx
@@ -1080,9 +1080,9 @@ public:
         /** Construct circulator with given <tt>center</tt> pixel, pointing to the neighbor
             at the given direction <tt>d</tt>.
         */
-    NeighborhoodCirculator(IMAGEITERATOR const & center = IMAGEITERATOR(),
+    NeighborhoodCirculator(IMAGEITERATOR const & aCenter = IMAGEITERATOR(),
                            Direction d = NEIGHBOROFFSETCIRCULATOR::InitialDirection)
-        : IMAGEITERATOR(center), neighborCode_(d)
+        : IMAGEITERATOR(aCenter), neighborCode_(d)
     {
         IMAGEITERATOR::operator+=(neighborCode_.diff());
     }
diff --git a/include/vigra/polygon.hxx b/include/vigra/polygon.hxx
index b103772..c535172 100644
--- a/include/vigra/polygon.hxx
+++ b/include/vigra/polygon.hxx
@@ -42,20 +42,20 @@
 #include <algorithm>
 #include "config.hxx"
 #include "error.hxx"
+#include "tinyvector.hxx"
 #include "array_vector.hxx"
+#include "gaussians.hxx"
+#include "splines.hxx"
+#include "linear_solve.hxx"
 
 namespace vigra {
 
-/** \addtogroup MathFunctions
-*/
-//@{
-
 namespace detail {
 
 template < class Point >    
-bool sortPoints(Point const & p1, Point const & p2) 
+bool pointYXOrdering(Point const & p1, Point const & p2) 
 {
-    return (p1[0]<p2[0]) || (p1[0] == p2[0] && p1[1] < p2[1]);
+    return (p1[1]<p2[1]) || (p1[1] == p2[1] && p1[0] < p2[0]);
 }
 
 template < class Point >    
@@ -67,6 +67,761 @@ bool orderedClockwise(const Point &O, const Point &A, const Point &B)
 } // namespace detail
 
 
+/** \addtogroup Geometry
+*/
+//@{
+
+    /** Polygons in two and higher dimenions.
+    
+    */
+template<class POINT=TinyVector<double, 2> >
+class Polygon 
+: protected ArrayVector<POINT>
+{
+  public:
+    typedef ArrayVector<POINT> Base;
+
+    typedef POINT                                 Point;
+    typedef typename Base::value_type             value_type;
+    typedef typename Base::reference              reference;
+    typedef typename Base::const_reference        const_reference;
+    typedef typename Base::pointer                pointer;
+    typedef typename Base::const_pointer          const_pointer;
+    typedef typename Base::iterator               iterator;
+    typedef typename Base::const_iterator         const_iterator;
+    typedef typename Base::reverse_iterator       reverse_iterator;
+    typedef typename Base::const_reverse_iterator const_reverse_iterator;
+    typedef typename Base::size_type              size_type;
+    typedef typename Base::difference_type        difference_type;
+    typedef typename POINT::value_type            coordinate_type;
+    
+    using Base::size;
+    using Base::empty;
+    using Base::begin;
+    using Base::end;
+    using Base::cbegin;
+    using Base::cend;
+    using Base::rbegin;
+    using Base::rend;
+    using Base::crbegin;
+    using Base::crend;
+
+    // use default copy constructor
+
+    Polygon()
+    : length_(0.0),
+      lengthValid_(false),
+      partialArea_(0.0),
+      partialAreaValid_(false)
+    {}
+
+    Polygon(size_type n)
+    : Base(n, Point()),
+      lengthValid_(false),
+      partialAreaValid_(false)
+    {}
+
+    template <class InputIterator>
+    Polygon(InputIterator b, InputIterator e)
+    : Base(b, e),
+      lengthValid_(false),
+      partialAreaValid_(false)
+    {}
+    
+    void clear()
+    {
+        invalidateProperties();
+        Base::clear();
+    }
+
+    void invalidateProperties()
+    {
+        lengthValid_ = false;
+        partialAreaValid_ = false;
+    }
+
+    double length() const
+    {
+        if(!lengthValid_)
+        {
+            length_ = 0.0;
+            for(unsigned int i = 1; i < size(); ++i)
+                length_ += ((*this)[i] - (*this)[i-1]).magnitude();
+            lengthValid_ = true;
+        }
+        return length_;
+    }
+
+    double partialArea() const
+    {
+        if(!partialAreaValid_)
+        {
+            partialArea_ = 0.0;
+            for(unsigned int i = 1; i < size(); ++i)
+                partialArea_ += ((*this)[i][0]*(*this)[i-1][1] -
+                                 (*this)[i][1]*(*this)[i-1][0]);
+            partialArea_ *= 0.5;
+            partialAreaValid_ = true;
+        }
+        return partialArea_;
+    }
+
+    double area() const
+    {
+        vigra_precondition(closed(),
+                           "Polygon::area() requires polygon to be closed!");
+        return abs(partialArea());
+    }
+
+        /// Returns true iff the last and first points are equal or the polygon is empty.
+    bool closed() const
+    {
+        return size() <= 1 || back() == front();
+    }
+
+        /** Linearly interpolate at <tt>offset</tt> between knots 
+            <tt>index</tt> and <tt>index+1</tt>.
+            
+            Preconditions: <tt>0 <= index < size()-1</tt> and <tt>0 <= offset <= 1</tt>.
+        */
+    Point interpolate(unsigned int index, double offset) const
+    {
+        if(index < size() - 1)
+            return (1.0 - offset) * (*this)[index] + offset * (*this)[index+1];
+        else
+            return (*this)[index];
+    }
+
+        /**
+         * Tests whether the given point lies within this polygon.
+         * Requires that this polygon is closed.
+
+         * Points which lie directly on the polylines or coincide with a knot
+         * are considered inside (this behavior is consistent with fillPolygon()).
+         * Parameter \a tolerance (interpreted as an absolute error bound)
+         * controls the numerical accuracy of this test.
+         */
+    bool contains(const_reference point, coordinate_type tolerance) const;
+
+    bool contains(const_reference point) const
+    {
+        return contains(point, 2.0*NumericTraits<coordinate_type>::epsilon());
+    }
+    
+    void push_back(const_reference v)
+    {
+        if(size())
+        {
+            if(lengthValid_)
+                length_ += (v - back()).magnitude();
+            if(partialAreaValid_)
+                partialArea_ += 0.5*(v[0]*back()[1] - v[1]*back()[0]);
+        }
+        push_back_unsafe(v);
+    }
+    
+    void push_back_unsafe(const_reference v)
+    {
+        Base::push_back(v);
+    }
+
+    void extend(const Polygon &other)
+    {
+        if(!other.size())
+            return;
+
+        const_iterator otherBegin(other.begin());
+        if(size())
+        {
+            if(*otherBegin == Base::back())
+            {
+                // don't copy first pixel
+                ++otherBegin;
+            }
+            else
+            {
+                if(lengthValid_)
+                    length_ += (other.front() - Base::back()).magnitude();
+                if(partialAreaValid_)
+                    partialArea_ += (other.front()[0]*Base::back()[1] -
+                                     other.front()[1]*Base::back()[0]);
+            }
+        }
+        if(lengthValid_)
+            length_ += other.length();
+        if(partialAreaValid_)
+            partialArea_ += other.partialArea();
+        Base::insert(Base::end(), otherBegin, other.end());
+    }
+
+    void setPoint(unsigned int pos, const_reference x)
+    {
+        invalidateProperties();
+        Base::operator[](pos) = x;
+    }
+
+        // doesn't call invalidateProperties()
+    void setPointUnsafe(unsigned int pos, const_reference x)
+    {
+        Base::operator[](pos) = x;
+    }
+
+        // alternative, but it will also invalidate if the caller only reads 
+        // reads the return value.
+    // reference operator[](unsigned int pos)
+    // {
+        // invalidateProperties();
+        // return Base::operator[](pos);
+    // }
+
+    const_reference operator[](unsigned int pos) const
+    {
+        return Base::operator[](pos);
+    }
+
+    const_reference front() const
+    {
+        return Base::front();
+    }
+    
+    const_reference back() const
+    {
+        return Base::back();
+    }
+    
+    iterator begin()
+    {
+        invalidateProperties();
+        return Base::begin();
+    }
+    
+    iterator end()
+    {
+        invalidateProperties();
+        return Base::end();
+    }
+    
+    reverse_iterator rbegin()
+    {
+        invalidateProperties();
+        return Base::rbegin();
+    }
+    
+    reverse_iterator rend()
+    {
+        invalidateProperties();
+        return Base::rend();
+    }
+
+    void erase(iterator pos)
+    {
+        invalidateProperties();
+        Base::erase(pos);
+    }
+
+    void erase(iterator pos, iterator end)
+    {
+        invalidateProperties();
+        Base::erase(pos, end);
+    }
+
+    iterator insert(iterator pos, const_reference x)
+    {
+        invalidateProperties();
+        return Base::insert(pos, x);
+    }
+
+    template <class InputIterator>
+    iterator insert(iterator pos, InputIterator i, InputIterator end)
+    {
+        invalidateProperties();
+        return Base::insert(pos, i, end);
+    }
+
+    Polygon split(unsigned int pos)
+    {
+        Polygon result;
+        if(pos == 0)
+        {
+            swap(result);
+        }
+        else if(pos < size())
+        {
+            result.insert(result.begin(), begin() + pos, end());
+            erase(begin() + pos, end());
+        }
+        return result;
+    }
+
+    template <class Sequence>
+    void arcLengthList(Sequence & arcLengths) const
+    {
+        double length = 0.0;
+        arcLengths.push_back(0.0);
+        for(unsigned int i = 1; i < size(); ++i)
+        {
+            length += ((*this)[i] - (*this)[i-1]).magnitude();
+            arcLengths.push_back(length);
+        }
+    }
+    
+        /** Find the point on the polygon that corresponds to the given quantile.
+        
+            \a quantile must be in <tt>[0.0, 1.0]</tt>. The result of this function
+            can be used as input to <tt>interpolate()</tt>. For example,
+            the following code computes the point in the middle of the polygon:
+            
+            \code
+            double c = poly.arcLengthQuantile(0.5);
+            Point center = poly.interpolate((int)floor(c), c - floor(c));
+            \endcode
+        */
+    double arcLengthQuantile(double quantile) const
+    {
+        vigra_precondition(this->size() > 0,
+            "Polygon:.arcLengthQuantile(): polygon is empty.");
+        if(quantile == 0.0 || this->size() == 1)
+            return 0.0;
+        if(quantile == 1.0)
+            return this->size() - 1.0;
+        vigra_precondition(0.0 < quantile && quantile < 1.0,
+            "Polygon:.arcLengthQuantile(): quantile must be between 0 and 1.");
+        ArrayVector<double> arcLength;
+        arcLength.reserve(this->size());
+        arcLengthList(arcLength);
+        double length = quantile*arcLength.back();
+        unsigned int k=0;
+        for(; k<this->size(); ++k)
+            if(arcLength[k] >= length)
+                break;
+        --k;
+        return k + (length - arcLength[k]) / (arcLength[k+1] - arcLength[k]);
+    }
+
+    void swap(Polygon &rhs)
+    {
+        Base::swap(rhs);
+        std::swap(length_, rhs.length_);
+        std::swap(lengthValid_, rhs.lengthValid_);
+        std::swap(partialArea_, rhs.partialArea_);
+        std::swap(partialAreaValid_, rhs.partialAreaValid_);
+    }
+
+    void reverse()
+    {
+        std::reverse(Base::begin(), Base::end());
+        if(partialAreaValid_)
+            partialArea_ = -partialArea_;
+    }
+
+    POINT nearestPoint(const_reference p) const;
+    
+    Polygon & operator+=(POINT const & offset)
+    {
+        if(!closed())
+            partialAreaValid_ = false;
+        for(unsigned int i = 0; i < size(); ++i)
+            Base::operator[](i) += offset;
+        return *this;
+    }
+
+    Polygon & operator-=(POINT const & offset)
+    {
+        if(!closed())
+            partialAreaValid_ = false;
+        for(unsigned int i = 0; i < size(); ++i)
+            Base::operator[](i) -= offset;
+        return *this;
+    }
+
+    Polygon & operator*=(double scale)
+    {
+        partialArea_ *= sq(scale);
+        length_ *= scale;
+        for(unsigned int i = 0; i < size(); ++i)
+            Base::operator[](i) *= scale;
+        return *this;
+    }
+
+    Polygon & operator/=(double scale)
+    {
+        partialArea_ /= sq(scale);
+        length_ /= scale;
+        for(unsigned int i = 0; i < size(); ++i)
+            Base::operator[](i) /= scale;
+        return *this;
+    }
+
+    bool operator==(Polygon const & rhs) const
+    {
+        if(size() != rhs.size())
+            return false;
+        for(size_type k=0; k<size(); ++k)
+            if((*this)[k] != rhs[k])
+                return false;
+        return true;
+    }
+
+    bool operator!=(Polygon const & rhs) const
+    {
+        return !((*this) == rhs);
+    }
+    
+  protected:
+    
+    mutable double length_;
+    mutable bool lengthValid_;
+    mutable double partialArea_;
+    mutable bool partialAreaValid_;
+};
+
+template <class POINT>
+POINT Polygon<POINT>::nearestPoint(const_reference p) const
+{
+    double dist = NumericTraits<double>::max();
+    POINT r;
+    for(unsigned int k=1; k<size(); ++k)
+    {
+        POINT dp = (*this)[k] - (*this)[k-1];
+        POINT dc = p - (*this)[k-1];
+        double t = dot(dp, dc);
+        if(t != 0.0)
+            t /= squaredNorm(dp);
+        if(t > 1.0)
+        {
+            double d = norm((*this)[k]-p);
+            if (d < dist)
+            {
+                dist = d;
+                r = (*this)[k];
+            }
+        }
+        else if(t < 0.0)
+        {
+            double d = norm((*this)[k-1]-p);
+            if (d < dist)
+            {
+                dist = d;
+                r = (*this)[k-1];
+            }
+        }
+        else
+        {
+            POINT pp = (*this)[k-1] + t*dp;
+            double d = norm(pp-p);
+            if (d < dist)
+            {
+                dist = d;
+                r = pp;
+            }
+        }
+    }
+    return r;
+}
+
+template <class POINT>
+bool 
+Polygon<POINT>::contains(const_reference point, 
+                         coordinate_type tolerance) const
+{
+    typedef typename Polygon<POINT>::Base Base;
+    vigra_precondition(closed(),
+                       "Polygon::contains() requires polygon to be closed!");
+    
+    // NOTE: the following code is very similar to detail::createScanIntervals()
+    //       to ensure consistent results.
+    
+    Polygon p = (*this) - point; // shift the polygon so that we only need to test
+                                 // for intersections with scanline 0
+    int n = p.size();
+    for(int k=0; k<n; ++k)
+        if(closeAtTolerance(p[k][1], 0.0, tolerance))
+            ((Base&)p)[k][1] = 0.0;
+        
+    int result = 0;
+    bool drop_next_start_point = false;
+    int first_point_maybe_dropped = -1;
+    for(int k=0; k<n-1; ++k)
+    {
+        Point const & p1 = p[k];
+        Point const & p2 = p[k+1];
+        
+        if(p1[1] == p2[1]) // ignore horizontal lines
+            continue;
+
+        double t = (p2[0] - p1[0]) / (p2[1] - p1[1]);
+        double y, yend, dy;
+        if(p1[1] < p2[1])
+        {
+            y = ceil(p1[1]);
+            yend = floor(p2[1]);
+            dy = 1.0;
+        }
+        else
+        {
+            y = floor(p1[1]);
+            yend = ceil(p2[1]);
+            dy = -1.0;
+        }
+        if(yend != p2[1])
+            yend += dy;
+        if(drop_next_start_point)
+        {
+            y += dy;
+            drop_next_start_point = false;
+        }
+        if(first_point_maybe_dropped == -1)
+        {
+            if(y == 0.0 && p1[0] - p1[1]*t < 0.0)
+                first_point_maybe_dropped = 1;
+            else
+                first_point_maybe_dropped = 0;
+        }
+        if(y*dy <= 0.0 && yend*dy > 0.0)  // intersects scanline 0
+        {
+            double x = p1[0] - p1[1]*t;
+            if(closeAtTolerance(x, 0.0, tolerance))
+                return true;
+            if(x < 0.0)
+                ++result;
+        }
+        else if(p2[1] == 0.0) // degenerate case
+        {
+            int j = (k+2)%n;
+            bool convex = detail::orderedClockwise(p1, p2, p[j]);
+            if(convex) 
+            {
+                double x = p2[0] - p2[1]*t;
+                if(closeAtTolerance(x, 0.0, tolerance))
+                    return true;
+                if(x < 0.0)
+                    ++result;
+            }
+            for(; j != k+1; j = (j+1)%n)
+            {
+                double bend = dy*(p[j][1] - yend);
+                if(bend == 0.0)
+                    continue;
+                // Drop startpoint of next segment when the polygon after a convex 
+                // degenerate knot eventually crosses the scanline, or when it 
+                // returns to the original side of the scanline after a concave 
+                // degenerate knot.
+                if((convex && bend > 0.0) || (!convex && bend < 0.0))
+                    drop_next_start_point = true;
+                break;
+            }
+        }
+    }
+    
+    if(drop_next_start_point && first_point_maybe_dropped == 1)
+        --result;
+
+    return (result % 2) != 0;
+}
+
+template <class POINT>
+inline Polygon<POINT> round(Polygon<POINT> const & p) 
+{
+    Polygon<POINT> result(p.size());
+    for(unsigned int i = 0; i < p.size(); ++i)
+    {
+        result.setPointUnsafe(i, round(p[i]));
+    }
+    return result;
+}
+
+template <class POINT>
+inline Polygon<TinyVector<std::ptrdiff_t, 2> > roundi(Polygon<POINT> const & p) 
+{
+    Polygon<TinyVector<std::ptrdiff_t, 2> > result(p.size());
+    for(unsigned int i = 0; i < p.size(); ++i)
+    {
+        result.setPointUnsafe(i,roundi(p[i]));
+    }
+    return result;
+}
+
+template <class POINT>
+inline Polygon<POINT> 
+operator+(Polygon<POINT> const & p, POINT const & offset)
+{
+    return Polygon<POINT>(p) += offset;
+}
+
+template <class POINT>
+inline Polygon<POINT> 
+operator+(POINT const & offset, Polygon<POINT> const & p)
+{
+    return Polygon<POINT>(p) += offset;
+}
+
+template <class POINT>
+inline Polygon<POINT> 
+operator-(Polygon<POINT> const & p)
+{
+    Polygon<POINT> result(p.size());
+    for(unsigned int i = 0; i < p.size(); ++i)
+        result.setPointUnsafe(i, -p[i]);
+    return result;
+}
+
+template <class POINT>
+inline Polygon<POINT> 
+operator-(Polygon<POINT> const & p, POINT const & offset)
+{
+    return Polygon<POINT>(p) -= offset;
+}
+
+template <class POINT>
+inline Polygon<POINT> 
+operator*(Polygon<POINT> const & p, double scale)
+{
+    return Polygon<POINT>(p) *= scale;
+}
+
+template <class POINT>
+inline Polygon<POINT> 
+operator*(double scale, Polygon<POINT> const & p)
+{
+    return Polygon<POINT>(p) *= scale;
+}
+
+
+template <class POINT>
+inline Polygon<POINT> 
+operator/(Polygon<POINT> const & p, double scale)
+{
+    return Polygon<POINT>(p) /= scale;
+}
+
+template <class POINT>
+inline Polygon<POINT> 
+transpose(Polygon<POINT> const & p)
+{
+    Polygon<POINT> result(p.size());
+    for(unsigned int i = 0; i < p.size(); ++i)
+    {
+        result.setPointUnsafe(i, POINT(p[i][1], p[i][0]));
+    }
+    return result;
+}
+
+template <class POINT>
+inline Polygon<POINT> 
+reverse(Polygon<POINT> const & p)
+{
+    Polygon<POINT> result(p);
+    result.reverse();
+    return result;
+}
+
+template<class Point>
+Point centroid(const Polygon<Point> &polygon)
+{
+    vigra_precondition(polygon.closed(),
+                       "centroid() expects a closed polygon");
+    double a = 0.0;
+    TinyVector<double, 2> result;
+    for(unsigned int i = 1; i < polygon.size(); ++i)
+    {
+        double pa = (polygon[i-1][0]*polygon[i][1] -
+                     polygon[i-1][1]*polygon[i][0]);
+        a += pa;
+        result += (polygon[i-1] + polygon[i])*pa;
+    }
+    return result / (3.0*a);
+}
+
+} // namespace vigra
+
+/********************************************************************/
+
+namespace std {
+
+template<class T>
+void swap(vigra::Polygon<T> &a, vigra::Polygon<T> &b)
+{
+    a.swap(b);
+}
+
+} // namespace std
+
+/********************************************************************/
+
+namespace vigra {
+
+/** \brief Create a polygon from the interpixel contour of a labeled region.
+
+    The point \a anchor_point must be in the region whose contour we want to extract,
+    and must be adjacent to the contour. The algorithm uses the 'left hand on the wall'
+    algorithm to trace the connected component whose label equals the label of the
+    \a anchor_point. The contour is returned in \a countour_points as a closed polygon 
+    that circles the region counter-clockwise in the image coordinate system (i.e. the
+    coordinate system where x points to the right and y points downwards). Since the
+    resulting polygon represents the interpixel contour, all points will have one integer 
+    and one half-integer coordinate.
+*/
+template<class T, class S, class PointArray>
+void 
+extractContour(MultiArrayView<2, T, S> const &label_image,
+               Shape2 const & anchor_point,
+               PointArray & contour_points) 
+{
+    typedef typename PointArray::value_type Point;
+    
+    Shape2 step[4] = { Shape2(0, -1), Shape2(1, 0), Shape2(0, 1), Shape2(-1, 0) };
+    Point contour_offsets[4] = { Point(-0.5, 0), Point(0, -0.5), Point(0.5, 0), Point(0, 0.5) };
+    
+    T foreground = label_image[anchor_point];
+
+    int direction;
+    Shape2 position;
+    // find a position outside the object from which we place the hand
+    for(direction = 3; direction >= 0; --direction)
+    {
+        position = anchor_point + step[(direction + 1) % 4];
+        if(!label_image.isInside(position) || label_image[position] != foreground)
+            break;
+    }
+    
+    vigra_precondition(direction >= 0,
+        "extractContour(): the anchor point must be at the region border.");
+        
+    int initial_direction = direction;
+    Shape2 initial_position = position;
+
+    // go around the object
+    do 
+    {
+        contour_points.push_back(position + contour_offsets[direction]);
+
+        Shape2 next_position = position + step[direction];
+
+        if(label_image.isInside(next_position) && 
+           label_image[next_position] == foreground)
+        {
+            // we have bumped into a wall => turn right to touch the wall again
+            direction = (direction + 1) % 4;
+        }
+        else
+        {
+            position = next_position;
+            int next_direction = (direction + 3) % 4;
+            next_position += step[next_direction];
+            if(!label_image.isInside(next_position) || 
+               label_image[next_position] != foreground)
+            {
+                // we have lost the wall => turn left and move forward to touch the wall again
+                direction = next_direction;
+                position = next_position;
+            }
+        }
+    } 
+    while (position != initial_position || direction != initial_direction);
+    
+    contour_points.push_back(contour_points.front()); // make it a closed polygon
+}
+
 /** \brief Compute convex hull of a 2D polygon.
 
     The input array \a points contains a (not necessarily ordered) set of 2D points
@@ -89,12 +844,15 @@ void convexHull(const PointArray1 &points, PointArray2 & convex_hull)
     
     typedef typename PointArray1::value_type Point;
     
-    ArrayVector<Point> ordered(points.begin(), points.end());
-    std::sort(ordered.begin(), ordered.end(), detail::sortPoints<Point>);
+    typename PointArray1::const_iterator begin = points.begin();
+    if(points.front() == points.back()) // closed polygon
+        ++begin;                        // => remove redundant start point
+    ArrayVector<Point> ordered(begin, points.end());
+    std::sort(ordered.begin(), ordered.end(), detail::pointYXOrdering<Point>);
     
     ArrayVector<Point> H;
     
-    int n = points.size(), k=0;
+    int n = ordered.size(), k=0;
     
     // Build lower hull
     for (int i = 0; i < n; i++) 
@@ -120,11 +878,1054 @@ void convexHull(const PointArray1 &points, PointArray2 & convex_hull)
         ++k;
     }
     
-    std::copy(H.begin(), H.begin()+k, std::back_inserter(convex_hull));
+    for(int i=k-1; i>=0; --i)
+        convex_hull.push_back(H[i]);
 }
 
-//@}
+/********************************************************************/
+/*                                                                  */
+/*                         polygon drawing                          */
+/*                                                                  */
+/********************************************************************/
 
-} // namespace vigra
+namespace detail {
+
+/*
+ * Find and sort all intersection points of the polygon with scanlines.
+ * Polygons are considered as closed set, i.e. pixels on the polygon 
+ * contour are included. The function handles degenerate cases (i.e.
+ * knots on scanlines) correctly.
+ */
+template<class Point, class Array>
+void createScanIntervals(Polygon<Point> const &p, Array & result) 
+{
+    bool drop_next_start_point = false;
+    int n = p.size();
+    for(int k=0; k<n-1; ++k)
+    {
+        Point const & p1 = p[k];
+        Point const & p2 = p[k+1];
+        
+        if(p1[1] == p2[1]) // ignore horizontal lines
+            continue;
+
+        double t = (p2[0] - p1[0]) / (p2[1] - p1[1]);
+        double y, yend, dy;
+        if(p1[1] < p2[1])
+        {
+            y = ceil(p1[1]);
+            yend = floor(p2[1]);
+            dy = 1.0;
+        }
+        else
+        {
+            y = floor(p1[1]);
+            yend = ceil(p2[1]);
+            dy = -1.0;
+        }
+        if(yend != p2[1]) // in general don't include the segment's endpoint
+            yend += dy;   // (since it is also the start point of the next segment)
+        if(drop_next_start_point) // handle degeneracy from previous iteration
+        {
+            y += dy;
+            drop_next_start_point = false;
+        }
+        for(; (y-yend)*dy < 0.0; y += dy)  // compute scanline intersections
+        {
+            double x = p1[0] + (y - p1[1])*t;
+            result.push_back(Point(x,y));
+        }
+        if(yend == p2[1]) // degenerate case: p2 is exactly on a scanline (yend is integer)
+        {
+            int j = (k+2)%n;
+            bool convex = detail::orderedClockwise(p1, p2, p[j]);
+            if(convex) // include the segment's endpoint p2 when it is a convex knot
+            {
+                result.push_back(p2);
+            }
+            for(; j != k+1; j = (j+1)%n)
+            {
+                double bend = dy*(p[j][1] - yend);
+                if(bend == 0.0)
+                    continue;
+                // Drop startpoint of next segment when the polygon after a convex 
+                // degenerate knot eventually crosses the scanline, or when it 
+                // returns to the original side of the scanline after a concave 
+                // degenerate knot.
+                if((convex && bend > 0.0) || (!convex && bend < 0.0))
+                    drop_next_start_point = true;
+                break;
+            }
+        }
+    }
+    
+    if(drop_next_start_point)
+        result.erase(result.begin());
+    
+    vigra_invariant((result.size() & 1) == 0,
+        "createScanIntervals(): internal error - should return an even number of points.");
+    sort(result.begin(), result.end(), pointYXOrdering<Point>);
+}
+
+
+} // namespace detail
+
+template<class Point, class FUNCTOR>
+bool
+inspectPolygon(Polygon<Point> const &p,
+               FUNCTOR const & f) 
+{
+    vigra_precondition(p.closed(),
+        "inspectPolygon(): polygon must be closed (i.e. first point == last point).");
+        
+    std::vector<Point> scan_intervals;
+    detail::createScanIntervals(p, scan_intervals);
+
+    for(unsigned int k=0; k < scan_intervals.size(); k+=2)
+    {
+        Shape2 p((MultiArrayIndex)ceil(scan_intervals[k][0]),
+                 (MultiArrayIndex)scan_intervals[k][1]);
+        MultiArrayIndex xend = (MultiArrayIndex)floor(scan_intervals[k+1][0]) + 1;
+        for(; p[0] < xend; ++p[0])
+            if(!f(p))
+                return false;
+    }
+    return true;
+}
+
+/** \brief Render closed polygon \a p into the image \a output_image. 
+
+    All pixels on the polygon's contour and in its interior are 
+    set to the given \a value. Parts of the polygon outside the image
+    region are clipped. The function uses a robust X-intersection array 
+    algorithm that is able to handle all corner cases (concave and 
+    self-intersecting polygons, knots on integer coordinates).
+ */
+template<class Point, class T, class S, class Value>
+void fillPolygon(Polygon<Point> const &p,
+                 MultiArrayView<2, T, S> &output_image, 
+                 Value value) 
+{
+    vigra_precondition(p.closed(),
+        "fillPolygon(): polygon must be closed (i.e. first point == last point).");
+        
+    std::vector<Point> scan_intervals;
+    detail::createScanIntervals(p, scan_intervals);
+
+    for(unsigned int k=0; k < scan_intervals.size(); k+=2)
+    {
+        MultiArrayIndex x    = (MultiArrayIndex)ceil(scan_intervals[k][0]),
+                        y    = (MultiArrayIndex)scan_intervals[k][1],
+                        xend = (MultiArrayIndex)floor(scan_intervals[k+1][0]) + 1;
+        vigra_invariant(y == scan_intervals[k+1][1],
+            "fillPolygon(): internal error - scan interval should have same y value.");
+        // clipping
+        if(y < 0)
+            continue;
+        if(y >= output_image.shape(1))
+            break;
+        if(x < 0)
+            x = 0;
+        if(xend > output_image.shape(0))
+            xend = output_image.shape(0);
+        // drawing
+        for(; x < xend; ++x)
+            output_image(x,y) = value;
+    }
+}
+
+#if 0
+
+// the following sophisticated polygon resampling functions have no tests yet
+
+/********************************************************************/
+
+template<bool useMaxStep, class PointIterator, class TargetArray>
+void simplifyPolygonHelper(
+    const PointIterator &polyBegin, const PointIterator &polyEnd,
+    TargetArray &simple, double epsilon,
+    double maxStep2 = vigra::NumericTraits<double>::max())
+{
+    if(polyEnd - polyBegin <= 2)
+        return; // no splitpoint necessary / possible
+
+    PointIterator splitPos(polyEnd), lastPoint(polyEnd);
+    --lastPoint;
+
+    double maxDist = epsilon;
+
+    // calculate normal of straight end point connection
+    typename TargetArray::value_type
+        straight(*lastPoint - *polyBegin);
+    double straightLength2 = straight.squaredMagnitude();
+
+    // search splitpoint
+    if(straightLength2 > 1e-16)
+    {
+        typename TargetArray::value_type
+            normal(straight[1], -straight[0]);
+
+        normal /= std::sqrt(straightLength2);
+
+        // iterate over points *between* first and last point:
+        PointIterator it(polyBegin);
+        for(++it; it != lastPoint; ++it)
+        {
+            double dist = fabs(dot(*it - *polyBegin, normal));
+            if(dist > maxDist)
+            {
+                splitPos = it;
+                maxDist = dist;
+            }
+        }
+    }
+    else
+    {
+        // start- and end-points identical?! -> look for most distant point
+        PointIterator it(polyBegin);
+        for(++it; it != lastPoint; ++it)
+        {
+            double dist = (*it - *polyBegin).magnitude();
+            if(dist > maxDist)
+            {
+                splitPos = it;
+                maxDist = dist;
+            }
+        }
+    }
+
+    if(useMaxStep && (straightLength2 > maxStep2) && (splitPos == polyEnd))
+    {
+        PointIterator it(polyBegin);
+        ++it;
+        double bestD2D = std::fabs((*it - *polyBegin).squaredMagnitude()
+                                   - (*it - *lastPoint).squaredMagnitude());
+        splitPos = it;
+        for(++it; it != lastPoint; ++it)
+        {
+            double dist2Diff = std::fabs((*it - *polyBegin).squaredMagnitude()
+                                         - (*it - *lastPoint).squaredMagnitude());
+            if(dist2Diff < bestD2D)
+            {
+                bestD2D = dist2Diff;
+                splitPos = it;
+            }
+        }
+    }
+
+    if(splitPos != polyEnd)
+    {
+        simplifyPolygonHelper<useMaxStep>(
+            polyBegin, splitPos + 1, simple, epsilon, maxStep2);
+        simple.push_back(*splitPos);
+        simplifyPolygonHelper<useMaxStep>(
+            splitPos, polyEnd, simple, epsilon, maxStep2);
+    }
+}
+
+template<class PointArray>
+void simplifyPolygon(
+    const PointArray &poly, PointArray &simple, double epsilon)
+{
+    simple.push_back(poly[0]);
+    simplifyPolygonHelper<false>(poly.begin(), poly.end(), simple, epsilon);
+    simple.push_back(poly[poly.size()-1]);
+}
+
+template<class PointArray>
+void simplifyPolygon(
+    const PointArray &poly, PointArray &simple, double epsilon, double maxStep)
+{
+    simple.push_back(poly[0]);
+    simplifyPolygonHelper<true>(poly.begin(), poly.end(),
+                                simple, epsilon, maxStep*maxStep);
+    simple.push_back(poly[poly.size()-1]);
+}
+
+/********************************************************************/
+
+namespace detail {
+
+template <class Point>
+Point digitalLineIntersection(TinyVector<double, 3> const & l1, TinyVector<double, 3> const & l2)
+{
+    double d = l1[0]*l2[1] - l1[1]*l2[0];
+    return Point((l1[1]*l2[2] - l1[2]*l2[1]) / d, (l1[2]*l2[0] - l1[0]*l2[2]) / d);
+}
+
+} // namespace detail
+
+template<class PointArray>
+void simplifyPolygonDigitalLine(
+    const PointArray &poly, PointArray &simple, int connectivity)
+{
+    typedef typename PointArray::value_type Point;
+
+    int size = poly.size();
+    if(size <= 2)
+    {
+        simple = poly;
+        return;
+    }
+
+    vigra_precondition(connectivity == 4 || connectivity == 8,
+       "simplifyPolygonDigitalLine(): connectivity must be 4 or 8.");
+
+    bool isOpenPolygon = poly[size-1] != poly[0];
+
+    ArrayVector<TinyVector<double, 3> > lines;
+    Point l1 = poly[0],
+          r1 = l1,
+          l2 = poly[1],
+          r2 = l2;
+    double a = l2[1] - l1[1],
+           b = l1[0] - l2[0],
+           c = -a*l2[0] - b*l2[1];
+    for(int k=2; k < size; ++k)
+    {
+        double ab = (connectivity == 4)
+                        ? std::fabs(a) + std::fabs(b)
+                        : std::max(std::fabs(a), std::fabs(b));
+        double d = a*poly[k][0] + b*poly[k][1] + c;
+        if(d < -1.0 || d > ab)
+        {
+            // finish current segment
+            c = (c - a*r2[0] - b*r2[1]) / 2.0;
+            lines.push_back(TinyVector<double, 3>(a, b, c));
+            // initialize new segment
+            l1 = poly[k-1];
+            r1 = l1;
+            l2 = poly[k];
+            r2 = l2;
+            a = l2[1] - l1[1];
+            b = l1[0] - l2[0];
+            c = -a*l2[0] - b*l2[1];
+        }
+        else if(d <= 0.0)
+        {
+            l2 = poly[k];
+            if(d < 0.0)
+            {
+                r1 = r2;
+                a = l2[1] - l1[1];
+                b = l1[0] - l2[0];
+                c = -a*l2[0] - b*l2[1];
+            }
+        }
+        else if(d >= ab - 1.0)
+        {
+            r2 = poly[k];
+            if(d > ab - 1.0)
+            {
+                l1 = l2;
+                a = r2[1] - r1[1];
+                b = r1[0] - r2[0];
+                c = -a*l2[0] - b*l2[1];
+            }
+        }
+    }
+
+    c = (c - a*r2[0] - b*r2[1]) / 2.0;
+    lines.push_back(TinyVector<double, 3>(a, b, c));
+    int segments = lines.size();
+
+    if(isOpenPolygon)
+        simple.push_back(poly[0]);
+    else
+        simple.push_back(detail::digitalLineIntersection<Point>(lines[0], lines[segments-1]));
+
+    for(int k=1; k<segments; ++k)
+        simple.push_back(detail::digitalLineIntersection<Point>(lines[k-1], lines[k]));
+
+    if(isOpenPolygon)
+        simple.push_back(poly[size-1]);
+    else
+        simple.push_back(detail::digitalLineIntersection<Point>(lines[0], lines[segments-1]));
+}
+
+/********************************************************************/
+
+template<class PointArray>
+void resamplePolygon(
+    const PointArray &poly, PointArray &simple, double desiredPointDistance)
+{
+    typedef typename PointArray::value_type Point;
+
+    int size = poly.size();
+    bool isOpenPolygon = !poly.closed();
+
+    ArrayVector<double> arcLength;
+    poly.arcLengthList(arcLength);
+    int segmentCount = int(std::ceil(arcLength[size-1] / desiredPointDistance));
+    if(segmentCount < 2)
+    {
+        simple.push_back(poly[0]);
+        if(!isOpenPolygon)
+        {
+            Point p = poly[1];
+            double dist = (p - poly[0]).magnitude();
+            for(int k=2; k < size-1; ++k)
+            {
+                double d = (poly[k] - poly[0]).magnitude();
+                if(d > dist)
+                {
+                    dist = d;
+                    p = poly[k];
+                }
+            }
+            simple.push_back(p);
+        }
+        simple.push_back(poly[size-1]);
+        return;
+    }
+
+    for(int k=0; k<size; ++k)
+        arcLength[k] *= segmentCount / arcLength[size-1];
+
+    ArrayVector<Point> integrals(segmentCount+1, Point(0.0, 0.0));
+    Point p1 = poly[0];
+    double t1 = 0.0;
+    int l = 1;
+    for(int k=1; k<size; ++k)
+    {
+        double d = arcLength[k];
+        while(d >= l && l <= segmentCount)
+        {
+            double t2 = 1.0;
+            double dt = t2 - t1;
+            Point p2 = poly.interpolate(k-1, (l - arcLength[k-1]) / (d - arcLength[k-1]));
+            Point sum1 = 0.5 * dt * (p1 + p2);
+            Point sumt = dt / 6.0 * (p1*(2.0*t1+t2) + p2*(t1+2.0*t2));
+            integrals[l-1] += sum1 - sumt;
+            integrals[l] += sumt;
+            if(isOpenPolygon && l==1)
+            {
+                integrals[0] +=  poly[0] - integrals[1];
+            }
+            p1 = p2;
+            t1 = 0.0;
+            ++l;
+            if(isOpenPolygon && l==segmentCount)
+            {
+                integrals[segmentCount] += integrals[segmentCount-1];
+            }
+        }
+        if(d < l && l <= segmentCount)
+        {
+            double t2 = std::fmod(d, 1.0);
+            double dt = t2 - t1;
+            Point p2 = poly[k];
+            Point sum1 = 0.5 * dt * (p1 + p2);
+            Point sumt = dt / 6.0 * (p1*(2.0*t1+t2) + p2*(t1+2.0*t2));
+            integrals[l-1] += sum1 - sumt;
+            integrals[l] += sumt;
+            p1 = p2;
+            t1 = t2;
+        }
+    }
+
+    if(isOpenPolygon)
+    {
+        integrals[segmentCount] += poly[size-1] - integrals[segmentCount-1];
+        integrals[1] -= integrals[0] / 6.0;
+        integrals[segmentCount-1] -= integrals[segmentCount] / 6.0;
+
+        ArrayVector<double> g(segmentCount);
+        double b = 2.0 / 3.0;
+        simple.push_back(poly[0]);
+        simple.push_back(integrals[1] / b);
+        for(int k=2; k<segmentCount; ++k)
+        {
+            g[k] = 1.0 / 6.0 / b;
+            b = 2.0 / 3.0 - g[k] / 6.0;
+            simple.push_back((integrals[k] - simple[k-1] / 6.0) / b);
+        }
+        for(int k = segmentCount-2; k >= 1; --k)
+        {
+            simple[k] -= g[k+1] * simple[k+1];
+        }
+
+        simple.push_back(poly[size-1]);
+    }
+    else
+    {
+        integrals[0] += integrals[segmentCount];
+
+        int initializationSteps = std::min(segmentCount, 5);
+        ArrayVector<Point> p(segmentCount+2*initializationSteps);
+        double b = 0.6220084679281461,
+               g = 0.26794919243112275;
+        p[0] = integrals[0] / b;
+
+        for(int k=1; k<segmentCount+2*initializationSteps; ++k)
+        {
+            p[k] = (integrals[k % segmentCount] - p[k-1] / 6.0) / b;
+        }
+        for(int k = segmentCount+2*initializationSteps-2; k >= initializationSteps; --k)
+        {
+            p[k] -= g * p[k+1];
+        }
+
+        for(int k=segmentCount; k<segmentCount+initializationSteps; ++k)
+            simple.push_back(p[k]);
+        for(int k=initializationSteps; k<=segmentCount; ++k)
+            simple.push_back(p[k]);
+    }
+}
+
+/********************************************************************/
+
+template<class PointArray>
+void resamplePolygonLinearInterpolation(
+    const PointArray &poly, PointArray &simple, double desiredPointDistance)
+{
+    int size = poly.size();
+    if(size <= 2)
+    {
+        simple = poly;
+        return;
+    }
+
+    ArrayVector<double> arcLengths;
+    poly.arcLengthList(arcLengths);
+
+    int steps = int(std::ceil(arcLengths[size-1] / desiredPointDistance));
+    double newStep = arcLengths[size-1] / steps;
+
+    simple.push_back(poly[0]);
+    int l = 1;
+    for(int k=1; k<steps; ++k)
+    {
+        double currentArcLength = k*newStep;
+        for(; l < size; ++l)
+        {
+            if(arcLengths[l] >= currentArcLength)
+                break;
+        }
+        double o = (arcLengths[l] - currentArcLength) / (arcLengths[l] - arcLengths[l-1]);
+        simple.push_back(o*poly[l-1] + (1.0-o)*poly[l]);
+    }
+    simple.push_back(poly[size-1]);
+}
+
+/********************************************************************/
+
+template<class PointArray>
+void resamplePolygonExponentialFilter(
+    const PointArray &poly, PointArray &simple, double scale, double desiredPointDistance)
+{
+    int size = poly.size();
+    if(size <= 2)
+    {
+        simple = poly;
+        return;
+    }
+
+    bool isOpenPolygon = !poly.closed();
+
+    typedef typename PointArray::value_type Point;
+    ArrayVector<Point> pforward(size), pbackward(size);
+    ArrayVector<double> wforward(size), wbackward(size), weights(size-1);
+    for(int k=0; k < size - 1; ++k)
+        weights[k] = std::exp(-(poly[k] - poly[k+1]).magnitude()/scale);
+
+    // init recursion with cyclic boundary conditions
+    Point p = poly[0];
+    double w = 1.0;
+    for(int k=1; k < size; ++k)
+    {
+        p = poly[k] + weights[k-1]*p;
+        w = 1.0 + weights[k-1]*w;
+    }
+    pforward[0] = p;
+    wforward[0] = w;
+
+    p = poly[size-1];
+    w = 1.0;
+    for(int k=size-2; k>=0; --k)
+    {
+        p = poly[k] + weights[k]*p;
+        w = 1.0 + weights[k]*w;
+    }
+    pbackward[size-1] = p;
+    wbackward[size-1] = w;
+
+    if(isOpenPolygon)
+    {
+        // change initialization into anti-reflective boundary conditions for open polygons
+        std::swap(wbackward[size-1], wforward[0]);
+        std::swap(pbackward[size-1], pforward[0]);
+        pforward[0] = 2.0*wforward[0]*poly[0] - pforward[0];
+        pbackward[size-1] = 2.0*wbackward[size-1]*poly[size-1] - pbackward[size-1];
+    }
+
+    // forward and backward pass of the recursive filter
+    for(int k=1; k < size; ++k)
+    {
+        pforward[k] = poly[k] + weights[k-1]*pforward[k-1];
+        wforward[k] = 1.0 + weights[k-1]*wforward[k-1];
+    }
+    for(int k=size-2; k >= 0; --k)
+    {
+        pbackward[k] = poly[k] + weights[k]*pbackward[k+1];
+        wbackward[k] = 1.0 + weights[k]*wbackward[k+1];
+    }
+
+    // measure the arc length of the new polygon (after possible shrinkage)
+    p = (pforward[0]+weights[0]*pbackward[1]) / (wforward[0] + weights[0]*wbackward[1]);
+    simple.push_back(p);
+
+    Point pend = isOpenPolygon
+                   ? (weights[size-2]*pforward[size-2]+pbackward[size-1]) /
+                     (weights[size-2]*wforward[size-2] + wbackward[size-1])
+                   : p;
+
+    ArrayVector<double> arcLength;
+    double length = 0.0;
+    arcLength.push_back(length);
+    for(int k=1; k<size-1; ++k)
+    {
+        Point pc = (pforward[k]+weights[k]*pbackward[k+1]) / (wforward[k] + weights[k]*wbackward[k+1]);
+        length += (pc - p).magnitude();
+        arcLength.push_back(length);
+        p = pc;
+    }
+    length += (p-pend).magnitude();
+    arcLength.push_back(length);
+
+//    alternative: use the arc lenth of the original polygon
+//    poly.arcLengthList(arcLength);
+
+    int steps = int(std::floor(arcLength[size-1] / desiredPointDistance+0.5));
+    double newStep = arcLength[size-1] / steps;
+
+    int l = 1;
+    for(int k=1; k < steps; ++k)
+    {
+        double currentArcLength = k*newStep;
+        for(; l < size; ++l)
+        {
+            if(arcLength[l] >= currentArcLength)
+                break;
+        }
+        double w = weights[l-1];
+        double o = (arcLength[l] - currentArcLength) / (arcLength[l] - arcLength[l-1]);
+        double wl = std::pow(w, 1.0-o);
+        double wr = std::pow(w, o);
+        simple.push_back((wl*pforward[l-1]+wr*pbackward[l]) / (wl*wforward[l-1] + wr*wbackward[l]));
+    }
+    simple.push_back(pend);
+}
+
+/********************************************************************/
+
+namespace detail {
+
+template<class ArcLengthList, class PointList>
+typename PointList::value_type
+singleGaussianConvolvePolygonReflective(
+    const ArcLengthList &arcLengthList,
+    const PointList &pointList,
+    int i, double arcLengthPos,
+    const Gaussian<double> &g)
+{
+    typedef typename PointList::value_type ValueType;
+
+    ValueType sum(vigra::NumericTraits<ValueType>::zero());
+    double norm = 0.0;
+
+    int size = arcLengthList.size(),
+        lastIndex = size - 1;
+    double reflectLength = 2.0*arcLengthList[lastIndex];
+
+    ValueType reflectPoint = 2.0*pointList[lastIndex];
+    for(int j = i; true; ++j)
+    {
+        int k = (j > lastIndex)
+                ? 2*lastIndex - j
+                : j;
+        double pos = arcLengthList[k];
+        ValueType point = pointList[k];
+        if(j > lastIndex)
+        {
+            pos = reflectLength - pos;
+            point = reflectPoint - point;
+        }
+        double diff = pos - arcLengthPos;
+        if(diff > g.radius())
+            break;
+        double w(g(diff));
+        sum += w*point;
+        norm += w;
+    }
+
+    reflectPoint = 2.0*pointList[0];
+    for(int j = i - 1; true; --j)
+    {
+        int k = std::abs(j);
+        double pos = arcLengthList[k];
+        ValueType point = pointList[k];
+        if(j < 0)
+        {
+            pos = -pos;
+            point = reflectPoint - point;
+        }
+        double diff = pos - arcLengthPos;
+        if(diff < -g.radius())
+            break;
+        double w(g(diff));
+        sum += w*point;
+        norm += w;
+    }
+
+    return sum / norm;
+}
+
+template<class ArcLengthList, class PointList>
+typename PointList::value_type
+singleGaussianConvolvePolygonCyclic(
+    const ArcLengthList &arcLengthList,
+    const PointList &pointList,
+    int i, double arcLengthPos,
+    const Gaussian<double> &g)
+{
+    typedef typename PointList::value_type ValueType;
+
+    ValueType sum(vigra::NumericTraits<ValueType>::zero());
+    double norm = 0.0;
+
+    int size = arcLengthList.size() - 1,
+        lastIndex = size - 1;
+    double totalLength = arcLengthList[size];
+
+    for(int j = i; true; ++j)
+    {
+        int k = j % size;
+        double pos = j > lastIndex
+                        ? arcLengthList[k] + totalLength
+                        : arcLengthList[k];
+        ValueType point = pointList[k];
+        double diff = pos - arcLengthPos;
+        if(diff > g.radius())
+            break;
+        double w(g(diff));
+        sum += w*point;
+        norm += w;
+    }
+
+    for(int j = i - 1; true; --j)
+    {
+        int k = (j + size) % size;
+        double pos = j < 0
+                       ? arcLengthList[k] - totalLength
+                       : arcLengthList[k];
+        ValueType point = pointList[k];
+        double diff = pos - arcLengthPos;
+        if(diff < -g.radius())
+            break;
+        double w(g(diff));
+        sum += w*point;
+        norm += w;
+    }
+
+    return sum / norm;
+}
+
+} // namespace detail
+
+template<class PointArray>
+void resamplePolygonGaussianFilter(
+    const PointArray &poly, PointArray &simple, double scale, double desiredPointDistance)
+{
+    int size = poly.size();
+    if(size <= 2)
+    {
+        simple = poly;
+        return;
+    }
+
+    ArrayVector<double> arcLengths;
+    poly.arcLengthList(arcLengths);
+
+    Gaussian<double> g(scale);
+
+    vigra_precondition(arcLengths[size-1] > g.radius(),
+        "resamplePolygonGaussianFilter(): Filter longer than polygon.");
+
+    bool isOpenPolygon = !poly.closed();
+
+    int steps = int(std::ceil(arcLengths[size-1] / desiredPointDistance));
+    double newStep = arcLengths[size-1] / steps;
+
+    int l = 0;
+    for(int k=0; k<steps; ++k)
+    {
+        double currentArcLength = k*newStep;
+        for(; l < size; ++l)
+        {
+            if(arcLengths[l] >= currentArcLength)
+                break;
+        }
+        if(isOpenPolygon)
+            simple.push_back(detail::singleGaussianConvolvePolygonReflective(arcLengths, poly, l, currentArcLength, g));
+        else
+            simple.push_back(detail::singleGaussianConvolvePolygonCyclic(arcLengths, poly, l, currentArcLength, g));
+    }
+    if(isOpenPolygon)
+        simple.push_back(detail::singleGaussianConvolvePolygonReflective(arcLengths, poly, size-1, arcLengths[size-1], g));
+    else
+        simple.push_back(simple[0]);
+}
+
+/********************************************************************/
+
+namespace detail {
+
+template<class Point>
+Point spline3Integral(Point const & p1, Point const & p2, double t1, double t2)
+{
+    StaticPolynomial<5, double> p[2];
+    p[0][0] = p[1][0] = 0.0;
+    if(t1 >= 1.0)
+    {
+        return (t1 - t2) / 120.0 *
+               (p1 * (-80.0 + t1*(80.0 + 2.0*t2*(t2 - 10.0) + t1*(3.0*t2 - 30.0 + 4.0*t1)) + t2*(40.0 + t2*(t2 - 10.0))) +
+                p2 * (-80.0 + t1*(40.0 + t2*(3.0*t2 - 20.0) + t1*(2.0*t2 - 10.0 + t1)) + t2*(80.0 + t2*(4.0*t2 - 30.0))));
+    }
+    else
+    {
+        return (t2 - t1) / 120.0 *
+               (p1 * (40.0 + t1*(2.0*t2*(3.0*t2 - 10.0) + t1*(9.0*t2 - 30.0 + 12.0*t1)) + t2*t2*(3.0*t2 - 10.0)) +
+                p2 * (40.0 + t1*(t2*(9.0*t2 - 20.0) + t1*(6.0*t2 - 10.0 + 3.0*t1)) + t2*t2*(12.0*t2 - 30.0)));
+    }
+}
+
+template<class ArcLengthList, class PointList>
+typename PointList::value_type
+singleSpline3ConvolvePolygon(
+    const ArcLengthList &arcLengthList,
+    const PointList &pointList,
+    int left, int center, int right)
+{
+    typedef typename PointList::value_type ValueType;
+
+    ValueType sum(vigra::NumericTraits<ValueType>::zero());
+    double arcLengthPos = arcLengthList[center];
+    for(int j = center + 1; j <= right; ++j)
+    {
+        double t1 = arcLengthList[j-1] - arcLengthPos,
+               t2 = arcLengthList[j] - arcLengthPos;
+        sum += spline3Integral(pointList[j-1], pointList[j], t1, t2);
+    }
+    for(int j = center - 1; j >= left; --j)
+    {
+        double t1 = arcLengthPos - arcLengthList[j+1],
+               t2 = arcLengthPos - arcLengthList[j];
+        sum -= spline3Integral(-pointList[j+1], -pointList[j], t1, t2);
+    }
+
+    return sum;
+}
+
+} // namespace detail
+
+template<class PointArray>
+void polygonSplineControlPoints(
+    const PointArray &poly, PointArray &splinePoints, int segmentCount)
+{
+    typedef typename PointArray::value_type Point;
+
+    int size = poly.size();
+    vigra_precondition(size >= 4,
+        "polygonSplineControlPoints(): Polygon must have at least 4 points.");
+
+    bool isOpenPolygon = !poly.closed();
+
+    ArrayVector<double> arcLength;
+    poly.arcLengthList(arcLength);
+    double totalLength = segmentCount / arcLength[size-1];
+    for(int k=0; k<size; ++k)
+        arcLength[k] *= totalLength;
+
+    PointArray augmentedPoly;
+    augmentedPoly.push_back(poly[0]);
+
+    ArrayVector<double> augmentedArcLength;
+    augmentedArcLength.push_back(0.0);
+
+    ArrayVector<int> splineIndices(segmentCount + 1);
+    splineIndices[0] = 0;
+    int l = 1;
+    for(int k=1; k<size-1; ++k)
+    {
+        double d = arcLength[k];
+        while(d > l)
+        {
+            augmentedPoly.push_back(poly.interpolate(k-1, (l - arcLength[k-1]) / (d - arcLength[k-1])));
+            augmentedArcLength.push_back(l);
+            splineIndices[l] = augmentedPoly.size()-1;
+            ++l;
+        }
+        augmentedPoly.push_back(poly[k]);
+        augmentedArcLength.push_back(d);
+        if(d == l)
+        {
+            splineIndices[l] = augmentedPoly.size()-1;
+            ++l;
+        }
+    }
+    augmentedPoly.push_back(poly[size-1]);
+    augmentedArcLength.push_back(segmentCount);
+    splineIndices[segmentCount] = augmentedPoly.size()-1;
+    size = augmentedPoly.size();
+
+    ArrayVector<Point> integrals(segmentCount+1);
+    if(isOpenPolygon)
+    {
+        integrals[0] = augmentedPoly[0];
+        PointArray reflectedPoly;
+        Point reflectPoint = 2.0*poly[0];
+        ArrayVector<double> reflectedArcLength;
+        for(int k=-splineIndices[1]; k <= splineIndices[3]; ++k)
+        {
+            if(k < 0)
+            {
+                reflectedPoly.push_back(reflectPoint - augmentedPoly[-k]);
+                reflectedArcLength.push_back(-augmentedArcLength[-k]);
+            }
+            else
+            {
+                reflectedPoly.push_back(augmentedPoly[k]);
+                reflectedArcLength.push_back(augmentedArcLength[k]);
+            }
+        }
+        integrals[1] = detail::singleSpline3ConvolvePolygon(reflectedArcLength, reflectedPoly,
+                                    0, 2*splineIndices[1], splineIndices[1] + splineIndices[3]);
+
+        reflectPoint = 2.0*augmentedPoly[size-1];
+        for(int k=size-2; k>=splineIndices[segmentCount-1]; --k)
+        {
+            augmentedPoly.push_back(reflectPoint - augmentedPoly[k]);
+            augmentedArcLength.push_back(2.0*segmentCount - augmentedArcLength[k]);
+        }
+        integrals[segmentCount-1] = detail::singleSpline3ConvolvePolygon(augmentedArcLength, augmentedPoly,
+               splineIndices[segmentCount-3], splineIndices[segmentCount-1],
+               2*splineIndices[segmentCount] - splineIndices[segmentCount-1]);
+        integrals[segmentCount] = augmentedPoly[size-1];
+    }
+    else
+    {
+        PointArray wrappedPoly;
+        ArrayVector<double> wrappedArcLength;
+        for(int k=splineIndices[segmentCount-1]; k < splineIndices[segmentCount]; ++k)
+        {
+            wrappedPoly.push_back(augmentedPoly[k]);
+            wrappedArcLength.push_back(augmentedArcLength[k] - segmentCount);
+        }
+        int indexShift = wrappedPoly.size();
+        for(int k=0; k <= splineIndices[3]; ++k)
+        {
+            wrappedPoly.push_back(augmentedPoly[k]);
+            wrappedArcLength.push_back(augmentedArcLength[k]);
+        }
+        integrals[1] = detail::singleSpline3ConvolvePolygon(wrappedArcLength, wrappedPoly,
+                             0, splineIndices[1] + indexShift, splineIndices[3] + indexShift);
+
+        for(int k=1; k <= splineIndices[2]; ++k)
+        {
+            augmentedPoly.push_back(augmentedPoly[k]);
+            augmentedArcLength.push_back(segmentCount + augmentedArcLength[k]);
+        }
+        integrals[segmentCount-1] = detail::singleSpline3ConvolvePolygon(augmentedArcLength, augmentedPoly,
+               splineIndices[segmentCount-3], splineIndices[segmentCount-1],
+               splineIndices[segmentCount] + splineIndices[1]);
+        integrals[0] = detail::singleSpline3ConvolvePolygon(augmentedArcLength, augmentedPoly,
+               splineIndices[segmentCount-2], splineIndices[segmentCount],
+               splineIndices[segmentCount] + splineIndices[2]);
+    }
+
+    for(int k=2; k <= segmentCount-2; ++k)
+        integrals[k] = detail::singleSpline3ConvolvePolygon(augmentedArcLength, augmentedPoly,
+                                    splineIndices[k-2], splineIndices[k], splineIndices[k+2]);
+
+    BSpline<7, double> spline7;
+    if(isOpenPolygon)
+    {
+        int solutionSize = segmentCount + 1;
+        Matrix<double> m(solutionSize, solutionSize),
+                    rhs(solutionSize, 2),
+                    solution(solutionSize, 2);
+        for(int k=0; k<solutionSize; ++k)
+        {
+            for(int l=-3; l<=3; ++l)
+            {
+                if(k + l < 0)
+                {
+                    m(k, 0) += 2.0*spline7(l);
+                    m(k, abs(k+l)) -= spline7(l);
+                }
+                else if(k + l >= solutionSize)
+                {
+                    m(k, solutionSize - 1) += 2.0*spline7(l);
+                    m(k, 2*solutionSize - k - l - 2) -= spline7(l);
+                }
+                else
+                    m(k,k+l) += spline7(l);
+            }
+            rhs(k, 0) = integrals[k][0];
+            rhs(k, 1) = integrals[k][1];
+        }
+
+        linearSolve(m, rhs, solution);
+
+        for(int k=0; k<solutionSize; ++k)
+        {
+            splinePoints.push_back(Point(solution(k,0), solution(k,1)));
+        }
+        splinePoints.push_back(2.0*splinePoints[solutionSize-1] - splinePoints[solutionSize-2]);
+        splinePoints.insert(splinePoints.begin(), 2.0*splinePoints[0] - splinePoints[1]);
+    }
+    else
+    {
+        int solutionSize = segmentCount;
+        Matrix<double> m(solutionSize, solutionSize),
+                    rhs(solutionSize, 2),
+                    solution(solutionSize, 2);
+        for(int k=0; k<solutionSize; ++k)
+        {
+            for(int l=-3; l<=3; ++l)
+                m(k, (k+l+solutionSize) % solutionSize) = spline7(l);
+            rhs(k, 0) = integrals[k][0];
+            rhs(k, 1) = integrals[k][1];
+        }
+        linearSolve(m, rhs, solution);
+
+        for(int k=0; k<solutionSize; ++k)
+        {
+            splinePoints.push_back(Point(solution(k,0), solution(k,1)));
+        }
+        splinePoints.push_back(splinePoints[0]);
+    }
+}
+
+#endif
+
+//@}
+
+} // namespace vigra
+
+namespace std {
+
+template <class T>
+ostream & operator<<(ostream & s, vigra::Polygon<T> const & a)
+{
+    for(std::size_t k=0; k<a.size()-1; ++k)
+        s << a[k] << ", ";
+    if(a.size())
+            s << a.back();
+    return s;
+}
+
+} // namespace std
 
 #endif /* VIGRA_POLYGON_HXX */
diff --git a/include/vigra/polynomial_registration.hxx b/include/vigra/polynomial_registration.hxx
new file mode 100644
index 0000000..11e9ae1
--- /dev/null
+++ b/include/vigra/polynomial_registration.hxx
@@ -0,0 +1,278 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2007-2013 by Benjamin Seppke                 */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_POLYNOMIAL_REGISTRATION_HXX
+#define VIGRA_POLYNOMIAL_REGISTRATION_HXX
+
+#include "mathutil.hxx"
+#include "matrix.hxx"
+#include "linear_solve.hxx"
+#include "tinyvector.hxx"
+#include "splineimageview.hxx"
+
+namespace vigra
+{
+
+/** \addtogroup Registration Image Registration
+ */
+//@{
+
+/**
+ * Iterative function for determinination of the polynom weights:
+ *
+ * Example: order=2, x, y
+ *   ----->
+ *          [1,
+ *              x, y,
+ *                    x^2, x*y, y^2]
+ *
+ * This function is needed, because the polynomial transformation Matrix
+ * has the the same number of rows. the target position is then determined
+ * by multiplying each x- and y-transformation result value with the
+ * corresponding weight for the current x- and y-coordinate, given by this
+ * function.
+ */
+std::vector<double> polynomialWarpWeights(double x, double y, unsigned int polynom_order)
+{
+    unsigned int poly_count = (polynom_order+1)*(polynom_order+2)/2;
+
+    std::vector<double> weights(poly_count);
+
+    unsigned int weight_idx=0;
+
+    for (unsigned int order=0; order<=polynom_order; order++)
+    {
+        for(unsigned int i=0; i<=order; i++, weight_idx++)
+        {
+            weights[weight_idx] = pow(x,(double)order-i)*pow(y,(double)i);
+        }
+    }
+    return weights;
+}
+
+/********************************************************/
+/*                                                      */
+/*     polynomialMatrix2DFromCorrespondingPoints        */
+/*                                                      */
+/********************************************************/
+
+/** \brief Create polynomial matrix of a certain degree that maps corresponding points onto each other.
+
+    For use with \ref polynomialWarpImage() of same degree.
+
+    Since polynoms are usually non-linear functions, a special semantics is embedded to define
+    a matrix here. Each matrix consist of two rows, containing x- and y-factors of the polynom.
+
+    The meaning of the matrix is explained at the example of a polynom of 2nd order:
+
+    First  Row = [a_x b_x c_x d_x e_x f_x]
+    Second Row = [a_y b_y c_y d_y e_y f_y]
+
+    The transformed coordinate p'=[x' y'] of a position p=[x y] is then:
+
+    x' = a_x + b_x*x + c_x*y + d_x*x^2 + e_x*x*y + f_x*y^2
+    y' = a_y + b_y*x + c_y*y + d_y*x^2 + e_y*x*y + f_y*y^2
+
+    Note that the order of the polynom's factors is directly influenced by the
+    \ref polynomialWarpWeights() function and follows the intuitive scheme.
+*/
+template <int PolynomOrder,
+          class SrcPointIterator,
+          class DestPointIterator>
+linalg::TemporaryMatrix<double>
+polynomialMatrix2DFromCorrespondingPoints(SrcPointIterator s, SrcPointIterator s_end,
+                                          DestPointIterator d)
+{
+    int point_count = s_end - s;
+    int poly_count = (PolynomOrder+1)*(PolynomOrder+2)/2;
+
+    vigra::Matrix<double> A(point_count,poly_count), b1(point_count,1), res1(poly_count,1), b2(point_count,1), res2(poly_count,1);
+    std::vector<double> weights;
+
+    for (int i =0; i<point_count; ++i, ++s, ++d)
+    {
+        weights = polynomialWarpWeights((*d)[0], (*d)[1], PolynomOrder);
+
+        for(int c=0; c<poly_count; c++)
+        {
+            A(i,c) = weights[c];
+        }
+
+        b1(i,0)=(*s)[0];b2(i,0)=(*s)[1];
+    }
+
+    if(!vigra::linearSolve(  A, b1, res1 ) || !vigra::linearSolve(  A, b2, res2 ))
+        vigra_fail("polynomialMatrix2DFromCorrespondingPoints(): singular solution matrix.");
+
+    vigra::Matrix<double> res(poly_count,2);
+
+    for(int c=0; c<poly_count; c++)
+    {
+        res(c,0) = res1(c,0);
+        res(c,1) = res2(c,0);
+    }
+
+    return res;
+}
+
+
+/********************************************************/
+/*                                                      */
+/*                polynomialWarpImage                   */
+/*                                                      */
+/********************************************************/
+
+/** \brief Warp an image according to an polynomial transformation.
+
+    To get more information about the structure of the matrix, 
+    see \ref polynomialMatrix2DFromCorrespondingPoints().
+
+    <b>\#include</b> \<vigra/polynomial_registration.hxx\><br>
+    Namespace: vigra
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <int ORDER, class T,
+                  class T2, class S2,
+                  class C>
+        void
+        polynomialWarpImage(SplineImageView<ORDER, T> const & src,
+                            MultiArrayView<2, T2, S2> dest,
+                            MultiArrayView<2, double, C> const & polynomialMatrix);
+    }
+    \endcode
+
+    \deprecatedAPI{polynomialWarpImage}
+
+    pass arguments explicitly:
+    \code
+    namespace vigra {
+        template <int ORDER, class T,
+                  class DestIterator, class DestAccessor,
+                  class C>
+        void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
+                                 DestIterator dul, DestIterator dlr, DestAccessor dest,
+                                 MultiArrayView<2, double, C> const & polynomialMatrix);
+    }
+    \endcode
+
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <int ORDER, class T,
+                  class DestIterator, class DestAccessor,
+                  class C>
+        void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
+                                 triple<DestIterator, DestIterator, DestAccessor> dest,
+                                 MultiArrayView<2, double, C> const & polynomialMatrix);
+    }
+    \endcode
+    \deprecatedEnd
+ */
+doxygen_overloaded_function(template <...> void polynomialWarpImage)
+
+template <int PolynomOrder,
+          int ORDER, class T,
+          class DestIterator, class DestAccessor,
+          class C>
+void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
+                         DestIterator dul, DestIterator dlr, DestAccessor dest,
+                         MultiArrayView<2, double, C> const & polynomialMatrix)
+{
+    int poly_count = (PolynomOrder+1)*(PolynomOrder+2)/2;
+
+    vigra_precondition(rowCount(polynomialMatrix) == poly_count && columnCount(polynomialMatrix) == 2,
+                           "polynomialWarpImage(): matrix doesn't represent a polynomial transformation of given degreee in 2D coordinates.");
+
+    double w = dlr.x - dul.x;
+    double h = dlr.y - dul.y;
+
+    std::vector<double> weights(poly_count);
+
+    for(double y = 0.0; y < h; ++y, ++dul.y)
+    {
+        typename DestIterator::row_iterator rd = dul.rowIterator();
+        for(double x=0.0; x < w; ++x, ++rd)
+        {
+            weights = polynomialWarpWeights(x,y, PolynomOrder);
+
+            double sx=0;
+            double sy=0;
+
+            for(int c=0; c<poly_count; c++)
+            {
+                sx += weights[c]*polynomialMatrix(c,0);
+                sy += weights[c]*polynomialMatrix(c,1);
+            }
+
+            if(src.isInside(sx, sy))
+                dest.set(src(sx, sy), rd);
+        }
+    }
+}
+
+template <int PolynomOrder,
+          int ORDER, class T,
+          class DestIterator, class DestAccessor,
+          class C>
+inline
+void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
+                         triple<DestIterator, DestIterator, DestAccessor> dest,
+                         MultiArrayView<2, double, C> const & polynomialMatrix)
+{
+    polynomialWarpImage<PolynomOrder>(src, dest.first, dest.second, dest.third, polynomialMatrix);
+}
+
+
+template <int PolynomOrder,
+          int ORDER, class T,
+          class T2, class S2,
+          class C>
+inline
+void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
+                          MultiArrayView<2, T2, S2> dest,
+                          MultiArrayView<2, double, C> const & polynomialMatrix)
+{
+    polynomialWarpImage<PolynomOrder>(src, destImageRange(dest), polynomialMatrix);
+}
+
+
+//@}
+
+} // namespace vigra
+
+
+#endif /* VIGRA_POLYNOMIAL_REGISTRATION_HXX */
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/include/vigra/print_backtrace.hxx
similarity index 60%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to include/vigra/print_backtrace.hxx
index 37a8c81..64ada42 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/include/vigra/print_backtrace.hxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,64 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#ifndef VIGRA_PRINT_BACKTRACE_HXX
+#define VIGRA_PRINT_BACKTRACE_HXX
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
-#include <vigra/numpy_array.hxx>
-#include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
+/* Quick-and-dirty way to print a backtrace upon a signal in Linux.
 
-namespace python = boost::python;
+   Especially useful if you can't use a debugger (e.g. on TravisCI).
+   
+   Usage:
+   
+   Make sure to compile in debug mode.
+   Have "addr2line" installed (was already present on TravisCI and our local machines).
+   
+   #include <vigra/print_backtrace.hxx>
+   
+   int main(int argc, char** argv)
+   {
+       program_name = argv[0];
+       signal(SIGSEGV, &vigra_print_backtrace);  // catch the desired signal
+       
+       run_buggy_code();
+   }   
+*/
 
-namespace vigra {
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+	
 
-UInt32 pychecksum(python::str const & s)
+static char * program_name;
+
+static int vigra_addr2line(void const * const addr)
 {
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
+    char addr2line_cmd[512] = {0};
+    sprintf(addr2line_cmd,"addr2line -C -f -p -i -e %.256s %p", program_name, addr);
+    return system(addr2line_cmd);
 }
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
-
-} // namespace vigra
-
-using namespace boost::python;
-using namespace vigra;
-
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
+static void vigra_print_backtrace(int sig)
 {
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
+    int i, trace_size = 0;
+    char **messages = (char **)NULL;
+    static const int BACKTRACE_SIZE = 100;
+    void *stack_traces[BACKTRACE_SIZE];
     
-    def("checksum", &pychecksum, args("data"));
+    fprintf(stderr, "caught signal %d, printing backtrace\n\n", sig);
+
+    trace_size = backtrace(stack_traces, BACKTRACE_SIZE);
+    messages = backtrace_symbols(stack_traces, trace_size);
+
+    for (i = 0; i < trace_size; ++i)
+    {
+        if (vigra_addr2line(stack_traces[i]) != 0)
+        {
+            fprintf(stderr, "  error determining line # for: %sn", messages[i]);
+        }
+    }
+    if (messages) { free(messages); }
+    exit(1);
 }
+    
+#endif // VIGRA_PRINT_BACKTRACE_HXX
diff --git a/include/vigra/bucket_queue.hxx b/include/vigra/priority_queue.hxx
similarity index 72%
copy from include/vigra/bucket_queue.hxx
copy to include/vigra/priority_queue.hxx
index dc9192c..e6416d0 100644
--- a/include/vigra/bucket_queue.hxx
+++ b/include/vigra/priority_queue.hxx
@@ -34,8 +34,8 @@
 /************************************************************************/
 
 
-#ifndef VIGRA_BUCKET_QUEUE_HXX
-#define VIGRA_BUCKET_QUEUE_HXX
+#ifndef VIGRA_PRIORITY_QUEUE_HXX
+#define VIGRA_PRIORITY_QUEUE_HXX
 
 #include "config.hxx"
 #include "error.hxx"
@@ -223,7 +223,7 @@ class BucketQueue<ValueType, true> // ascending queue
     Thus functor is called within <tt>push</tt> so that it does not need an
     extra argument.
 
-    <b>\#include</b> \<vigra/bucket_queue.hxx\><br>
+    <b>\#include</b> \<vigra/priority_queue.hxx\><br>
     Namespace: vigra
 */
 template <class ValueType,
@@ -281,7 +281,7 @@ class MappedBucketQueue
     types. Internally, it uses a <tt>std::priority_queue</tt>, but implements an 
     API where priorities and payload data are separate, like in \ref vigra::BucketQueue.
 
-    <b>\#include</b> \<vigra/bucket_queue.hxx\><br>
+    <b>\#include</b> \<vigra/priority_queue.hxx\><br>
     Namespace: vigra
 */
 template <class ValueType,
@@ -399,6 +399,198 @@ class PriorityQueue<ValueType, unsigned short, Ascending>
     {}
 };
 
+
+
+/** \brief Heap-based changable priority queue with a maximum number of elemements.
+
+    This pq allows to change the priorities of elements in the queue
+
+    <b>\#include</b> \<vigra/priority_queue.hxx\><br>
+    
+    Namespace: vigra
+*/
+template<class T,class COMPARE = std::less<T> >
+class ChangeablePriorityQueue {
+
+
+public:
+
+    typedef T priority_type;
+    typedef int ValueType;
+    typedef ValueType value_type;
+    typedef ValueType const_reference;
+
+
+
+    /// Create an empty ChangeablePriorityQueue which can contain atmost maxSize elements
+    ChangeablePriorityQueue(const size_t maxSize)  
+    : maxSize_(maxSize),
+      currentSize_(0),
+      heap_(maxSize_+1),
+      indices_(maxSize_+1, -1),
+      priorities_(maxSize_+1)
+    {
+        for(int i = 0; i <= maxSize_; i++)
+            indices_[i] = -1;
+    }
+    
+
+    void reset(){
+        currentSize_ = 0 ;
+        for(int i = 0; i <= maxSize_; i++)
+            indices_[i] = -1;
+    }
+    /// check if the PQ is empty
+    bool empty() const {
+        return currentSize_ == 0;
+    }
+ 
+    /// check if the PQ is empty
+    void clear() {
+        for(int i = 0; i < currentSize_; i++)
+        {
+            indices_[heap_[i+1]] = -1;
+            heap_[i+1] = -1;
+        }
+        currentSize_ = 0;
+    }
+ 
+    /// check if i is an index on the PQ
+    bool contains(const int i) const{
+        return indices_[i] != -1;
+    }
+ 
+    /// return the number of elements in the PQ
+    int size()const{
+        return currentSize_;
+    }
+ 
+
+    /** \brief Insert a index with a given priority.
+
+        If the queue contains i bevore this 
+        call the priority of the given index will
+        be changed
+    */
+    void push(const value_type i, const priority_type p) {
+        if(!contains(i)){
+            currentSize_++;
+            indices_[i] = currentSize_;
+            heap_[currentSize_] = i;
+            priorities_[i] = p;
+            bubbleUp(currentSize_);
+        }
+        else{
+            changePriority(i,p);
+        }
+    }
+ 
+    /** \brief get index with top priority
+    */
+    const_reference top() const {
+        return heap_[1];
+    }
+ 
+    /**\brief get top priority
+    */
+    priority_type topPriority() const {
+        return priorities_[heap_[1]];
+    }
+ 
+    /** \brief Remove the current top element.
+    */
+    void pop() {
+        const int min = heap_[1];
+        swapItems(1, currentSize_--);
+        bubbleDown(1);
+        indices_[min] = -1;
+        heap_[currentSize_+1] = -1;
+    }
+ 
+    /// returns the value associated with index i
+    priority_type priority(const value_type i) const{
+        return priorities_[i];
+    }
+  
+    /// deleqte the priority associated with index i
+    void deleteItem(const value_type i)   {
+        int ind = indices_[i];
+        swapItems(ind, currentSize_--);
+        bubbleUp(ind);
+        bubbleDown(ind);
+        indices_[i] = -1;
+    }
+    /** \brief change priority of a given index.
+        The index must be in the queue!
+        Call push to auto insert / change .
+    */
+    void changePriority(const value_type i,const priority_type p)  {
+        if(_gt(p,priorities_[i])){
+            priorities_[i] = p;
+            bubbleDown(indices_[i]);
+        }
+        else if(_lt(p,priorities_[i])) {
+            priorities_[i] = p;
+            bubbleUp(indices_[i]);
+        }
+    }
+private:
+    
+
+    void swapItems(const int i,const  int j) {
+        std::swap(heap_[i],heap_[j]);
+        indices_[heap_[i]] = i; 
+        indices_[heap_[j]] = j;
+    }
+ 
+    void bubbleUp(int k)    {
+        while(k > 1 && _gt( priorities_[heap_[k/2]],priorities_[heap_[k]]))   {
+            swapItems(k, k/2);
+            k = k/2;
+        }
+    }
+ 
+    void bubbleDown(int k)  {
+        int j;
+        while(2*k <= currentSize_) {
+            j = 2*k;
+            if(j < currentSize_ && _gt(priorities_[heap_[j]] , priorities_[heap_[j+1]]) )
+                j++;
+            if( _leqt(priorities_[heap_[k]] , priorities_[heap_[j]]))
+                break;
+            swapItems(k, j);
+            k = j;
+        }
+    }
+
+
+    bool _lt(const T & a,const T & b)const{
+        return comp_(a,b);
+    }
+    bool _leqt(const T & a,const T & b)const{
+        return !comp_(b,a);
+    }
+    bool _eq(const T & a,const T & b)const{
+        return !comp_(a,b) && !comp_(b,a);
+    }
+    bool _gt(const T & a,const T & b)const{
+        return !_eq(a,b) && !comp_(a,b);
+    }
+    bool _geqt(const T & a,const T & b)const{
+        return !comp_(a,b);
+    }
+ 
+
+    size_t maxSize_;
+    size_t currentSize_;
+    std::vector<int> heap_;
+    std::vector<int> indices_;
+    std::vector<T>   priorities_;
+    COMPARE          comp_;
+
+};
+
+
 } // namespace vigra
 
-#endif // VIGRA_BUCKET_QUEUE_HXX
+#endif // VIGRA_PRIORITY_QUEUE_HXX
diff --git a/include/vigra/project2ellipse.hxx b/include/vigra/project2ellipse.hxx
index f57fe01..e816a65 100644
--- a/include/vigra/project2ellipse.hxx
+++ b/include/vigra/project2ellipse.hxx
@@ -45,7 +45,7 @@ namespace vigra{
 
 //---------------------------------------------------------------------------
 
-void projectEllipse2D_FirstQuad (double &vx, double &vy, double a, double b, const double eps, const int iter_max){                
+inline void projectEllipse2D_FirstQuad (double &vx, double &vy, double a, double b, const double eps, const int iter_max){                
   
   double t=0,tmin,tmax,d1,d2,f,x1,y1,l;                      
   int i;
@@ -84,7 +84,7 @@ void projectEllipse2D_FirstQuad (double &vx, double &vy, double a, double b, con
 }
 
 
-void projectEllipse2D(double &vx, double &vy, const double _a,const double _b,const double eps,const int max_iter){
+inline void projectEllipse2D(double &vx, double &vy, const double _a,const double _b,const double eps,const int max_iter){
   
   //double err;
   double a=_a,b=_b;
@@ -174,4 +174,4 @@ void projectEllipse2D(double &vx, double &vy, const double _a,const double _b,co
 }
   } //closing namespace detail
 } //closing namespace vigra
-#endif // VIGRA_PROJECT2ELLIPSE_HXX
\ No newline at end of file
+#endif // VIGRA_PROJECT2ELLIPSE_HXX
diff --git a/include/vigra/projective_registration.hxx b/include/vigra/projective_registration.hxx
new file mode 100644
index 0000000..ee98719
--- /dev/null
+++ b/include/vigra/projective_registration.hxx
@@ -0,0 +1,245 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2007-2014 by Benjamin Seppke                 */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_PROJECTIVE_REGISTRATION_HXX
+#define VIGRA_PROJECTIVE_REGISTRATION_HXX
+
+#include "mathutil.hxx"
+#include "matrix.hxx"
+#include "linear_solve.hxx"
+#include "tinyvector.hxx"
+#include "splineimageview.hxx"
+
+namespace vigra
+{
+
+/** \addtogroup Registration Image Registration
+ */
+//@{
+
+/********************************************************/
+/*                                                      */
+/*     projectiveMatrix2DFromCorrespondingPoints        */
+/*                                                      */
+/********************************************************/
+
+/** \brief Create homogeneous matrix that maps corresponding points onto each other.
+
+    For use with \ref projectiveWarpImage(). Since four corresponding points are needed to be given,
+    the matrix will compute a full projective transform.
+ */
+template <class SrcPointIterator, class DestPointIterator>
+linalg::TemporaryMatrix<double>
+projectiveMatrix2DFromCorrespondingPoints(SrcPointIterator s, SrcPointIterator send, DestPointIterator d)
+{
+    //Calculate the matrix using least squares of all points of points like the result is:
+    // ( x2 )   ( s_x        r1        t_x )   ( x1 )
+    // ( y2 ) = (  r2        s_y        t_y ) * ( y1 )
+    // (  1 )   (  p1        p2        1   )   (  1 )
+    int size = send - s;
+
+    vigra_assert(size >= 4,
+                 "projectiveMatrix2DFromCorrespondingPoints(): need at least four corresponding points.");
+
+    vigra::Matrix<double> A(2*size,8, 0.0), b(2*size,1),  res(8,1);
+    for (int i =0; i<size; ++i, ++s, ++d)
+    {
+        //m_00                m_01                m_02                m_10                    m_11                    m_12                m_20                                m_21
+        //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+        A(i,0)=(*d)[0];        A(i,1)=(*d)[1];        A(i,2)=1;            A(i,3)=0;                A(i,4)=0;                A(i,5)=0;            A(i,6)=-1*((*d)[0])*((*s)[0]);            A(i,7)=-1*((*d)[1])*((*s)[0]);
+        b(i,0)=(*s)[0];
+
+        A(size+i,0)=0;        A(size+i,1)=0;        A(size+i,2)=0;        A(size+i,3)=(*d)[0];    A(size+i,4)=(*d)[1];    A(size+i,5)=1;        A(size+i,6)=-1*((*d)[0])*((*s)[1]);        A(size+i,7)=-1*((*d)[1])*((*s)[1]);
+        b(size+i,0)=(*s)[1];
+
+    }
+
+    vigra_assert(linearSolve(A, b, res),
+                "projectiveMatrix2DFromCorrespondingPoints(): singular solution matrix.");
+
+    linalg::TemporaryMatrix<double> projectiveMat(3,3);
+    projectiveMat(0,0) = res(0,0);        projectiveMat(0,1) = res(1,0);        projectiveMat(0,2) = res(2,0);
+    projectiveMat(1,0) = res(3,0);        projectiveMat(1,1) = res(4,0);        projectiveMat(1,2) = res(5,0);
+    projectiveMat(2,0) = res(6,0);        projectiveMat(2,1) = res(7,0);        projectiveMat(2,2) = 1;
+
+    return projectiveMat;
+}
+
+/********************************************************/
+/*                                                      */
+/*                projectiveWarpImage                   */
+/*                                                      */
+/********************************************************/
+
+/** \brief Warp an image according to an projective transformation.
+
+    The matrix can be computed from a set of correspondung points 
+    using \ref projectiveMatrix2DFromCorrespondingPoints().
+
+    <b> Declarations:</b>
+
+    <b>\#include</b> \<vigra/projective_registration.hxx\><br>
+    Namespace: vigra
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <int ORDER, class T,
+                  class T2, class S2,
+                  class C>
+        void
+        projectiveWarpImage(SplineImageView<ORDER, T> const & src,
+                            MultiArrayView<2, T2, S2> dest,
+                            MultiArrayView<2, double, C> const & projectiveMatrix);
+    }
+    \endcode
+
+    \deprecatedAPI{projectiveWarpImage}
+    pass \ref ImageIterators and \ref DataAccessors :
+
+    pass arguments explicitly:
+    \code
+    namespace vigra {
+        template <int ORDER, class T,
+                class DestIterator, class DestAccessor,
+                class C>
+        void projectiveWarpImage(SplineImageView<ORDER, T> const & src,
+                                 DestIterator dul, DestIterator dlr, DestAccessor dest,
+                                 MultiArrayView<2, double, C> const & projectiveMatrix);
+    }
+    \endcode
+
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <int ORDER, class T,
+                class DestIterator, class DestAccessor,
+                class C>
+        void projectiveWarpImage(SplineImageView<ORDER, T> const & src,
+                                 triple<DestIterator, DestIterator, DestAccessor> dest,
+                                 MultiArrayView<2, double, C> const & projectiveMatrix);
+    }
+    \endcode
+    \deprecatedEnd
+
+    The algorithm applies the given \a projectiveMatrix to the <i>destination coordinates</i> and copies
+    the image value from the resulting source coordinates, using the given SplineImageView \a src for interpolation.
+    If the resulting coordinate is outside the source image, nothing will be written at that destination point.
+
+    \code
+        for all dest pixels:
+            currentSrcCoordinate = projectiveMatrix * currentDestCoordinate;
+            if src.isInside(currentSrcCoordinate):
+                dest[currentDestCoordinate] = src[currentSrcCoordinate]; // copy an interpolated value
+    \endcode
+
+    The matrix represent a 2-dimensional projective transform by means of homogeneous coordinates,
+    i.e. it must be a 3x3 matrix whose last row is (p1,p2,1).
+
+    <b> Required Interface:</b>
+
+    \code
+    DestImageIterator dest_upperleft;
+
+    double x = ..., y = ...;
+
+    if (spline.isInside(x,y))
+        dest_accessor.set(spline(x, y), dest_upperleft);
+
+    \endcode
+
+    <b>See also:</b> Functions to specify projective transformation: \ref translationMatrix2D(), \ref scalingMatrix2D(),
+                    \ref shearMatrix2D(), \ref rotationMatrix2DRadians(), \ref rotationMatrix2DDegrees() and \ref projectiveMatrix2DFromCorrespondingPoints()
+*/
+doxygen_overloaded_function(template <...> void projectiveWarpImage)
+
+template <int ORDER, class T,
+          class DestIterator, class DestAccessor,
+          class C>
+void projectiveWarpImage(SplineImageView<ORDER, T> const & src,
+                     DestIterator dul, DestIterator dlr, DestAccessor dest,
+                     MultiArrayView<2, double, C> const & projectiveMatrix)
+{
+    vigra_precondition(rowCount(projectiveMatrix) == 3 && columnCount(projectiveMatrix) == 3 && projectiveMatrix(2,2) == 1.0,
+        "projectiveWarpImage(): matrix doesn't represent an projective transformation with homogeneous 2D coordinates.");
+
+
+    double w = dlr.x - dul.x;
+    double h = dlr.y - dul.y;
+
+    for(double y = 0.0; y < h; ++y, ++dul.y)
+    {
+        typename DestIterator::row_iterator rd = dul.rowIterator();
+        for(double x=0.0; x < w; ++x, ++rd)
+        {
+            double fac = 1.0/(x*projectiveMatrix(2,0) + y*projectiveMatrix(2,1) + 1);
+            double sx = (x*projectiveMatrix(0,0) + y*projectiveMatrix(0,1) + projectiveMatrix(0,2)) * fac;
+            double sy = (x*projectiveMatrix(1,0) + y*projectiveMatrix(1,1) + projectiveMatrix(1,2)) * fac;
+            if(src.isInside(sx, sy))
+                dest.set(src(sx, sy), rd);
+        }
+    }
+}
+
+template <int ORDER, class T,
+          class DestIterator, class DestAccessor,
+          class C>
+inline
+void projectiveWarpImage(SplineImageView<ORDER, T> const & src,
+                     triple<DestIterator, DestIterator, DestAccessor> dest,
+                     MultiArrayView<2, double, C> const & projectiveMatrix)
+{
+    projectiveWarpImage(src, dest.first, dest.second, dest.third, projectiveMatrix);
+}
+
+
+template <int ORDER, class T,
+          class T2, class S2,
+          class C>
+inline
+void projectiveWarpImage(SplineImageView<ORDER, T> const & src,
+                          MultiArrayView<2, T2, S2> dest,
+                          MultiArrayView<2, double, C> const & projectiveMatrix)
+{
+    projectiveWarpImage(src, destImageRange(dest), projectiveMatrix);
+}
+
+
+//@}
+
+} // namespace vigra
+
+
+#endif /* VIGRA_PROJECTIVE_REGISTRATION_HXX */
diff --git a/include/vigra/python_graph.hxx b/include/vigra/python_graph.hxx
new file mode 100644
index 0000000..7a02091
--- /dev/null
+++ b/include/vigra/python_graph.hxx
@@ -0,0 +1,839 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2011-2012 Stefan Schmidt and Ullrich Koethe            */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+/**
+ * This header provides definitions of graph-related types
+ * and optionally provides a gateway to popular graph libraries
+ * (for now, BGL is supported).
+ */
+
+#ifndef VIGRA_PYTHON_GRAPH_HXX
+#define VIGRA_PYTHON_GRAPH_HXX
+
+/*boost*/
+#include <boost/python.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+
+/*vigra*/
+#include <vigra/graphs.hxx>
+#include <vigra/numpy_array.hxx>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/graph_generalization.hxx>
+#include <vigra/multi_array.hxx>
+#include <vigra/graphs.hxx>
+#include <vigra/priority_queue.hxx>
+#include <vigra/merge_graph_adaptor.hxx>
+namespace vigra{
+
+
+
+
+
+
+template<class MAP>
+struct GraphMapTypeTraits;
+
+template< unsigned int DIM,class T>
+struct GraphMapTypeTraits<NumpyArray<DIM,T> >{
+    typedef typename NumpyArray<DIM,T>::value_type Value;
+    typedef Value &                                Reference;
+    typedef const Value  &                         ConstReference;
+};
+
+
+    
+template<class GRAPH>
+struct NodeHolder :  GRAPH::Node
+{
+    typedef typename GRAPH::Node Node;
+    NodeHolder(const lemon::Invalid & iv = lemon::INVALID)
+    : Node(lemon::INVALID),
+      graph_(NULL)
+    {}
+    NodeHolder(const GRAPH & g , const Node & item)
+    : Node(item),
+      graph_(&g)
+    {}
+
+    typename GRAPH::index_type id()const{
+        return graph_->id(*this);
+    }
+
+    typename GraphDescriptorToMultiArrayIndex<GRAPH>::IntrinsicNodeMapShape
+    intrinsicNodeCoordinate()const{
+        return GraphDescriptorToMultiArrayIndex<GRAPH>::intrinsicNodeCoordinate(*graph_,*this);
+    }
+
+    const GRAPH * graph_;
+};
+
+
+
+template<class GRAPH>
+struct EdgeHolder : GRAPH::Edge
+{
+
+    typedef typename GRAPH::Edge Edge;
+    EdgeHolder(const lemon::Invalid & iv = lemon::INVALID)
+    : Edge(lemon::INVALID),
+      graph_(NULL)
+    {}
+    EdgeHolder(const GRAPH & g , const Edge & item)
+    : Edge(item),
+      graph_(&g)
+    {}
+
+    typename GRAPH::index_type id()const{
+        return graph_->id(*this);
+    }
+
+    NodeHolder<GRAPH> u()const{
+        return NodeHolder<GRAPH>(*graph_,graph_->u(*this));
+    }
+    NodeHolder<GRAPH> v()const{
+        return NodeHolder<GRAPH>(*graph_,graph_->v(*this));
+    }
+
+    typename GraphDescriptorToMultiArrayIndex<GRAPH>::IntrinsicEdgeMapShape
+    intrinsicEdgeCoordinate()const{
+        return GraphDescriptorToMultiArrayIndex<GRAPH>::intrinsicEdgeCoordinate(*graph_,*this);
+    }
+
+    const GRAPH * graph_; 
+};
+
+
+
+template<class GRAPH>
+struct ArcHolder: GRAPH::Arc {
+    typedef typename GRAPH::Arc Arc;
+    ArcHolder(const lemon::Invalid & iv = lemon::INVALID)
+    : Arc(lemon::INVALID),
+      graph_(NULL)
+    {}
+    ArcHolder(const GRAPH & g , const Arc & item)
+    : Arc(item),
+      graph_(&g)
+    {}
+
+    typename GRAPH::index_type id()const{
+        return graph_->id(*this);
+    }
+
+    typename GraphDescriptorToMultiArrayIndex<GRAPH>::IntrinsicArcMapShape
+    intrinsicArcCoordinate()const{
+        return GraphDescriptorToMultiArrayIndex<GRAPH>::intrinsicArcCoordinate(*graph_,*this);
+    }
+
+
+    const GRAPH * graph_;
+};
+
+
+namespace detail_python_graph{
+
+template<class GRAPH>
+struct ArcToTargetNodeHolder{
+    typedef typename GRAPH::Node Node;
+    typedef typename GRAPH::Arc Arc;
+    ArcToTargetNodeHolder(const GRAPH & graph)
+    : graph_(&graph){
+    }
+    NodeHolder<GRAPH> operator()(const Arc & arc)const{
+        return NodeHolder<GRAPH>(*graph_,graph_->target(arc));
+    }
+    const GRAPH * graph_;
+};
+
+template<class GRAPH>
+struct ArcToEdgeHolder{
+    typedef typename GRAPH::Edge Edge;
+    typedef typename GRAPH::Arc Arc;
+    ArcToEdgeHolder(const GRAPH & graph)
+    : graph_(&graph){
+    }
+    EdgeHolder<GRAPH> operator()(const Arc & arc)const{
+        const Edge edge(arc);
+        return EdgeHolder<GRAPH>(*graph_,edge);
+    }
+    const GRAPH * graph_;
+};
+
+template<class GRAPH>
+struct ArcToArcHolder{
+    typedef typename GRAPH::Edge Edge;
+    typedef typename GRAPH::Arc Arc;
+    ArcToArcHolder(const GRAPH & graph)
+    : graph_(&graph){
+    }
+    ArcHolder<GRAPH> operator()(const Arc & arc)const{
+        return ArcHolder<GRAPH>(*graph_,arc);
+    }
+    const GRAPH * graph_;
+};
+
+
+template<class GRAPH>
+struct NodeToNodeHolder{
+    typedef typename GRAPH::Node Node;
+    NodeToNodeHolder(const GRAPH & graph)
+    : graph_(&graph){
+    }
+    NodeHolder<GRAPH> operator()(const Node & node)const{
+        return NodeHolder<GRAPH>(*graph_,node);
+    }
+    const GRAPH * graph_;
+};
+
+template<class GRAPH>
+struct EdgeToEdgeHolder{
+    typedef typename GRAPH::Edge Edge;
+    EdgeToEdgeHolder(const GRAPH & graph)
+    : graph_(&graph){
+    }
+    EdgeHolder<GRAPH> operator()(const Edge & edge)const{
+        return EdgeHolder<GRAPH>(*graph_,edge);
+    }
+    const GRAPH * graph_;
+};
+
+} // end namespace detail_python_graph
+
+
+
+template<class GRAPH>
+struct NodeIteratorHolder{
+    typedef typename GRAPH::Node Node;
+    typedef typename GRAPH::NodeIt Iter;
+    typedef detail_python_graph::NodeToNodeHolder<GRAPH> Transform;
+    typedef boost::transform_iterator<Transform ,Iter ,NodeHolder<GRAPH>, NodeHolder<GRAPH> > const_iterator;
+    NodeIteratorHolder(const GRAPH & graph,const Node & node = Node(lemon::INVALID) )
+    : graph_(&graph),
+      node_(node){
+    }
+    const_iterator begin()const{
+
+        Iter iter = GraphIteratorAccessor<GRAPH>::nodesBegin(*graph_);
+        return const_iterator(iter,Transform(*graph_));
+    }
+    const_iterator end()const{
+        Iter iter = GraphIteratorAccessor<GRAPH>::nodesEnd(*graph_);
+        return const_iterator(iter,Transform(*graph_));
+    }
+    const GRAPH * graph_;
+    Node node_;
+};
+
+template<class GRAPH>
+struct EdgeIteratorHolder{
+    typedef typename GRAPH::Edge Edge;
+    typedef typename GRAPH::EdgeIt Iter;
+    typedef detail_python_graph::EdgeToEdgeHolder<GRAPH> Transform;
+    typedef boost::transform_iterator<Transform ,Iter ,EdgeHolder<GRAPH>, EdgeHolder<GRAPH> > const_iterator;
+    EdgeIteratorHolder(const GRAPH & graph,const Edge & edge = Edge(lemon::INVALID) )
+    : graph_(&graph),
+      edge_(edge){
+    }
+    const_iterator begin()const{
+
+        Iter iter = GraphIteratorAccessor<GRAPH>::edgesBegin(*graph_);
+        return const_iterator(iter,Transform(*graph_));
+    }
+    const_iterator end()const{
+        Iter iter = GraphIteratorAccessor<GRAPH>::edgesEnd(*graph_);
+        return const_iterator(iter,Transform(*graph_));
+    }
+    const GRAPH * graph_;
+    Edge edge_;
+};
+
+
+template<class GRAPH>
+struct NeighbourNodeIteratorHolder{
+    typedef typename GRAPH::Node Node;
+    typedef typename GRAPH::OutArcIt Iter;
+    typedef detail_python_graph::ArcToTargetNodeHolder<GRAPH> Transform;
+    typedef boost::transform_iterator<Transform ,Iter ,NodeHolder<GRAPH>, NodeHolder<GRAPH> > const_iterator;
+    NeighbourNodeIteratorHolder(const GRAPH & graph,const Node & node)
+    : graph_(&graph),
+      node_(node){
+    }
+    const_iterator begin()const{
+        Iter iter = GraphIteratorAccessor<GRAPH>::outArcBegin(*graph_,node_);
+        return const_iterator(iter,Transform(*graph_));
+    }
+    const_iterator end()const{
+        Iter iter = GraphIteratorAccessor<GRAPH>::outArcEnd(*graph_,node_);
+        return const_iterator(iter,Transform(*graph_));
+    }
+    const GRAPH * graph_;
+    Node node_;
+};
+
+
+template<class GRAPH>
+struct IncEdgeIteratorHolder{
+    typedef typename GRAPH::Node Node;
+    typedef typename GRAPH::Edge Edge;
+    typedef typename GRAPH::OutArcIt Iter;
+    typedef detail_python_graph::ArcToArcHolder<GRAPH> Transform;
+    typedef boost::transform_iterator<Transform ,Iter ,ArcHolder<GRAPH>, ArcHolder<GRAPH> > const_iterator;
+    IncEdgeIteratorHolder(const GRAPH & graph,const Node & node)
+    : graph_(&graph),
+      node_(node){
+    }
+    const_iterator begin()const{
+        Iter iter = GraphIteratorAccessor<GRAPH>::outArcBegin(*graph_,node_);
+        return const_iterator(iter,Transform(*graph_));
+    }
+    const_iterator end()const{
+        Iter iter = GraphIteratorAccessor<GRAPH>::outArcEnd(*graph_,node_);
+        return const_iterator(iter,Transform(*graph_));
+    }
+    const GRAPH * graph_;
+    Node node_;
+};
+
+
+template<class G,class AV>
+class NumpyScalarEdgeMap{
+
+public:
+    typedef G  Graph;
+    typedef AV ArrayView;
+    typedef typename  Graph::Edge                Key;
+    typedef typename  ArrayView::value_type      Value;
+    typedef typename  ArrayView::reference       Reference;
+    typedef typename  ArrayView::const_reference ConstReference;
+
+    typedef typename  Graph::Edge                key_type;
+    typedef typename  ArrayView::value_type      value_type;
+    typedef typename  ArrayView::reference       reference;
+    typedef typename  ArrayView::const_reference const_reference;
+
+    NumpyScalarEdgeMap()
+    :   graph_(NULL),
+        array_(){
+    }
+
+    NumpyScalarEdgeMap(const Graph & graph,ArrayView array)
+    :   graph_(&graph),
+        array_(array){
+    }
+
+    Reference operator[](const Key & key){
+        return array_[GraphDescriptorToMultiArrayIndex<Graph>::intrinsicEdgeCoordinate(*graph_,key)];
+    }
+    ConstReference operator[](const Key & key)const{
+        return   array_[GraphDescriptorToMultiArrayIndex<Graph>::intrinsicEdgeCoordinate(*graph_,key)];
+    }
+private:
+    bool any()const{
+        return array_.any();
+    }
+    const Graph * graph_;
+    MultiArrayView<IntrinsicGraphShape<Graph>::IntrinsicEdgeMapDimension,Value> array_;
+
+};
+
+template<class G,class AV>
+class NumpyScalarNodeMap{
+
+public:
+    typedef G  Graph;
+    typedef AV ArrayView;
+    typedef typename  Graph::Node                Key;
+    typedef typename  ArrayView::value_type      Value;
+    typedef typename  ArrayView::reference       Reference;
+    typedef typename  ArrayView::const_reference ConstReference;
+
+    typedef typename  Graph::Node                key_type;
+    typedef typename  ArrayView::value_type      value_type;
+    typedef typename  ArrayView::reference       reference;
+    typedef typename  ArrayView::const_reference const_reference;
+    //typedef Value &                                Reference;
+    //typedef const Value &                          ConstReference;
+
+    NumpyScalarNodeMap()
+    :   graph_(NULL),
+        array_(){
+    }
+
+    NumpyScalarNodeMap(const Graph & graph,ArrayView array)
+    :   graph_(&graph),
+        array_(array){
+    }
+
+    Reference operator[](const Key & key){
+        return array_[GraphDescriptorToMultiArrayIndex<Graph>::intrinsicNodeCoordinate(*graph_,key)];
+    }
+    ConstReference operator[](const Key & key)const{
+        return   array_[GraphDescriptorToMultiArrayIndex<Graph>::intrinsicNodeCoordinate(*graph_,key)];
+    }
+    bool any()const{
+        return array_.any();
+    }
+private:
+    const Graph * graph_;
+    MultiArrayView<IntrinsicGraphShape<Graph>::IntrinsicNodeMapDimension,Value> array_;
+
+};
+
+
+template<class G,class AV>
+class NumpyMultibandNodeMap{
+
+public:
+    typedef G  Graph;
+    typedef AV ArrayView;
+    typedef typename  Graph::Node                Key;
+    typedef typename  Graph::Node                key_type;
+
+    //typedef typename  ArrayView::value_type      Value;
+    //typedef typename  ArrayView::reference       Reference;
+    //typedef typename  ArrayView::const_reference ConstReference;
+
+    typedef  MultiArray<1,typename AV::value_type>           Value;
+    typedef  MultiArrayView<1,typename AV::value_type>       Reference;
+    typedef  MultiArrayView<1,typename AV::value_type> ConstReference;
+    typedef  MultiArray<1,typename AV::value_type>           value_type;
+    typedef  MultiArrayView<1,typename AV::value_type>       reference;
+    typedef  MultiArrayView<1,typename AV::value_type> const_reference;
+    //typedef Value &                                Reference;
+    //typedef const Value &                          ConstReference;
+
+    NumpyMultibandNodeMap()
+    :   graph_(NULL),
+        array_(){
+    }
+
+    NumpyMultibandNodeMap(const Graph & graph,ArrayView array)
+    :   graph_(&graph),
+        array_(array){
+    }
+
+    Reference operator[](const Key & key){
+        return array_[GraphDescriptorToMultiArrayIndex<Graph>::intrinsicNodeCoordinate(*graph_,key)];
+    }
+    ConstReference operator[](const Key & key)const{
+        return array_[GraphDescriptorToMultiArrayIndex<Graph>::intrinsicNodeCoordinate(*graph_,key)];
+    }
+    bool any()const{
+        return array_.any();
+    }
+private:
+    const Graph * graph_;
+    mutable AV array_;
+
+};
+
+
+template<class G,class AV>
+class NumpyMultibandEdgeMap{
+
+public:
+    typedef G  Graph;
+    typedef AV ArrayView;
+    typedef typename  Graph::Edge                Key;
+    typedef typename  Graph::Edge                key_type;
+
+    //typedef typename  ArrayView::value_type      Value;
+    //typedef typename  ArrayView::reference       Reference;
+    //typedef typename  ArrayView::const_reference ConstReference;
+
+    typedef  MultiArray<1,typename AV::value_type>           Value;
+    typedef  MultiArrayView<1,typename AV::value_type>       Reference;
+    typedef  MultiArrayView<1,typename AV::value_type> ConstReference;
+    typedef  MultiArray<1,typename AV::value_type>           value_type;
+    typedef  MultiArrayView<1,typename AV::value_type>       reference;
+    typedef  MultiArrayView<1,typename AV::value_type> const_reference;
+    //typedef Value &                                Reference;
+    //typedef const Value &                          ConstReference;
+
+    NumpyMultibandEdgeMap()
+    :   graph_(NULL),
+        array_(){
+    }
+
+    NumpyMultibandEdgeMap(const Graph & graph,ArrayView array)
+    :   graph_(&graph),
+        array_(array){
+    }
+
+    Reference operator[](const Key & key){
+        return array_[GraphDescriptorToMultiArrayIndex<Graph>::intrinsicEdgeCoordinate(*graph_,key)];
+    }
+    ConstReference operator[](const Key & key)const{
+        return   array_[GraphDescriptorToMultiArrayIndex<Graph>::intrinsicEdgeCoordinate(*graph_,key)];
+    }
+    bool any()const{
+        return array_.any();
+    }
+private:
+    const Graph * graph_;
+    mutable AV array_;
+
+};
+
+
+
+
+
+
+// tagged shape for lemon graphs
+// edge map / node map / arc map 
+template<class G>
+class TaggedGraphShape{
+public:
+    typedef G Graph;
+    const static unsigned int ND = IntrinsicGraphShape<Graph>::IntrinsicNodeMapDimension;
+    const static unsigned int ED = IntrinsicGraphShape<Graph>::IntrinsicEdgeMapDimension;
+    const static unsigned int AD = IntrinsicGraphShape<Graph>::IntrinsicArcMapDimension;
+    static TaggedShape  taggedNodeMapShape(const Graph & graph){
+        return NumpyArray<ND,int>::ArrayTraits::taggedShape(IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(graph),"n");
+    }
+    static TaggedShape  taggedEdgeMapShape(const Graph & graph){
+        return NumpyArray<ED,int>::ArrayTraits::taggedShape(IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(graph),"e");
+    }
+    static TaggedShape  taggedArcMapShape(const Graph & graph){
+        return NumpyArray<AD,int>::ArrayTraits::taggedShape(IntrinsicGraphShape<Graph>::intrinsicArcMapShape(graph),"e");
+    }
+
+    static AxisInfo  axistagsNodeMap(const Graph & graph){
+        return AxisInfo("n");
+    }
+    static AxisInfo  axistagsEdgeMap(const Graph & graph){
+        return AxisInfo("e");
+    }
+    static AxisTags  axistagsArcMap(const Graph & graph){
+        return AxisInfo("e");
+    }
+};
+
+// macro to specialize TaggedGraphShape for 
+// grid graphs up to 4 dimensions
+#define VIGRA_MAKE_TAGGED_GRAPH_SHAPE_MACRO(DIM,tn,te,ta) \
+template<class BOOST_DIRECTED_TAG> \
+class TaggedGraphShape<GridGraph<DIM,BOOST_DIRECTED_TAG> >{ \
+public: \
+    typedef GridGraph<DIM,BOOST_DIRECTED_TAG> Graph; \
+    const static unsigned int ND = IntrinsicGraphShape<Graph>::IntrinsicNodeMapDimension; \
+    const static unsigned int ED = IntrinsicGraphShape<Graph>::IntrinsicEdgeMapDimension; \
+    const static unsigned int AD = IntrinsicGraphShape<Graph>::IntrinsicArcMapDimension; \
+    static TaggedShape  taggedNodeMapShape(const Graph & graph){ \
+       return NumpyArray<ND,int>::ArrayTraits::taggedShape(IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(graph),tn); \
+    } \
+    static TaggedShape  taggedEdgeMapShape(const Graph & graph){  \
+       return NumpyArray<ED,int>::ArrayTraits::taggedShape(IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(graph),te);  \
+    } \
+    static TaggedShape  taggedArcMapShape(const Graph & graph){  \
+       return NumpyArray<AD,int>::ArrayTraits::taggedShape(IntrinsicGraphShape<Graph>::intrinsicArcMapShape(graph),ta);  \
+    } \
+    static AxisInfo  axistagsNodeMap(const Graph & graph){ \
+        return AxisInfo(tn); \
+    } \
+    static AxisInfo  axistagsEdgeMap(const Graph & graph){ \
+        return AxisInfo(te); \
+    } \
+    static AxisTags  axistagsArcMap(const Graph & graph){ \
+        return AxisInfo(ta); \
+    } \
+};
+
+VIGRA_MAKE_TAGGED_GRAPH_SHAPE_MACRO(1,"x","xe","xe");
+VIGRA_MAKE_TAGGED_GRAPH_SHAPE_MACRO(2,"xy","xye","xye");
+VIGRA_MAKE_TAGGED_GRAPH_SHAPE_MACRO(3,"xyz","xyze","xyze");
+VIGRA_MAKE_TAGGED_GRAPH_SHAPE_MACRO(4,"xyzt","xyzte","xyzte");
+
+#undef VIGRA_MAKE_TAGGED_GRAPH_SHAPE_MACRO
+
+
+/*
+// TODO ASK UKOETHE FOR HELP HERE
+template<unsigned int G_DIM ,class T,class G,unsigned int OG_DIM>
+void reshapeNodeMapIfEmpty(
+    const G & graph,
+    const NumpyArray<OG_DIM,T> & otherArray,
+    NumpyArray<G_DIM ,T> & toReshapeArray
+){
+    const static unsigned int GraphNodeMapDim = IntrinsicGraphShape<G>::IntrinsicNodeMapDimension;
+    const static unsigned int OutShapeLength  = GraphNodeMapDim == G_DIM ? G_DIM  : GraphNodeMapDim +1;
+    typedef typename MultiArray<OutShapeLength,int>::difference_type OutShapeType;
+    OutShapeType outShape;
+    for(size_t d=0;d<GraphNodeMapDim;++d){
+        outShape[d]=IntrinsicGraphShape<G>::intrinsicNodeMapShape(graph)[d];
+    }
+    if( G_DIM == GraphNodeMapDim + 1){
+
+        outShape[GraphNodeMapDim]=otherArray.shape(OG_DIM);
+        if(GraphNodeMapDim==1)
+            toReshapeArray.reshapeIfEmpty( NumpyArray<G_DIM ,T>::ArrayTraits::taggedShape(outShape,"xc"));
+        else if(GraphNodeMapDim==2)
+            toReshapeArray.reshapeIfEmpty( NumpyArray<G_DIM ,T>::ArrayTraits::taggedShape(outShape,"xyc"));
+        else if(GraphNodeMapDim==3)
+            toReshapeArray.reshapeIfEmpty( NumpyArray<G_DIM ,T>::ArrayTraits::taggedShape(outShape,"xyzc"));
+        else if(GraphNodeMapDim==4)
+            toReshapeArray.reshapeIfEmpty( NumpyArray<G_DIM ,T>::ArrayTraits::taggedShape(outShape,"xyztc"));
+        else
+            throw std::runtime_error("reshapeNodeMapIfEmpty does onnly support graphs with an intrinsic node map shape <=4");
+    }
+    else{
+        toReshapeArray.reshapeIfEmpty(outShape);
+    }
+}
+*/
+
+
+
+template<class G,class T>
+struct NumpyNodeMap
+: 
+    IfBool<
+        IsMultiband<T>::value,
+        NumpyMultibandNodeMap< G ,  NumpyArray<IntrinsicGraphShape<G>::IntrinsicNodeMapDimension+1,T> > , 
+        NumpyScalarNodeMap<    G ,  NumpyArray<IntrinsicGraphShape<G>::IntrinsicNodeMapDimension  ,T> >
+    >::type
+
+{
+    typedef typename IfBool<
+        IsMultiband<T>::value,
+        NumpyArray<IntrinsicGraphShape<G>::IntrinsicNodeMapDimension+1,T> , 
+        NumpyArray<IntrinsicGraphShape<G>::IntrinsicNodeMapDimension  ,T>
+    >::type NumpyArrayType;
+
+
+    typedef typename IfBool<
+        IsMultiband<T>::value,
+        NumpyMultibandNodeMap< G ,  NumpyArray<IntrinsicGraphShape<G>::IntrinsicNodeMapDimension+1,T> > , 
+        NumpyScalarNodeMap<    G ,  NumpyArray<IntrinsicGraphShape<G>::IntrinsicNodeMapDimension  ,T> >
+    >::type BaseType;
+
+    NumpyNodeMap(const G & g, NumpyArrayType numpyArray)
+    :BaseType(g,numpyArray){
+    }
+
+};
+
+
+template<class G,class T>
+struct NumpyEdgeMap
+: 
+    IfBool<
+        IsMultiband<T>::value,
+        NumpyMultibandEdgeMap< G ,  NumpyArray<IntrinsicGraphShape<G>::IntrinsicEdgeMapDimension+1,T> > , 
+        NumpyScalarEdgeMap<    G ,  NumpyArray<IntrinsicGraphShape<G>::IntrinsicEdgeMapDimension  ,T> >
+    >::type
+
+{
+    typedef typename IfBool<
+        IsMultiband<T>::value,
+        NumpyArray<IntrinsicGraphShape<G>::IntrinsicEdgeMapDimension+1,T> , 
+        NumpyArray<IntrinsicGraphShape<G>::IntrinsicEdgeMapDimension  ,T>
+    >::type NumpyArrayType;
+
+
+    typedef typename IfBool<
+        IsMultiband<T>::value,
+        NumpyMultibandEdgeMap< G ,  NumpyArray<IntrinsicGraphShape<G>::IntrinsicEdgeMapDimension+1,T> > , 
+        NumpyScalarEdgeMap<    G ,  NumpyArray<IntrinsicGraphShape<G>::IntrinsicEdgeMapDimension  ,T> >
+    >::type BaseType;
+
+    NumpyEdgeMap(const G & g, NumpyArrayType numpyArray)
+    :BaseType(g,numpyArray){
+    }
+
+};
+
+
+
+template<class G,class T>
+struct PyEdgeMapTraits{
+    typedef NumpyEdgeMap<G,T> Map;
+    typedef typename IfBool<
+        IsMultiband<T>::value,
+        NumpyArray<IntrinsicGraphShape<G>::IntrinsicEdgeMapDimension+1,T> , 
+        NumpyArray<IntrinsicGraphShape<G>::IntrinsicEdgeMapDimension  ,T>
+    >::type Array;
+};
+
+
+
+
+template<class G,class T>
+struct PyNodeMapTraits{
+    typedef NumpyNodeMap<G,T> Map;
+    typedef typename IfBool<
+        IsMultiband<T>::value,
+        NumpyArray<IntrinsicGraphShape<G>::IntrinsicNodeMapDimension+1,T> , 
+        NumpyArray<IntrinsicGraphShape<G>::IntrinsicNodeMapDimension  ,T>
+    >::type Array;
+};
+
+
+namespace cluster_operators{
+
+template<class MERGE_GRAPH>
+class PythonOperator{
+    
+    typedef PythonOperator<MERGE_GRAPH > SelfType;
+public:
+
+
+    typedef float WeightType;
+    typedef MERGE_GRAPH MergeGraph;
+    typedef typename MergeGraph::Graph Graph;
+    typedef typename Graph::Edge GraphEdge;
+    typedef typename Graph::Node GraphNode;
+    typedef typename MergeGraph::Edge Edge;
+    typedef typename MergeGraph::Node Node;
+    typedef typename MergeGraph::EdgeIt EdgeIt;
+    typedef typename MergeGraph::NodeIt NodeIt;
+    typedef typename MergeGraph::IncEdgeIt IncEdgeIt;
+    typedef typename MergeGraph::index_type index_type;
+    typedef MergeGraphItemHelper<MergeGraph,Edge> EdgeHelper;
+    typedef MergeGraphItemHelper<MergeGraph,Node> NodeHelper;
+
+
+    typedef NodeHolder<MERGE_GRAPH> NodeHolderType;
+    typedef EdgeHolder<MERGE_GRAPH> EdgeHolderType;
+
+    PythonOperator(
+        MergeGraph & mergeGraph,
+        boost::python::object object,
+        const bool useMergeNodeCallback,
+        const bool useMergeEdgesCallback,
+        const bool useEraseEdgeCallback
+    )
+    :   mergeGraph_(mergeGraph),
+        object_(object)
+    {
+        if(useMergeNodeCallback){
+            typedef typename MergeGraph::MergeNodeCallBackType Callback;
+            Callback cb(Callback:: template from_method<SelfType,&SelfType::mergeNodes>(this));
+            mergeGraph_.registerMergeNodeCallBack(cb);
+
+        }
+        if(useMergeEdgesCallback){
+            typedef typename MergeGraph::MergeEdgeCallBackType Callback;
+            Callback cb(Callback:: template from_method<SelfType,&SelfType::mergeEdges>(this));
+            mergeGraph_.registerMergeEdgeCallBack(cb);
+        }
+        if(useEraseEdgeCallback){
+            typedef typename MergeGraph::EraseEdgeCallBackType Callback;
+            Callback cb(Callback:: template from_method<SelfType,&SelfType::eraseEdge>(this));
+            mergeGraph_.registerEraseEdgeCallBack(cb);
+        }
+
+    }
+    bool done(){
+        bool retVal;
+        try{
+            retVal =  boost::python::extract<bool>(object_.attr("done")());
+        }
+        catch(std::exception & e){
+            std::cout<<"reason: "<<e.what()<<"\n";
+            throw std::runtime_error("error while calling cluster_operators PythonOperator::done");
+        }
+        return retVal;
+    }
+    void mergeEdges(const Edge & a,const Edge & b){
+        try{
+            const EdgeHolderType aa(mergeGraph_,a);
+            const EdgeHolderType bb(mergeGraph_,b);
+            object_.attr("mergeEdges")(aa,bb);
+        }
+        catch(std::exception & e){
+            std::cout<<"reason: "<<e.what()<<"\n";
+            throw std::runtime_error("error while calling cluster_operators PythonOperator::mergeEdges");
+        }
+    }
+    void mergeNodes(const Node & a,const Node & b){\
+        try{
+            const NodeHolderType aa(mergeGraph_,a);
+            const NodeHolderType bb(mergeGraph_,b);
+            object_.attr("mergeNodes")(aa,bb);
+        }
+        catch(std::exception & e){
+            std::cout<<"reason: "<<e.what()<<"\n";
+            throw std::runtime_error("error while calling cluster_operators PythonOperator::mergeNodes");
+        }
+    }
+    void eraseEdge(const Edge & e){
+        try{
+            const EdgeHolderType ee(mergeGraph_,e);
+            object_.attr("eraseEdge")(ee);
+        }
+        catch(std::exception & e){
+            std::cout<<"reason: "<<e.what()<<"\n";
+            throw std::runtime_error("error while calling cluster_operators PythonOperator::eraseEdge");
+        }
+    }
+    Edge contractionEdge(){
+        EdgeHolderType eh;
+        try{
+            eh = boost::python::extract<EdgeHolderType>(object_.attr("contractionEdge")());
+        }
+        catch(std::exception & e){
+            std::cout<<"reason: "<<e.what()<<"\n";
+            throw std::runtime_error("error while calling cluster_operators PythonOperator::contractionEdge");
+        }
+        return eh;
+    }
+    WeightType contractionWeight()const{
+        WeightType w;
+        try{
+            w = boost::python::extract<WeightType>(object_.attr("contractionWeight")());
+        }
+        catch(std::exception & e){
+            std::cout<<"reason: "<<e.what()<<"\n";
+            throw std::runtime_error("error while calling cluster_operators PythonOperator::contractionWeight");
+        }
+        return w;
+    }
+
+    MergeGraph & mergeGraph(){
+        return mergeGraph_;
+    }
+private:
+    MergeGraph & mergeGraph_;
+    boost::python::object object_;
+};
+
+} // end namespace cluster_operators
+
+
+} // namespace vigra
+
+#endif // VIGRA_PYTHON_GRAPH_HXX
diff --git a/include/vigra/python_utility.hxx b/include/vigra/python_utility.hxx
index 8222901..3ca8eef 100644
--- a/include/vigra/python_utility.hxx
+++ b/include/vigra/python_utility.hxx
@@ -84,7 +84,7 @@ class python_ptr
     typedef PyObject & reference;
 
     enum refcount_policy { increment_count, borrowed_reference = increment_count,
-                           keep_count, new_reference = keep_count };
+                           keep_count, new_reference = keep_count, new_nonzero_reference };
 
     explicit python_ptr(pointer p = 0, refcount_policy rp = increment_count)
     : ptr_( p )
@@ -93,6 +93,10 @@ class python_ptr
         {
             Py_XINCREF(ptr_);
         }
+        else if(rp == new_nonzero_reference)
+        {
+            pythonToCppException(p);
+        }
     }
 
     python_ptr(python_ptr const & p)
@@ -126,6 +130,10 @@ class python_ptr
         {
             Py_XINCREF(p);
         }
+        else if(rp == new_nonzero_reference)
+        {
+            pythonToCppException(p);
+        }
         Py_XDECREF(ptr_);
         ptr_ = p;
     }
diff --git a/include/vigra/quadprog.hxx b/include/vigra/quadprog.hxx
index 59ad27e..20663b0 100644
--- a/include/vigra/quadprog.hxx
+++ b/include/vigra/quadprog.hxx
@@ -131,7 +131,7 @@ void quadprogDeleteConstraint(MultiArrayView<2, T, C1> & R, MultiArrayView<2, T,
      </ul>
      
      The function writes the optimal solution into the vector \a x and returns the cost of this solution. 
-     If the problem is infeasible, std::numeric_limits::infinity() is returned. In this case
+     If the problem is infeasible, <tt>std::numeric_limits::infinity()</tt> is returned. In this case
      the value of vector \a x is undefined.
      
      <b>Usage:</b>
@@ -164,7 +164,43 @@ void quadprogDeleteConstraint(MultiArrayView<2, T, C1> & R, MultiArrayView<2, T,
                    
       double f = quadraticProgramming(G, g, CE, ce, CI, ci, x);
      \endcode
+     
+     This algorithm can also be used to solve non-negative least squares problems
+     (see \ref nonnegativeLeastSquares() for an alternative algorithm). Consider the 
+     problem to minimize <tt> f = (A*x - b)' * (A*x - b) </tt> subject to <tt> x >= 0</tt>.
+     Expanding the product in the objective gives <tt>f = x'*A'*A*x - 2*b'*A*x + b'*b</tt>.
+     This is equivalent to the problem of minimizing <tt>fn = 0.5 * x'*G*x + g'*x</tt> with
+     <tt>G = A'*A</tt> and <tt>g = -A'*b</tt> (the constant term <tt>b'*b</tt> has no
+     effect on the optimal solution and can be dropped). The following code computes the 
+     solution <tt>x' = [18.4493, 0, 4.50725]</tt>:
+     \code
+        double A_data[] = {
+             1, -3,  2,
+            -3, 10, -5,
+             2, -5,  6
+        };
+
+        double b_data[] = {
+             27, 
+            -78, 
+             64
+        };
+
+        Matrix<double> A(3, 3, A_data),
+                       b(3, 1, b_data),
+                       G =   transpose(A)*A,
+                       g = -(transpose(A)*b),
+                       CE,    // empty since there are no equality constraints
+                       ce,    // likewise
+                       CI = identityMatrix<double>(3), // constrain all elements of x
+                       ci(3, 1, 0.0),                  // ... to be non-negative
+                       x(3, 1);
+
+        quadraticProgramming(G, g, CE, ce, CI, ci, x);
+     \endcode
    */
+doxygen_overloaded_function(template <...> unsigned int quadraticProgramming)
+
 template <class T, class C1, class C2, class C3, class C4, class C5, class C6, class C7>
 T 
 quadraticProgramming(MultiArrayView<2, T, C1> const & G, MultiArrayView<2, T, C2> const & g,  
diff --git a/include/vigra/random.hxx b/include/vigra/random.hxx
index ff1ad73..eed8bca 100644
--- a/include/vigra/random.hxx
+++ b/include/vigra/random.hxx
@@ -49,12 +49,12 @@
   #include <vigra/windows.h>  // for GetCurrentProcessId() and GetCurrentThreadId()
 #endif
 
-#if __linux__
+#ifdef __linux__
   #include <unistd.h>       // for getpid()
   #include <sys/syscall.h>  // for SYS_gettid
 #endif
 
-#if __APPLE__
+#ifdef __APPLE__
   #include <unistd.h>               // for getpid()
   #include <sys/syscall.h>          // SYS_thread_selfid
   #include <AvailabilityMacros.h>   // to check if we are on MacOS 10.6 or later
@@ -86,7 +86,7 @@ template <class Iterator, RandomEngineTag EngineTag>
 void seed(Iterator init, UInt32 key_length, RandomState<EngineTag> & engine)
 {
     const UInt32 N = RandomState<EngineTag>::N;
-    int k = (int)std::max(N, key_length);
+    int k = static_cast<int>(std::max(N, key_length));
     UInt32 i = 1, j = 0;
     Iterator data = init;
     for (; k; --k) 
@@ -128,32 +128,32 @@ void seed(RandomSeedTag, RandomState<EngineTag> & engine)
     static UInt32 globalCount = 0;
     ArrayVector<UInt32> seedData;
     
-    seedData.push_back((UInt32)time(0));
-    seedData.push_back((UInt32)clock());
+    seedData.push_back(static_cast<UInt32>(time(0)));
+    seedData.push_back(static_cast<UInt32>(clock()));
     seedData.push_back(++globalCount);
     
     std::size_t ptr((char*)&engine - (char*)0);
-    seedData.push_back((UInt32)(ptr & 0xffffffff));
+    seedData.push_back(static_cast<UInt32>((ptr & 0xffffffff)));
     static const UInt32 shift = sizeof(ptr) > 4 ? 32 : 16;
-    seedData.push_back((UInt32)(ptr >> shift));
+    seedData.push_back(static_cast<UInt32>((ptr >> shift)));
     
 #ifdef _MSC_VER
-    seedData.push_back((UInt32)GetCurrentProcessId());
-    seedData.push_back((UInt32)GetCurrentThreadId());
+    seedData.push_back(static_cast<UInt32>(GetCurrentProcessId()));
+    seedData.push_back(static_cast<UInt32>(GetCurrentThreadId()));
 #endif
 
 #ifdef __linux__
-    seedData.push_back((UInt32)getpid());
+    seedData.push_back(static_cast<UInt32>(getpid()));
 # ifdef SYS_gettid
-    seedData.push_back((UInt32)syscall(SYS_gettid));
+    seedData.push_back(static_cast<UInt32>(syscall(SYS_gettid)));
 # endif
 #endif
 
 #ifdef __APPLE__
-    seedData.push_back((UInt32)getpid());
+    seedData.push_back(static_cast<UInt32>(getpid()));
   #if defined(SYS_thread_selfid) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
     // SYS_thread_selfid was introduced in MacOS 10.6
-    seedData.push_back((UInt32)syscall(SYS_thread_selfid));
+    seedData.push_back(static_cast<UInt32>(syscall(SYS_thread_selfid)));
   #endif
 #endif
 
@@ -525,7 +525,7 @@ class RandomNumberGenerator
         */
     double uniform() const
     {
-        return (double)this->get() / 4294967295.0;
+        return static_cast<double>(this->get()) / 4294967295.0;
     }
 
         /** Return a uniformly distributed double-precision random number in [lower, upper].
diff --git a/include/vigra/random_access_set.hxx b/include/vigra/random_access_set.hxx
new file mode 100644
index 0000000..11ff5c4
--- /dev/null
+++ b/include/vigra/random_access_set.hxx
@@ -0,0 +1,635 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2014 by Thorsten Beier and Ullrich Koethe              */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+
+//! @cond Doxygen_Suppress
+#pragma once
+#ifndef VIGRA_RANDOM_ACCESS_SET_HXX
+#define VIGRA_RANDOM_ACCESS_SET_HXX
+
+#include <vector>
+#include <algorithm>
+#include <utility>
+
+namespace vigra {
+   
+/// set with O(n) insert and O(1) access
+///
+/// \tparam Key key and value type of the set
+/// \tparam Alloc allocator of the set
+/// RandomAccessSet has the same interface as std::set.
+/// In addition, there is operator[].
+/// \warning Values in set must not be changend through the mutable iterator
+/// because doing so would potentially change the order of the values
+/// \\ingroup datastructures
+template<class Key,class Compare=std::less<Key>,class Alloc=std::allocator<Key> >
+class RandomAccessSet {
+private:
+   /// type of the underlying vector
+   typedef std::vector<Key,Alloc> VectorType;
+
+public:
+   // typedefs
+   /// key type of the set
+   typedef Key key_type;
+   /// value type of the set
+   typedef Key ValueType;
+   /// value type of the set
+   typedef Key value_type;
+   /// comperator
+   typedef Compare key_compare;
+   /// value comperator
+   typedef Compare value_compare;
+   /// acclocator
+   typedef Alloc  allocator_type;
+   /// const reference type
+   typedef typename Alloc::const_reference const_reference;
+   /// iterator type
+   typedef typename VectorType::iterator iterator;
+   /// const iterator type
+   typedef typename VectorType::const_iterator const_iterator;
+   /// size type
+   typedef typename VectorType::size_type size_type;
+   /// difference type
+   typedef typename VectorType::difference_type difference_type;
+   /// const pointer type
+   typedef typename VectorType::const_pointer const_pointer;
+   /// const reverse iterator
+   typedef typename VectorType::const_reverse_iterator  const_reverse_iterator;
+
+   // memeber functions:
+   // constructor
+   RandomAccessSet(const size_t, const Compare& compare=Compare(), const Alloc& alloc=Alloc());
+   RandomAccessSet(const Compare& compare=Compare(), const Alloc& alloc=Alloc());
+   template <class InputIterator>
+      RandomAccessSet(InputIterator, InputIterator, const Compare& compare =Compare(), const Alloc & alloc=Alloc());
+   RandomAccessSet(const RandomAccessSet&);
+
+   // operator=
+   RandomAccessSet& operator=(const RandomAccessSet &);
+   // operator[]
+   const value_type& operator[](const size_type) const;
+   // iterators
+   const_iterator begin() const;
+   const_iterator end() const;
+   const_iterator rbegin() const;
+   const_iterator rend() const;
+
+   iterator begin();
+   iterator end();
+   iterator rbegin();
+   iterator rend();
+   bool empty() const;
+   size_type size() const;
+   size_type max_size() const;
+   std::pair< const_iterator,bool> insert(const value_type&);
+   template <class InputIterator>
+      void insert(InputIterator, InputIterator);
+   const_iterator insert(const_iterator , const value_type&);
+   void erase(iterator position);
+   size_type erase(const key_type& );
+   void erase( const_iterator, const_iterator);
+   void swap(RandomAccessSet&);
+   void clear();
+   key_compare key_comp() const;
+   value_compare value_comp() const;
+   const_iterator find(const key_type&) const;
+   iterator find(const key_type&);
+   size_type count(const key_type&) const;
+   const_iterator lower_bound(const key_type&) const;
+   const_iterator upper_bound(const key_type&) const;
+   std::pair<const_iterator,const_iterator> equal_range(const key_type&) const;
+   iterator lower_bound(const key_type&) ;
+   iterator upper_bound(const key_type&) ;
+   std::pair<iterator,iterator> equal_range(const key_type&) ;
+   allocator_type get_allocator() const;
+
+   // std vector functions
+   void reserve(const size_t size){
+       vector_.reserve(size);
+   }
+   size_t capacity()const{
+       return vector_.capacity();
+   }
+   
+   template<class SET>
+   void assignFromSet(const SET & set){
+      vector_.assign(set.begin(),set.end());
+   }
+
+private:
+   std::vector<Key> vector_;
+   Compare compare_;
+};
+
+/// constructor
+/// \param reserveSize reserve /allocate space
+/// \param compare comperator
+/// \param alloc allocator
+template<class Key, class Compare, class Alloc>
+inline
+RandomAccessSet<Key,Compare,Alloc>::RandomAccessSet
+(
+   const size_t reserveSize,
+   const Compare& compare,
+   const Alloc& alloc
+)
+:  vector_(alloc),
+   compare_(compare) {
+   vector_.reserve(reserveSize);
+}
+
+/// const access values
+/// \param index index of the value in the set
+/// \return value / key at the position index
+template<class Key, class Compare, class Alloc>
+inline const typename RandomAccessSet<Key,Compare,Alloc>::value_type&
+RandomAccessSet<Key,Compare,Alloc>::operator[]
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::size_type  index
+) const
+{
+   return vector_[index];
+}
+
+/// constructor
+/// \param compare comperator
+/// \allloc allocator
+template<class Key, class Compare, class Alloc>
+inline
+RandomAccessSet<Key,Compare,Alloc>::RandomAccessSet
+(
+   const Compare& compare,
+   const Alloc& alloc
+)
+:  vector_(alloc),
+   compare_(compare)
+{}
+
+/// constructor
+/// \tparam InputIterator (key/value) input iterator
+/// \param beginInput
+/// \param endInput
+template<class Key, class Compare, class Alloc>
+template <class InputIterator>
+inline
+RandomAccessSet<Key,Compare,Alloc>::RandomAccessSet
+(
+   InputIterator beginInput,
+   InputIterator endInput,
+   const Compare& compare,
+   const Alloc& alloc
+)
+:  vector_(alloc),
+   compare_(compare)
+{
+   while(beginInput!=endInput) {
+      this->insert(*beginInput);
+      ++beginInput;
+   }
+}
+
+/// copy constructor
+/// \param src other random access set
+template<class Key, class Compare, class Alloc>
+inline
+RandomAccessSet<Key,Compare,Alloc>::RandomAccessSet
+(
+   const RandomAccessSet<Key,Compare,Alloc>& src
+)
+:  vector_(src.vector_),
+   compare_(src.compare_) {
+}
+
+/// assignment operator
+/// \param src other random access set
+template<class Key, class Compare, class Alloc>
+inline RandomAccessSet<Key,Compare,Alloc>&
+RandomAccessSet<Key,Compare,Alloc>::operator=
+(
+   const RandomAccessSet<Key,Compare,Alloc> & src
+)
+{
+    if(this!=&src) {
+      vector_=src.vector_;
+      compare_=src.compare_;
+   }
+   return *this;
+}
+
+/// const begin iterator
+/// \returns begin iterator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::const_iterator
+RandomAccessSet<Key,Compare,Alloc>::begin() const
+{
+   return vector_.begin();
+}
+
+/// const end iterator
+/// \returns end iterator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::const_iterator
+RandomAccessSet<Key,Compare,Alloc>::end() const
+{
+    return vector_.end();
+}
+/// reverse const begin iterator
+/// \returns reverse begin iterator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::const_iterator
+RandomAccessSet<Key,Compare,Alloc>::rbegin() const
+{
+   return vector_.rbegin();
+}
+
+/// reverse const end iterator
+/// \param reverse end iterator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::const_iterator
+RandomAccessSet<Key,Compare,Alloc>::rend() const
+{
+    return vector_.rend();
+}
+
+/// begin iterator
+/// \param begin iterator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::iterator
+RandomAccessSet<Key,Compare,Alloc>::begin()
+{
+   return vector_.begin();
+}
+
+/// end iterator
+/// \param end iterator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::iterator
+RandomAccessSet<Key,Compare,Alloc>::end()
+{
+    return vector_.end();
+}
+
+/// reverse  begin iterator
+/// \param reverse begin iterator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::iterator
+RandomAccessSet<Key,Compare,Alloc>::rbegin()
+{
+   return vector_.rbegin();
+}
+
+/// reverse end iterator
+/// \param reverse end iterator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::iterator
+RandomAccessSet<Key,Compare,Alloc>::rend()
+{
+    return vector_.rend();
+}
+
+/// query if the set is empty
+/// \return true if empty
+template<class Key, class Compare, class Alloc>
+inline bool
+RandomAccessSet<Key,Compare,Alloc>::empty() const
+{
+   return vector_.empty();
+}
+
+/// number of elements of the set
+/// \returns number of elements in the set
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::size_type
+RandomAccessSet<Key,Compare,Alloc>::size() const
+{
+   return vector_.size();
+}
+
+/// maximum size of the underlying container
+/// \return the maximum size
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::size_type
+RandomAccessSet<Key,Compare,Alloc>::max_size() const
+{
+   return vector_.max_size();
+}
+
+// modifiers
+/// insert an element into the set
+///
+/// \param value element to insert
+/// \return pair in which the first entry is an iterator pointing to inserted
+/// value and the second entry is true iff the value had not already been in the
+/// set
+template<class Key, class Compare, class Alloc>
+inline std::pair<typename RandomAccessSet<Key,Compare,Alloc>::const_iterator,bool>
+RandomAccessSet<Key,Compare,Alloc>::insert
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::value_type& value
+) {
+   bool found(true);
+   iterator i(lower_bound(static_cast<Key>(value)));
+   if(i == end() || compare_(static_cast<Key>(value), *i)) {
+      i = vector_.insert(i, static_cast<Key>(value));
+      found = false;
+   }
+   return std::make_pair(i, !found);
+}
+
+/// insert a sequence of elements
+///
+/// \param first iterator to the first element
+/// \param last iterator to the last element
+template<class Key, class Compare, class Alloc>
+template <class InputIterator>
+inline void
+RandomAccessSet<Key,Compare,Alloc>::insert
+(
+   InputIterator first,
+   InputIterator last
+)
+{
+   while(first!=last) {
+      this->insert(*first);
+      ++first;
+   }
+}
+
+/// insert a sequence of elements with a hint for the position
+///
+/// \param position iterator to the position
+/// \param value element to insert
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::const_iterator
+RandomAccessSet<Key,Compare,Alloc>::insert
+(
+   typename RandomAccessSet<Key,Compare,Alloc>::const_iterator position,
+   const typename RandomAccessSet<Key,Compare,Alloc>::value_type& value
+)
+{
+   if((position == begin() || this->operator()(*(position-1),value))
+   && (position == end() || this->operator()(value, *position))) {
+       return vector_.insert(position, value);
+   }
+   return insert(value).first;
+}
+
+/// erase an element
+/// \param position iterator to the position
+template<class Key, class Compare, class Alloc>
+inline void
+RandomAccessSet<Key,Compare,Alloc>::erase
+(
+   typename RandomAccessSet<Key,Compare,Alloc>::iterator position
+)
+{
+   vector_.erase(position);
+}
+
+/// erease and element
+/// \param x element
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::size_type
+RandomAccessSet<Key,Compare,Alloc>::erase
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type& x
+)
+{
+   iterator i =find(x);
+   if(i!=vector_.end())
+   {
+      erase(i);
+      return 1;
+   }
+   return 0;
+}
+
+/// erase a sequence of elements
+/// \param first iterator to the beginning of the sequence to erase
+/// \param last iterator to the end of the sequence to erase
+template<class Key, class Compare, class Alloc>
+inline void
+RandomAccessSet<Key,Compare,Alloc>::erase
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::const_iterator first,
+   const typename RandomAccessSet<Key,Compare,Alloc>::const_iterator last
+)
+{
+   vector_.erase(first,last);
+}
+
+/// swap random access sets
+/// \param rhs set to swap with
+template<class Key, class Compare, class Alloc>
+inline void
+RandomAccessSet<Key,Compare,Alloc>::swap
+(
+   RandomAccessSet<Key,Compare,Alloc>& rhs
+)
+{
+   vector_.swap(rhs.vector_);
+   std::swap(compare_, rhs.compare_);
+}
+
+/// clear the set
+///
+/// erases all elements
+template<class Key, class Compare, class Alloc>
+inline void
+RandomAccessSet<Key,Compare,Alloc>::clear()
+{
+   vector_.clear();
+}
+
+/// key comparator
+/// \return key comparator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::key_compare
+RandomAccessSet<Key,Compare,Alloc>::key_comp() const
+{
+   return compare_;
+}
+
+/// value comparator
+/// \return value comparator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::value_compare
+RandomAccessSet<Key,Compare,Alloc>::value_comp() const
+{
+   return compare_;
+}
+
+/// find an element
+/// \param value element
+/// \return const_iterator to the position where element was found or end
+/// iterator if the element was not found
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::const_iterator
+RandomAccessSet<Key,Compare,Alloc>::find
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type& value
+) const
+{
+   const_iterator i(lower_bound(value));
+   if (i != end() && compare_(value, *i))
+   {
+       i = end();
+   }
+   return i;
+}
+
+/// find an element
+/// \param value element
+/// \return iterator to the position where the element was found or end
+/// iterator if the element was not found
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::iterator
+RandomAccessSet<Key,Compare,Alloc>::find
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type& value
+)
+{
+   iterator i(lower_bound(value));
+   if (i != end() && compare_(value, *i))
+   {
+       i = end();
+   }
+   return i;
+}
+
+/// count elements
+/// \param element
+/// \return zero or one
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::size_type
+RandomAccessSet<Key,Compare,Alloc>::count
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type&  value
+) const
+{
+   return find(value) != end() ? 1 : 0;
+}
+
+/// lower bound
+/// \param value
+/// \return iterator to lower bound
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::const_iterator
+RandomAccessSet<Key,Compare,Alloc>::lower_bound
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type& value
+) const
+{
+   return std::lower_bound(vector_.begin(), vector_.end(), value, compare_);
+}
+
+/// lower bound
+/// \param value
+/// \return iterator to lower bound
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::iterator
+RandomAccessSet<Key,Compare,Alloc>::lower_bound
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type& value
+)
+{
+   return std::lower_bound(vector_.begin(), vector_.end(), value, compare_);
+}
+
+/// upper bound
+/// \param value
+/// \return iterator to upper bound
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::const_iterator
+RandomAccessSet<Key,Compare,Alloc>::upper_bound
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type& value
+) const
+{
+   return std::upper_bound(vector_.begin(), vector_.end(), value, compare_);
+}
+
+/// upper bound
+/// \param value
+/// \return iterator to upper bound
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::iterator
+RandomAccessSet<Key,Compare,Alloc>::upper_bound
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type& value
+)
+{
+   return std::upper_bound(vector_.begin(), vector_.end(), value, compare_);
+}
+
+/// equal range
+/// \param value
+/// \return iterator pair to lower equal range
+template<class Key, class Compare, class Alloc>
+inline std::pair<typename RandomAccessSet<Key,Compare,Alloc>::const_iterator,typename RandomAccessSet<Key,Compare,Alloc>::const_iterator>
+RandomAccessSet<Key,Compare,Alloc>::equal_range
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type& value
+) const
+{
+   return std::equal_range(vector_.begin(), vector_.end(), value, compare_);
+}
+
+/// equal range
+/// \param value
+/// \return iterator pair to lower equal range
+template<class Key, class Compare, class Alloc>
+inline std::pair<typename RandomAccessSet<Key,Compare,Alloc>::iterator,typename RandomAccessSet<Key,Compare,Alloc>::iterator>
+RandomAccessSet<Key,Compare,Alloc>::equal_range
+(
+   const typename RandomAccessSet<Key,Compare,Alloc>::key_type& value
+)
+{
+   return std::equal_range(vector_.begin(), vector_.end(), value, compare_);
+}
+/// allocators
+/// \return allocator
+template<class Key, class Compare, class Alloc>
+inline typename RandomAccessSet<Key,Compare,Alloc>::allocator_type
+RandomAccessSet<Key,Compare,Alloc>::get_allocator() const
+{
+   return vector_.get_allocator();
+}
+
+} // namespace vigra
+
+#endif // VIGRA_RANDOM_ACCESS_SET_HXX
+//! @endcond
\ No newline at end of file
diff --git a/include/vigra/random_forest.hxx b/include/vigra/random_forest.hxx
index 940f1bc..885044f 100644
--- a/include/vigra/random_forest.hxx
+++ b/include/vigra/random_forest.hxx
@@ -749,7 +749,7 @@ void RandomForest<LabelType, PreprocessorTag>::onlineLearn(MultiArrayView<2,U,C1
     //visitor.visit_at_beginning(*this, preprocessor);
 
     // THE MAIN EFFING RF LOOP - YEAY DUDE!
-    for(int ii = 0; ii < (int)trees_.size(); ++ii)
+    for(int ii = 0; ii < static_cast<int>(trees_.size()); ++ii)
     {
         online_visitor_.tree_id=ii;
         poisson_sampler.sample();
@@ -1002,7 +1002,7 @@ void RandomForest<LabelType, PreprocessorTag>::
     visitor.visit_at_beginning(*this, preprocessor);
     // THE MAIN EFFING RF LOOP - YEAY DUDE!
     
-    for(int ii = 0; ii < (int)trees_.size(); ++ii)
+    for(int ii = 0; ii < static_cast<int>(trees_.size()); ++ii)
     {
         //initialize First region/node/stack entry
         sampler
@@ -1098,7 +1098,7 @@ void RandomForest<LabelType,PreprocessorTag>
       "RandomForestn::predictProbabilities():"
         " Too few columns in feature matrix.");
     vigra_precondition( columnCount(prob)
-                        == (MultiArrayIndex)ext_param_.class_count_,
+                        == static_cast<MultiArrayIndex>(ext_param_.class_count_),
       "RandomForestn::predictProbabilities():"
       " Probability matrix must have as many columns as there are classes.");
     prob.init(0.0);
@@ -1137,9 +1137,9 @@ void RandomForest<LabelType,PreprocessorTag>
                     //update votecount.
                     for(int l=0; l<ext_param_.class_count_; ++l)
                     {
-                        prob(predictionSet.indices[set_id][i], l) += (T2)weights[l];
+                        prob(predictionSet.indices[set_id][i], l) += static_cast<T2>(weights[l]);
                         //every weight in totalWeight.
-                        totalWeights[predictionSet.indices[set_id][i]] += (T1)weights[l];
+                        totalWeights[predictionSet.indices[set_id][i]] += static_cast<T1>(weights[l]);
                     }
                 }
             }
@@ -1241,7 +1241,7 @@ void RandomForest<LabelType, PreprocessorTag>
       "RandomForestn::predictProbabilities():"
         " Too few columns in feature matrix.");
     vigra_precondition( columnCount(prob)
-                        == (MultiArrayIndex)ext_param_.class_count_,
+                        == static_cast<MultiArrayIndex>(ext_param_.class_count_),
       "RandomForestn::predictProbabilities():"
       " Probability matrix must have as many columns as there are classes.");
 
@@ -1290,7 +1290,7 @@ void RandomForest<LabelType, PreprocessorTag>
             {
                 double cur_w = weights[l] * (weighted * (*(weights-1))
                                            + (1-weighted));
-                prob(row, l) += (T)cur_w;
+                prob(row, l) += static_cast<T>(cur_w);
                 //every weight in totalWeight.
                 totalWeight += cur_w;
             }
@@ -1331,7 +1331,7 @@ void RandomForest<LabelType, PreprocessorTag>
       "RandomForestn::predictProbabilities():"
         " Too few columns in feature matrix.");
     vigra_precondition( columnCount(prob)
-                        == (MultiArrayIndex)ext_param_.class_count_,
+                        == static_cast<MultiArrayIndex>(ext_param_.class_count_),
       "RandomForestn::predictProbabilities():"
       " Probability matrix must have as many columns as there are classes.");
 
@@ -1365,7 +1365,7 @@ void RandomForest<LabelType, PreprocessorTag>
             {
                 double cur_w = weights[l] * (weighted * (*(weights-1))
                                            + (1-weighted));
-                prob(row, l) += (T)cur_w;
+                prob(row, l) += static_cast<T>(cur_w);
                 //every weight in totalWeight.
                 totalWeight += cur_w;
             }
diff --git a/include/vigra/random_forest/rf_algorithm.hxx b/include/vigra/random_forest/rf_algorithm.hxx
index fba236a..f8022ee 100644
--- a/include/vigra/random_forest/rf_algorithm.hxx
+++ b/include/vigra/random_forest/rf_algorithm.hxx
@@ -32,8 +32,8 @@
 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
+#ifndef VIGRA_RF_ALGORITHM_HXX
 #define VIGRA_RF_ALGORITHM_HXX
-
 #include <vector>
 #include "splices.hxx"
 #include <queue>
@@ -163,7 +163,7 @@ class VariableSelectionResult
         bool ret_ = init(all_features, response, errorcallback); 
         if(!ret_)
             return false;
-        vigra_precondition(std::distance(b, e) == (std::ptrdiff_t)selected.size(),
+        vigra_precondition(std::distance(b, e) == static_cast<std::ptrdiff_t>(selected.size()),
                            "Number of features in ranking != number of features matrix");
         std::copy(b, e, selected.begin());
         return true;
@@ -305,7 +305,7 @@ void forward_selection(FeatureT          const & features,
     {
         //result is being reused just ensure that the number of features is
         //the same.
-        vigra_precondition((int)selected.size() == featureCount,
+        vigra_precondition(static_cast<int>(selected.size()) == featureCount,
                            "forward_selection(): Number of features in Feature "
                            "matrix and number of features in previously used "
                            "result struct mismatch!");
@@ -408,7 +408,7 @@ void backward_elimination(FeatureT              const & features,
     {
         //result is being reused just ensure that the number of features is
         //the same.
-        vigra_precondition((int)selected.size() == featureCount,
+        vigra_precondition(static_cast<int>(selected.size()) == featureCount,
                            "backward_elimination(): Number of features in Feature "
                            "matrix and number of features in previously used "
                            "result struct mismatch!");
@@ -504,7 +504,7 @@ void rank_selection      (FeatureT              const & features,
     {
         //result is being reused just ensure that the number of features is
         //the same.
-        vigra_precondition((int)selected.size() == featureCount,
+        vigra_precondition(static_cast<int>(selected.size()) == featureCount,
                            "forward_selection(): Number of features in Feature "
                            "matrix and number of features in previously used "
                            "result struct mismatch!");
@@ -822,7 +822,7 @@ public:
             }
             //update distances;
             
-            for(int jj = 0 ; jj < (int)addr.size(); ++jj)
+            for(int jj = 0 ; jj < static_cast<int>(addr.size()); ++jj)
             {
                 if(jj == ii_keep)
                     continue;
@@ -1337,3 +1337,4 @@ void get_ranking(Array1 const & in, Vector1 & out)
 }//namespace algorithms
 }//namespace rf
 }//namespace vigra
+#endif //VIGRA_RF_ALGORITHM_HXX
diff --git a/include/vigra/random_forest/rf_common.hxx b/include/vigra/random_forest/rf_common.hxx
index a82b1f5..a6f84c8 100755
--- a/include/vigra/random_forest/rf_common.hxx
+++ b/include/vigra/random_forest/rf_common.hxx
@@ -774,7 +774,7 @@ public:
         PULL(precision_, double);
         PULL(response_size_, int);
         class_weights_ = in["class_weights_"];
-        #undef PUSH
+        #undef PULL
     }
     void make_map(map_type & in) const
     {
@@ -822,6 +822,7 @@ public:
     template<class C_Iter>
     ProblemSpec & classes_(C_Iter begin, C_Iter end)
     {
+        classes.clear();
         int size = end-begin;
         for(int k=0; k<size; ++k, ++begin)
             classes.push_back(detail::RequiresExplicitCast<LabelType>::cast(*begin));
@@ -837,6 +838,7 @@ public:
     template<class W_Iter>
     ProblemSpec & class_weights(W_Iter begin, W_Iter end)
     {
+        class_weights_.clear();
         class_weights_.insert(class_weights_.end(), begin, end);
         is_weighted_ = true;
         return *this;
diff --git a/include/vigra/random_forest/rf_earlystopping.hxx b/include/vigra/random_forest/rf_earlystopping.hxx
index 37dffd7..bedc088 100644
--- a/include/vigra/random_forest/rf_earlystopping.hxx
+++ b/include/vigra/random_forest/rf_earlystopping.hxx
@@ -1,6 +1,7 @@
 #ifndef RF_EARLY_STOPPING_P_HXX
 #define RF_EARLY_STOPPING_P_HXX
 #include <cmath>
+#include <stdexcept>
 #include "rf_common.hxx"
 
 namespace vigra
@@ -303,7 +304,8 @@ public:
     }
 
     template<class WeightIter, class T, class C>
-    bool after_prediction(WeightIter iter,  int k, MultiArrayView<2, T, C> prob, double totalCt)
+    bool after_prediction(WeightIter iter,  int k,
+            MultiArrayView<2, T, C> const &prob, double totalCt)
     {
         if(k == SB::tree_count_ -1)
         {
@@ -414,5 +416,52 @@ public:
         return false;
     }
 };
+
+
+class DepthAndSizeStopping: public StopBase
+{
+public:
+    int max_depth_;
+    int min_size_;
+
+    int max_depth_reached; //for debug maximum reached depth
+
+    DepthAndSizeStopping()
+        : max_depth_(NumericTraits<int>::max()), min_size_(0)
+    {}
+
+    /** Constructor DepthAndSize Criterion
+     * Stop growing the tree if a certain depth or size is reached or make a
+     * leaf if the node is smaller than a certain size. Note this is checked
+     * before the split so it is still possible that smaller leafs are created
+     */
+
+    DepthAndSizeStopping(int depth, int size) :
+        max_depth_(depth <= 0 ? NumericTraits<int>::max() : depth),
+        min_size_(size)
+    {}
+
+    template<class T>
+    void set_external_parameters(ProblemSpec<T> const &,
+            int tree_count = 0, bool /* is_weighted_ */= false)
+    {}
+
+    template<class Region>
+    bool operator()(Region& region)
+    {
+        if (region.depth() > max_depth_)
+           throw std::runtime_error("violation in the stopping criterion");
+
+        return (region.depth() >= max_depth_) || (region.size() < min_size_) ;
+    }
+
+    template<class WeightIter, class T, class C>
+    bool after_prediction(WeightIter, int /* k */,
+            MultiArrayView<2, T, C> const &/* prob */, double /* totalCt */)
+    {
+        return true;
+    }
+};
+
 } //namespace vigra;
 #endif //RF_EARLY_STOPPING_P_HXX
diff --git a/include/vigra/random_forest/rf_preprocessing.hxx b/include/vigra/random_forest/rf_preprocessing.hxx
index a3622b6..a10fcb7 100755
--- a/include/vigra/random_forest/rf_preprocessing.hxx
+++ b/include/vigra/random_forest/rf_preprocessing.hxx
@@ -37,6 +37,7 @@
 #define VIGRA_RF_PREPROCESSING_HXX
 
 #include <limits>
+#include <vigra/mathutil.hxx>
 #include "rf_common.hxx"
 
 namespace vigra
@@ -107,8 +108,8 @@ namespace detail
                 break;
             case RF_PROPORTIONAL:
                 ext_param.actual_msample_ =
-                    (int)std::ceil(  options.training_set_proportion_ *
-                                     ext_param.row_count_);
+                    static_cast<int>(std::ceil(options.training_set_proportion_ *
+                                               ext_param.row_count_));
                     break;
             case RF_FUNCTION:
                 ext_param.actual_msample_ =
@@ -126,8 +127,10 @@ namespace detail
     template<unsigned int N, class T, class C>
     bool contains_nan(MultiArrayView<N, T, C> const & in)
     {
-        for(int ii = 0; ii < in.size(); ++ii)
-            if(in[ii] != in[ii])
+        typedef typename MultiArrayView<N, T, C>::const_iterator Iter;
+        Iter i = in.begin(), end = in.end();
+        for(; i != end; ++i)
+            if(isnan(NumericTraits<T>::toRealPromote(*i)))
                 return true;
         return false; 
     }
@@ -139,8 +142,10 @@ namespace detail
     {
          if(!std::numeric_limits<T>::has_infinity)
              return false;
-         for(int ii = 0; ii < in.size(); ++ii)
-            if(in[ii] == std::numeric_limits<T>::infinity())
+        typedef typename MultiArrayView<N, T, C>::const_iterator Iter;
+        Iter i = in.begin(), end = in.end();
+        for(; i != end; ++i)
+            if(abs(*i) == std::numeric_limits<T>::infinity())
                 return true;
          return false;
     }
@@ -213,7 +218,7 @@ class Processor<ClassificationTag, LabelType, T1, C1, T2, C2>
         if(ext_param.class_weights_.size() == 0)
         {
             ArrayVector<T2> 
-                tmp((std::size_t)ext_param.class_count_, 
+                tmp(static_cast<std::size_t>(ext_param.class_count_),
                     NumericTraits<T2>::one());
             ext_param.class_weights(tmp.begin(), tmp.end());
         }
diff --git a/include/vigra/random_forest/rf_region.hxx b/include/vigra/random_forest/rf_region.hxx
index 5fb4067..55ba7e7 100755
--- a/include/vigra/random_forest/rf_region.hxx
+++ b/include/vigra/random_forest/rf_region.hxx
@@ -115,7 +115,7 @@ class DT_StackEntry
     {
         int num = 0;
 
-        for(int ii = 0; ii < (int)classCounts().size(); ++ii)
+        for(int ii = 0; ii < static_cast<int>(classCounts().size()); ++ii)
         {
             num += classCounts()[ii] > 0;
         }
diff --git a/include/vigra/random_forest/rf_ridge_split.hxx b/include/vigra/random_forest/rf_ridge_split.hxx
index bb65ddd..925d7e9 100644
--- a/include/vigra/random_forest/rf_ridge_split.hxx
+++ b/include/vigra/random_forest/rf_ridge_split.hxx
@@ -167,7 +167,7 @@ class RidgeSplit: public SplitBase<Tag>
     MultiArray<2, T2> labels(lShape(multiClassLabels.shape(0),1));
       //number of classes should be >1, otherwise makeTerminalNode would have been called
       int nNumClasses=0;
-      for(int n=0; n<(int)region.classCounts().size(); n++)
+      for(int n=0; n<static_cast<int>(region.classCounts().size()); n++)
         nNumClasses+=((region.classCounts()[n]>0) ? 1:0);
       
       //convert to binary case
@@ -175,7 +175,7 @@ class RidgeSplit: public SplitBase<Tag>
       {
         int nMaxClass=0;
         int nMaxClassCounts=0;
-        for(int n=0; n<(int)region.classCounts().size(); n++)
+        for(int n=0; n<static_cast<int>(region.classCounts().size()); n++)
         {
           //this should occur in any case:
           //we had more than two non-zero classes in order to get here
diff --git a/include/vigra/random_forest/rf_split.hxx b/include/vigra/random_forest/rf_split.hxx
index 838e335..3a914a5 100644
--- a/include/vigra/random_forest/rf_split.hxx
+++ b/include/vigra/random_forest/rf_split.hxx
@@ -165,10 +165,10 @@ class SplitBase
         the class histogram
     **/
     template<class T, class C, class T2,class C2, class Region, class Random>
-    int makeTerminalNode(MultiArrayView<2, T, C> features,
-                      MultiArrayView<2, T2, C2>  labels,
-                      Region &                   region,
-                      Random                     randint)
+    int makeTerminalNode(MultiArrayView<2, T, C>    /* features */,
+                         MultiArrayView<2, T2, C2>  /* labels */,
+                         Region &                   region,
+                         Random                     /* randint */)
     {
         Node<e_ConstProbNode> ret(t_data, p_data);
         node_ = ret;
@@ -1099,6 +1099,8 @@ class ThresholdSplit: public SplitBase<Tag>
         }
         //std::cerr << current_min_gini << "curr " << region_gini_ << std::endl;
         // did not find any suitable split
+        // FIXME: this is wrong: sometimes we must execute bad splits to make progress,
+        //        especially near the root.
         if(closeAtTolerance(current_min_gini, region_gini_))
             return  this->makeTerminalNode(features, labels, region, randint);
         
diff --git a/include/vigra/random_forest/rf_visitors.hxx b/include/vigra/random_forest/rf_visitors.hxx
index c927013..0ee7535 100755
--- a/include/vigra/random_forest/rf_visitors.hxx
+++ b/include/vigra/random_forest/rf_visitors.hxx
@@ -158,7 +158,7 @@ class VisitorBase
      * \param index     index of current tree
      */
     template<class RF, class PR, class SM, class ST>
-    void visit_after_tree(RF& rf, PR & pr,  SM & sm, ST & st, int index)
+    void visit_after_tree(RF & rf, PR & pr, SM & sm, ST & st, int index)
     {}
     
     /** do something after all trees have been learned
@@ -194,7 +194,7 @@ class VisitorBase
      * use the NodeBase class.
      */
     template<class TR, class IntT, class TopT,class Feat>
-    void visit_external_node(TR & tr, IntT index, TopT node_t,Feat & features)
+    void visit_external_node(TR & tr, IntT index, TopT node_t, Feat & features)
     {}
     
     /** do something when visiting a internal node after it has been learned
@@ -202,7 +202,7 @@ class VisitorBase
      * \sa visit_external_node
      */
     template<class TR, class IntT, class TopT,class Feat>
-    void visit_internal_node(TR & tr, IntT index, TopT node_t,Feat & features)
+    void visit_internal_node(TR & /* tr */, IntT /* index */, TopT /* node_t */, Feat & /* features */)
     {}
 
     /** return a double value.  The value of the first 
@@ -614,7 +614,7 @@ public:
     /** Initialize, set the number of trees
      */
     template<class RF,class PR>
-    void visit_at_beginning(RF & rf,const PR & pr)
+    void visit_at_beginning(RF & rf,const PR & /* pr */)
     {
         tree_id=0;
         trees_online_information.resize(rf.options_.tree_count_);
@@ -633,19 +633,19 @@ public:
     /** simply increase the tree count
     */
     template<class RF, class PR, class SM, class ST>
-    void visit_after_tree(RF& rf, PR & pr,  SM & sm, ST & st, int index)
+    void visit_after_tree(RF & /* rf */, PR & /* pr */,  SM & /* sm */, ST & /* st */, int /* index */)
     {
         tree_id++;
     }
     
     template<class Tree, class Split, class Region, class Feature_t, class Label_t>
     void visit_after_split( Tree          & tree, 
-                Split         & split,
-                            Region       & parent,
+                            Split         & split,
+                            Region        & parent,
                             Region        & leftChild,
                             Region        & rightChild,
                             Feature_t     & features,
-                            Label_t       & labels)
+                            Label_t       & /* labels */)
     {
         int linear_index;
         int addr=tree.topology_.size();
@@ -793,7 +793,7 @@ public:
 
     /** does the basic calculation per tree*/
     template<class RF, class PR, class SM, class ST>
-    void visit_after_tree(    RF& rf, PR & pr,  SM & sm, ST & st, int index)
+    void visit_after_tree(RF & rf, PR & pr,  SM & sm, ST & st, int index)
     {
         //do the first time called.
         if(int(oobCount.size()) != rf.ext_param_.row_count_)
@@ -825,7 +825,7 @@ public:
     void visit_at_end(RF & rf, PR & pr)
     {
         // do some normalisation
-        for(int l=0; l < (int)rf.ext_param_.row_count_; ++l)
+        for(int l=0; l < static_cast<int>(rf.ext_param_.row_count_); ++l)
         {
             if(oobCount[l])
             {
@@ -985,7 +985,7 @@ class OOB_Error : public VisitorBase
         // ullis original metric and breiman style stuff
         int totalOobCount =0;
         int breimanstyle = 0;
-        for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll)
+        for(int ll=0; ll < static_cast<int>(rf.ext_param_.row_count_); ++ll)
         {
             if(oobCount[ll])
             {
@@ -1148,7 +1148,7 @@ class CompleteOOBInfo : public VisitorBase
         }
         int breimanstyle = 0;
         int totalOobCount = 0;
-        for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll)
+        for(int ll=0; ll < static_cast<int>(rf.ext_param_.row_count_); ++ll)
         {
             if(oobCount[ll])
             {
@@ -1169,7 +1169,7 @@ class CompleteOOBInfo : public VisitorBase
                     = oobroc_per_tree.bindOuter(index);
             for(int gg = 0; gg < current_roc.shape(2); ++gg)
             {
-                for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll)
+                for(int ll=0; ll < static_cast<int>(rf.ext_param_.row_count_); ++ll)
                 {
                     if(oobCount[ll])
                     {
@@ -1195,7 +1195,7 @@ class CompleteOOBInfo : public VisitorBase
         oob_per_tree2 = 0; 
         int totalOobCount =0;
         int breimanstyle = 0;
-        for(int ll=0; ll < (int)rf.ext_param_.row_count_; ++ll)
+        for(int ll=0; ll < static_cast<int>(rf.ext_param_.row_count_); ++ll)
         {
             if(oobCount[ll])
             {
@@ -1275,11 +1275,11 @@ class VariableImportanceVisitor : public VisitorBase
     template<class Tree, class Split, class Region, class Feature_t, class Label_t>
     void visit_after_split( Tree          & tree, 
                             Split         & split,
-                            Region        & parent,
-                            Region        & leftChild,
-                            Region        & rightChild,
-                            Feature_t     & features,
-                            Label_t       & labels)
+                            Region        & /* parent */,
+                            Region        & /* leftChild */,
+                            Region        & /* rightChild */,
+                            Feature_t     & /* features */,
+                            Label_t       & /* labels */)
     {
         //resize to right size when called the first time
         
@@ -1308,7 +1308,7 @@ class VariableImportanceVisitor : public VisitorBase
      * \sa FieldProxy
      */
     template<class RF, class PR, class SM, class ST>
-    void after_tree_ip_impl(RF& rf, PR & pr,  SM & sm, ST & st, int index)
+    void after_tree_ip_impl(RF& rf, PR & pr,  SM & sm, ST & /* st */, int index)
     {
         typedef MultiArrayShape<2>::type Shp_t;
         Int32                   column_count = rf.ext_param_.column_count_;
@@ -1388,7 +1388,7 @@ class VariableImportanceVisitor : public VisitorBase
             {               
                 //permute dimension. 
                 int n = oob_indices.size();
-                for(int jj = 1; jj < n; ++jj)
+                for(int jj = n-1; jj >= 1; --jj)
                     std::swap(features(oob_indices[jj], ii), 
                               features(oob_indices[randint(jj+1)], ii));
 
@@ -1438,7 +1438,7 @@ class VariableImportanceVisitor : public VisitorBase
     /** Normalise variable importance after the number of trees is known.
      */
     template<class RF, class PR>
-    void visit_at_end(RF & rf, PR & pr)
+    void visit_at_end(RF & rf, PR & /* pr */)
     {
         variable_importance_ /= rf.trees_.size();
     }
@@ -1535,8 +1535,9 @@ class CorrelationVisitor : public VisitorBase
 #undef VAR_WRITE
 */
     }
+
     template<class RF, class PR>
-    void visit_at_beginning(RF const & rf, PR  & pr)
+    void visit_at_beginning(RF const & rf, PR & pr)
     {
         typedef MultiArrayShape<2>::type Shp;
         int n = rf.ext_param_.column_count_;
diff --git a/include/vigra/random_forest_hdf5_impex.hxx b/include/vigra/random_forest_hdf5_impex.hxx
index ff34fbe..cc119db 100644
--- a/include/vigra/random_forest_hdf5_impex.hxx
+++ b/include/vigra/random_forest_hdf5_impex.hxx
@@ -224,6 +224,33 @@ void rf_export_HDF5(const RandomForest<T, Tag> & rf,
     rf_export_HDF5(rf, h5context, pathname);
 }
 
+/** \brief Save a random forest to an HDF5 file specified by its id
+
+    The random forest is saved as a set of HDF5 datasets, groups, and
+    attributes below a certain HDF5 group (default: root). No additional data
+    should be stored in that group.
+
+    \warning In case the underlying HDF5 library used by Vigra is not
+    exactly the same library used to open the file with the given id, this
+    method will lead to crashes.
+
+    \param rf       Random forest object to be exported
+    \param outf_id  HDF5 file id
+    \param pathname If empty or not supplied, save the random forest to the
+                    root group of the HDF5 file. Otherwise, save to a
+                    new-created group specified by the path name (relative
+                    to the root group).
+*/
+template<class T, class Tag>
+void rf_export_HDF5(const RandomForest<T, Tag> & rf,
+                    hid_t outf_id,
+                    const std::string & pathname = "")
+{
+    HDF5HandleShared fileHandle(outf_id, NULL, "");
+    HDF5File h5context(fileHandle, pathname);
+    rf_export_HDF5(rf, h5context);
+}
+
 /** \brief Read a random forest from an HDF5File object's specified group.
     
     The random forest is read from a certain HDF5 group (default: current group
@@ -261,6 +288,7 @@ bool rf_import_HDF5(RandomForest<T, Tag> & rf,
     // get external parameters
     detail::problemspec_import_HDF5(h5context, rf.ext_param_,
                                     rf_hdf5_ext_param);
+    rf.trees_.clear();
     // get all groups in base path
     // no check for the rf_hdf5_tree prefix...
     std::vector<std::string> names = h5context.ls();
@@ -300,6 +328,33 @@ bool rf_import_HDF5(RandomForest<T, Tag> & rf,
     return rf_import_HDF5(rf, h5context, pathname);
 }
 
+/** \brief Read a random forest from an HDF5 file specified by its id.
+
+    The random forest is read from a certain HDF5 group (default: root group
+    of the HDF5 file) as a set of HDF5 datasets, groups, and attributes.
+    No additional data should be present in that group.
+
+    \warning In case the underlying HDF5 library used by Vigra is not
+    exactly the same library used to open the file with the given id, this
+    method will lead to crashes.
+
+    \param rf        Random forest object to be imported
+    \param inf_id   HDF5 file id
+    \param pathname  If empty or not supplied, read from the random forest
+                     from the current group of the HDF5 file. Otherwise,
+                     use the group specified by the path name, which may
+                     be either relative or absolute.
+*/
+template<class T, class Tag>
+bool rf_import_HDF5(RandomForest<T, Tag> & rf, 
+                    hid_t inf_id,
+                    const std::string & pathname = "")
+{
+    HDF5HandleShared fileHandle(inf_id, NULL, "");
+    HDF5File h5context(fileHandle, pathname, true);
+    return rf_import_HDF5(rf, h5context);
+}
+
 } // namespace vigra
 
 #endif // VIGRA_RANDOM_FOREST_HDF5_IMPEX_HXX
diff --git a/include/vigra/rbf_registration.hxx b/include/vigra/rbf_registration.hxx
new file mode 100644
index 0000000..c794884
--- /dev/null
+++ b/include/vigra/rbf_registration.hxx
@@ -0,0 +1,312 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2007-2014 by Benjamin Seppke                 */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_RBF_REGISTRATION_HXX
+#define VIGRA_RBF_REGISTRATION_HXX
+
+#include <vigra/mathutil.hxx>
+#include <vigra/matrix.hxx>
+#include <vigra/linear_solve.hxx>
+#include <vigra/tinyvector.hxx>
+#include <vigra/splineimageview.hxx>
+#include <vigra/affine_registration.hxx>
+
+namespace vigra {
+
+/** \addtogroup Registration Image Registration
+ */
+//@{
+
+namespace detail {
+
+// Small and hopefully fast helper function to compute the squared-distance
+// between two points (2d)
+template <class SrcPoint, class DestPoint>
+inline double distance2(SrcPoint const & p1, DestPoint const & p2)
+{
+    return (double)(p1[0]-p2[0])*(p1[0]-p2[0]) + (p1[1]-p2[1])*(p1[1]-p2[1]);
+}
+
+} //end of namespace vigra::detail
+
+
+/**
+ * The famous thin plate spline functor [weight(d) = d^2*log(d^2)]
+ * only affects up to max distance...
+ */
+struct ThinPlateSplineFunctor
+{
+    template <class SrcPoint, class DestPoint>
+    inline double operator()(SrcPoint const & p1, DestPoint const & p2) const
+    {
+        double dist2 = detail::distance2(p1, p2);
+
+        if(dist2 == 0 )
+        {
+            return 0;
+        }
+        else
+        {
+            return dist2*log(dist2);
+        }
+    }
+};
+
+/**
+ * A distance power based radial basis functor [weight = dist^N]
+ */
+template<int N>
+struct DistancePowerFunctor
+{
+    template <class SrcPoint, class DestPoint>
+    inline double operator()(SrcPoint const & p1, DestPoint const & p2) const
+    {
+        double dist2 = detail::distance2(p1, p2);
+
+        if(dist2 == 0)
+        {
+            return 0;
+        }
+        else
+        {
+            return pow(dist2, N/2.0);
+        }
+    }
+};
+
+/********************************************************/
+/*                                                      */
+/*          rbfMatrix2DFromCorrespondingPoints          */
+/*                                                      */
+/********************************************************/
+
+/** \brief Create a matrix that maps corresponding points onto each other using a given RBF.
+
+ For use with \ref rbfWarpImage(). For n given (corresponding) points,
+ the matrix will be of size (n+3,2). Note that the representation of this matrix is exactly
+ the same as the "W" matrix of Bookstein. More information can be found in the following article:
+
+ Fred L. Bookstein. Principal Warps: Thin-Plate Splines and the Decomposition of Deformations. IEEE PAMI, Vol 11, No 8. 1989
+ */
+template <class RadialBasisFunctor,
+          class SrcPointIterator, class DestPointIterator>
+linalg::TemporaryMatrix<double>
+rbfMatrix2DFromCorrespondingPoints(SrcPointIterator s, SrcPointIterator s_end, DestPointIterator d, RadialBasisFunctor const & rbf)
+{
+    int point_count = s_end - s;
+
+    Matrix<double> L(point_count+3, point_count+3, 0.0);
+    Matrix<double> Y(point_count+3,               2, 0.0);
+    Matrix<double> W(point_count+3,               2, 0.0);
+
+    //fill P (directly into K) and V (directly into Y)
+    for(int i=0; i<point_count; ++i)
+    {
+        L(i, point_count  ) = L(point_count,   i) = 1;
+        L(i, point_count+1) = L(point_count+1, i) = (d[i])[0];
+        L(i, point_count+2) = L(point_count+2, i) = (d[i])[1];
+
+        Y(i,0)= (s[i])[0];
+        Y(i,1)= (s[i])[1];
+    }
+
+    //fill K (directly into L)
+    for(int j=0; j<point_count; j++)
+    {
+        for(int i=0; i<j; i++)
+        {
+            L(i,j) = L(j,i) = rbf(d[i], d[j]);
+        }
+    }
+
+    linearSolve(L, Y, W);
+    //Results are okay, even if vigra reports failure...
+    //so I commented this out
+    //    if(!linearSolve(L, Y, W))
+    //        vigra_fail("radialBasisMatrix2DFromCorrespondingPoints(): singular solution matrix.");
+
+    return W;
+};
+
+
+/********************************************************/
+/*                                                      */
+/*                     rbfWarpImage                     */
+/*                                                      */
+/********************************************************/
+
+/** \brief Warp an image according to an radial basis function based transformation.
+
+ To get more information about the structure of the matrix, see \ref rbfMatrix2DFromCorrespondingPoints()
+
+ <b>\#include</b> \<vigra/rbf_registration.hxx\><br>
+ Namespace: vigra
+
+ pass 2D array views:
+ \code
+ namespace vigra {
+     template <int ORDER, class T,
+               class T2, class S2,
+               class DestPointIterator,
+               class C,
+               class RadialBasisFunctor>
+     void
+     rbfWarpImage(SplineImageView<ORDER, T> const & src,
+                  MultiArrayView<2, T2, S2> dest,
+                  DestPointIterator d, DestPointIterator d_end,
+                  MultiArrayView<2, double, C> const & W,
+                  RadialBasisFunctor rbf);
+ }
+ \endcode
+
+ \deprecatedAPI{rbfWarpImage}
+
+ pass arguments explicitly:
+ \code
+ namespace vigra {
+     template <int ORDER, class T,
+               class DestIterator, class DestAccessor,
+               class DestPointIterator,
+               class C,
+               class RadialBasisFunctor>
+     void
+     rbfWarpImage(SplineImageView<ORDER, T> const & src,
+                  DestIterator dul, DestIterator dlr, DestAccessor dest,
+                  DestPointIterator d, DestPointIterator d_end,
+                  MultiArrayView<2, double, C> const & W,
+                  RadialBasisFunctor rbf);
+ }
+ \endcode
+
+ use argument objects in conjunction with \ref ArgumentObjectFactories :
+ \code
+ namespace vigra {
+     template <int ORDER, class T,
+               class DestIterator, class DestAccessor,
+               class DestPointIterator,
+               class C,
+               class RadialBasisFunctor>
+     void
+     rbfWarpImage(SplineImageView<ORDER, T> const & src,
+                  triple<DestIterator, DestIterator, DestAccessor> dest,
+                  DestPointIterator d, DestPointIterator d_end,
+                  MultiArrayView<2, double, C> const & W,
+                  RadialBasisFunctor rbf);
+ }
+ }
+ \endcode
+ \deprecatedEnd
+ */
+template <int ORDER, class T,
+          class DestIterator, class DestAccessor,
+          class DestPointIterator,
+          class C,
+          class RadialBasisFunctor>
+void
+rbfWarpImage(SplineImageView<ORDER, T> const & src,
+             DestIterator dul, DestIterator dlr, DestAccessor dest,
+             DestPointIterator d, DestPointIterator d_end,
+             MultiArrayView<2, double, C> const & W,
+             RadialBasisFunctor rbf)
+{
+    int point_count = d_end - d;
+
+    vigra_precondition(rowCount(W) == point_count+3 && columnCount(W) == 2,
+                       "vigra::rbfWarpImage(): matrix doesn't represent a proper transformation of given point size in 2D coordinates.");
+
+    double w = dlr.x - dul.x;
+    double h = dlr.y - dul.y;
+
+    for(double y = 0.0; y < h; ++y, ++dul.y)
+    {
+        typename DestIterator::row_iterator rd = dul.rowIterator();
+        for(double x=0.0; x < w; ++x, ++rd)
+        {
+            //Affine part
+            double    sx = W(point_count,0)+W(point_count+1,0)*x+ W(point_count+2,0)*y,
+                    sy = W(point_count,1)+W(point_count+1,1)*x+ W(point_count+2,1)*y;
+
+            //RBS part
+            for(int i=0; i<point_count; i++)
+            {
+                double weight = rbf(d[i], Diff2D(x,y));
+                sx += W(i,0)*weight;
+                sy += W(i,1)*weight;
+
+            }
+
+            if(src.isInside(sx, sy))
+                dest.set(src(sx, sy), rd);
+        }
+    }
+};
+
+template <int ORDER, class T,
+          class DestIterator, class DestAccessor,
+          class DestPointIterator,
+          class C,
+          class RadialBasisFunctor>
+inline
+void rbfWarpImage(SplineImageView<ORDER, T> const & src,
+                  triple<DestIterator, DestIterator, DestAccessor> dest,
+                  DestPointIterator d, DestPointIterator d_end,
+                  MultiArrayView<2, double, C> const & W,
+                  RadialBasisFunctor rbf)
+{
+    rbfWarpImage(src, dest.first, dest.second, dest.third, d, d_end, W, rbf);
+}
+
+template <int ORDER, class T,
+          class T2, class S2,
+          class DestPointIterator,
+          class C,
+          class RadialBasisFunctor>
+inline
+void rbfWarpImage(SplineImageView<ORDER, T> const & src,
+                  MultiArrayView<2, T2, S2> dest,
+                  DestPointIterator d, DestPointIterator d_end,
+                  MultiArrayView<2, double, C> const & W,
+                  RadialBasisFunctor rbf)
+{
+    rbfWarpImage(src, destImageRange(dest), d, d_end, W, rbf);
+}
+
+
+//@}
+
+} // namespace vigra
+
+
+#endif /* VIGRA_RBF_REGISTRATION_HXX */
diff --git a/include/vigra/recursiveconvolution.hxx b/include/vigra/recursiveconvolution.hxx
index 8705631..e1c3dd4 100644
--- a/include/vigra/recursiveconvolution.hxx
+++ b/include/vigra/recursiveconvolution.hxx
@@ -273,7 +273,7 @@ void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
         {    
             TempType f = TempType(b * old);
             old = as(is) + f;
-            double norm = (1.0 - b) / (1.0 + b - bleft - bright);
+            norm = (1.0 - b) / (1.0 + b - bleft - bright);
             bleft /= b;
             bright *= b;
             ad.set(norm * (line[x] + f), id);
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/include/vigra/region_shrinking.hxx
similarity index 56%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to include/vigra/region_shrinking.hxx
index 37a8c81..ffbdbab 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/include/vigra/region_shrinking.hxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*               Copyright 2012-2013 by Ullrich Koethe                  */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,61 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
-#include <vigra/numpy_array.hxx>
-#include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
-
-namespace python = boost::python;
+#ifndef VIGRA_REGION_SHRINK_HXX
+#define VIGRA_REGION_SHRINK_HXX
 
+#include "multi_array.hxx"
+#include "multi_gridgraph.hxx"
 namespace vigra {
 
-UInt32 pychecksum(python::str const & s)
-{
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+    template<unsigned int DIM, class LABEL_TYPE,class LABEL_TYPE_OUT>
+    void regionShrinking(
+        MultiArrayView<DIM,LABEL_TYPE>     labels,
+        const size_t shrinkNpixels,
+        MultiArrayView<DIM,LABEL_TYPE_OUT> shrinkedLabels
+    ){
+        shrinkedLabels = labels;
+
+        typedef GridGraph<DIM, undirected_tag> Graph;
+        typedef typename Graph::Node Node;
+        //typedef typename Graph::Edge Edge;
+        typedef typename Graph::NodeIt graph_scanner;
+        typedef typename Graph::OutArcIt neighbor_iterator;
+
+        const Graph g(labels.shape());
+
+        // INITAL LOOP
+        for (graph_scanner n(g); n != lemon::INVALID; ++n){
+            const Node node(*n);
+            for (neighbor_iterator arc(g, node); arc != lemon::INVALID; ++arc){
+                const Node otherNode = g.target(arc);
+
+                if(labels[node]!=labels[otherNode]){
+                    shrinkedLabels[node]=0;
+                    shrinkedLabels[otherNode]=0;
+                }
+            }
+        }
+
+        MultiArray<DIM,bool> visited(labels.shape());
+        for(size_t r=0;r<shrinkNpixels-1;++r){
+            std::fill(visited.begin(),visited.end(),false);
+            for (graph_scanner n(g); n != lemon::INVALID; ++n){
+                const Node node(*n);
+                if(!visited[n] && shrinkedLabels[node]==0){
+                    for (neighbor_iterator arc(g, node); arc != lemon::INVALID; ++arc){
+                        const Node otherNode = g.target(arc);
+                        shrinkedLabels[otherNode]=0;
+                        visited[otherNode]=true;
+                    }
+                }
+            }
+        }
+    }
 
-} // namespace vigra
 
-using namespace boost::python;
-using namespace vigra;
+} // end namespace vigra
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
-{
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
-}
+#endif // VIGRA_REGION_SHRINK_HXX
diff --git a/include/vigra/regression.hxx b/include/vigra/regression.hxx
index c10c80e..88c52a3 100644
--- a/include/vigra/regression.hxx
+++ b/include/vigra/regression.hxx
@@ -364,7 +364,7 @@ class LeastAngleRegressionOptions
         */
     LeastAngleRegressionOptions & maxSolutionCount(unsigned int n)
     {
-        max_solution_count = (int)n;
+        max_solution_count = static_cast<int>(n);
         return *this;
     }
 
@@ -514,8 +514,8 @@ leastAngleRegressionMainLoop(LarsData<T, C1, C2> & d,
     MultiArrayIndex currentSolutionCount = 0;
     while(currentSolutionCount < maxSolutionCount)
     {
-        //ColumnSet activeSet = d.columnPermutation.subarray(0, (unsigned int)d.activeSetSize);
-        ColumnSet inactiveSet = d.columnPermutation.subarray((unsigned int)d.activeSetSize, (unsigned int)cols);
+        //ColumnSet activeSet = d.columnPermutation.subarray(0, static_cast<unsigned int>(d.activeSetSize));
+        ColumnSet inactiveSet = d.columnPermutation.subarray(static_cast<unsigned int>(d.activeSetSize), static_cast<unsigned int>(cols));
 
         // find next dimension to be activated
         Matrix<T> cLARS = transpose(d.A) * (d.b - d.lars_prediction),      // correlation with LARS residual
@@ -604,7 +604,7 @@ leastAngleRegressionMainLoop(LarsData<T, C1, C2> & d,
                 ArrayVector<ArrayVector<MultiArrayIndex> > nnactiveSets;
                 LarsData<T, C1, C2> nnd(d, d.activeSetSize);
 
-                leastAngleRegressionMainLoop(nnd, nnactiveSets, &nnresults, (Array3*)0,
+                leastAngleRegressionMainLoop(nnd, nnactiveSets, &nnresults, static_cast<Array3*>(0),
                                              LeastAngleRegressionOptions().leastSquaresSolutions(false).nnlasso());
                 //Matrix<T> nnlsq_solution(d.activeSetSize, 1);
                 typename Array2::value_type nnlsq_solution(Shape(d.activeSetSize, 1));
@@ -684,7 +684,7 @@ leastAngleRegressionMainLoop(LarsData<T, C1, C2> & d,
             d.next_lsq_prediction += next_lsq_solution_view(k,0)*columnVector(d.A, d.columnPermutation[k]);
     }
 
-    return (unsigned int)currentSolutionCount;
+    return static_cast<unsigned int>(currentSolutionCount);
 }
 
 template <class T, class C1, class C2, class Array1, class Array2>
@@ -877,9 +877,9 @@ leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2
                      LeastAngleRegressionOptions const & options = LeastAngleRegressionOptions())
 {
     if(options.least_squares_solutions)
-        return detail::leastAngleRegressionImpl(A, b, activeSets, (Array2*)0, &solutions, options);
+        return detail::leastAngleRegressionImpl(A, b, activeSets, static_cast<Array2*>(0), &solutions, options);
     else
-        return detail::leastAngleRegressionImpl(A, b, activeSets, &solutions, (Array2*)0, options);
+        return detail::leastAngleRegressionImpl(A, b, activeSets, &solutions, static_cast<Array2*>(0), options);
 }
 
 template <class T, class C1, class C2, class Array1, class Array2>
@@ -891,24 +891,41 @@ leastAngleRegression(MultiArrayView<2, T, C1> const & A, MultiArrayView<2, T, C2
     return detail::leastAngleRegressionImpl(A, b, activeSets, &lasso_solutions, &lsq_solutions, options);
 }
 
-   /** Non-negative Least Squares Regression.
+    /** Non-negative Least Squares Regression.
 
-       Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (with <tt>m \>= n</tt>),
-       and a column vector \a b of length <tt>m</tt> rows, this function computes
-       a column vector \a x of length <tt>n</tt> with <b>non-negative entries</b> that solves the optimization problem
+        Given a matrix \a A with <tt>m</tt> rows and <tt>n</tt> columns (with <tt>m \>= n</tt>),
+        and a column vector \a b of length <tt>m</tt> rows, this function computes
+        a column vector \a x of length <tt>n</tt> with <b>non-negative entries</b> that solves the optimization problem
 
-        \f[ \tilde \textrm{\bf x} = \textrm{argmin}
-            \left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right|\right|_2^2
-            \textrm{ subject to } \textrm{\bf x} \ge \textrm{\bf 0}
-        \f]
+         \f[ \tilde \textrm{\bf x} = \textrm{argmin}
+             \left|\left|\textrm{\bf A} \textrm{\bf x} - \textrm{\bf b}\right|\right|_2^2
+             \textrm{ subject to } \textrm{\bf x} \ge \textrm{\bf 0}
+         \f]
 
-       Both \a b and \a x must be column vectors (i.e. matrices with <tt>1</tt> column).
-       Note that all matrices must already have the correct shape. The solution is computed by means
-       of \ref leastAngleRegression() with non-negativity constraint.
+        Both \a b and \a x must be column vectors (i.e. matrices with <tt>1</tt> column).
+        Note that all matrices must already have the correct shape. The solution is computed by means
+        of \ref leastAngleRegression() with non-negativity constraint.
+
+        <b>\#include</b> \<vigra/regression.hxx\><br/>
+        Namespaces: vigra and vigra::linalg
+     
+        <b> Declarations:</b>
+      
+        \code
+        namespace vigra {
+            namespace linalg {
+                template <class T, class C1, class C2, class C3>
+                void
+                nonnegativeLeastSquares(MultiArrayView<2, T, C1> const & A,
+                                        MultiArrayView<2, T, C2> const &b, 
+                                        MultiArrayView<2, T, C3> &x);
+            }
+            using linalg::nonnegativeLeastSquares;
+        }
+        \endcode
+    */
+doxygen_overloaded_function(template <...> unsigned int nonnegativeLeastSquares)
 
-       <b>\#include</b> \<vigra/regression.hxx\>
-       Namespaces: vigra and vigra::linalg
-   */
 template <class T, class C1, class C2, class C3>
 inline void
 nonnegativeLeastSquares(MultiArrayView<2, T, C1> const & A,
diff --git a/include/vigra/resampling_convolution.hxx b/include/vigra/resampling_convolution.hxx
index da64210..5f16775 100644
--- a/include/vigra/resampling_convolution.hxx
+++ b/include/vigra/resampling_convolution.hxx
@@ -78,12 +78,12 @@ struct MapTargetToSourceCoordinate
     {
         return Rational<int>(i * a + b, c);
     }
-    
+
     bool isExpand2() const
     {
         return a == 1 && b == 0 && c == 2;
     }
-    
+
     bool isReduce2() const
     {
         return a == 2 && b == 0 && c == 1;
@@ -121,7 +121,7 @@ resamplingExpandLine2(SrcIter s, SrcIter send, SrcAcc src,
     int wo = send - s;
     int wn = dend - d;
     int wo2 = 2*wo - 2;
-    
+
     int ileft = std::max(kernels[0].right(), kernels[1].right());
     int iright = wo + std::min(kernels[0].left(), kernels[1].left()) - 1;
     for(int i = 0; i < wn; ++i, ++d)
@@ -129,26 +129,26 @@ resamplingExpandLine2(SrcIter s, SrcIter send, SrcAcc src,
         int is = i / 2;
         KernelRef kernel = kernels[i & 1];
         KernelIter k = kernel.center() + kernel.right();
-        TmpType sum = NumericTraits<TmpType>::zero();        
+        TmpType sum = NumericTraits<TmpType>::zero();
         if(is < ileft)
         {
             for(int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k)
             {
-                int mm = (m < 0) 
-                        ? -m 
+                int mm = (m < 0)
+                        ? -m
                         : m;
                 sum += *k * src(s, mm);
-            }        
+            }
         }
         else if(is > iright)
         {
             for(int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k)
             {
-                int mm =  (m >= wo) 
+                int mm =  (m >= wo)
                             ? wo2 - m
                             : m;
                 sum += *k * src(s, mm);
-            }        
+            }
         }
         else
         {
@@ -156,7 +156,7 @@ resamplingExpandLine2(SrcIter s, SrcIter send, SrcAcc src,
             for(int m = 0; m < kernel.size(); ++m, --k, ++ss)
             {
                 sum += *k * src(ss);
-            }        
+            }
         }
         dest.set(sum, d);
     }
@@ -184,33 +184,33 @@ resamplingReduceLine2(SrcIter s, SrcIter send, SrcAcc src,
     int wo = send - s;
     int wn = dend - d;
     int wo2 = 2*wo - 2;
-    
+
     int ileft = kernel.right();
     int iright = wo + kernel.left() - 1;
     for(int i = 0; i < wn; ++i, ++d)
     {
         int is = 2 * i;
         KernelIter k = kbegin;
-        TmpType sum = NumericTraits<TmpType>::zero();        
+        TmpType sum = NumericTraits<TmpType>::zero();
         if(is < ileft)
         {
             for(int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k)
             {
-                int mm = (m < 0) 
-                        ? -m 
+                int mm = (m < 0)
+                        ? -m
                         : m;
                 sum += *k * src(s, mm);
-            }        
+            }
         }
         else if(is > iright)
         {
             for(int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k)
             {
-                int mm =  (m >= wo) 
+                int mm =  (m >= wo)
                             ? wo2 - m
                             : m;
                 sum += *k * src(s, mm);
-            }        
+            }
         }
         else
         {
@@ -218,7 +218,7 @@ resamplingReduceLine2(SrcIter s, SrcIter send, SrcAcc src,
             for(int m = 0; m < kernel.size(); ++m, --k, ++ss)
             {
                 sum += *k * src(ss);
-            }        
+            }
         }
         dest.set(sum, d);
     }
@@ -243,7 +243,7 @@ resamplingReduceLine2(SrcIter s, SrcIter send, SrcAcc src,
 /** \brief Performs a 1-dimensional resampling convolution of the source signal using the given
     set of kernels.
 
-    This function is mainly used internally: It is called for each dimension of a 
+    This function is mainly used internally: It is called for each dimension of a
     higher dimensional array in order to perform a separable resize operation.
 
     <b> Declaration:</b>
@@ -261,7 +261,7 @@ resamplingReduceLine2(SrcIter s, SrcIter send, SrcAcc src,
         resamplingConvolveLine(SrcIter s, SrcIter send, SrcAcc src,
                                DestIter d, DestIter dend, DestAcc dest,
                                KernelArray const & kernels,
-                               Functor mapTargetToSourceCoordinate)    
+                               Functor mapTargetToSourceCoordinate)
     }
     \endcode
 
@@ -288,7 +288,7 @@ resamplingConvolveLine(SrcIter s, SrcIter send, SrcAcc src,
         resamplingReduceLine2(s, send, src, d, dend, dest, kernels);
         return;
     }
-    
+
     typedef typename
         NumericTraits<typename SrcAcc::value_type>::RealPromote
         TmpType;
@@ -872,7 +872,24 @@ resamplingConvolveImage(MultiArrayView<2, T1, S1> const & src,
 
 /** \brief Two-fold down-sampling for image pyramid construction.
 
-    Sorry, no \ref detailedDocumentation() available yet.
+    This function implements the reduction by one resolution level (first signature)
+    or across several pyramid levels (last signature) of a Gaussian pyramid as described in
+
+    P. Burt, E. Adelson: <i>"The Laplacian Pyramid as a Compact Image Code"</i>, IEEE Trans. Communications, 9(4):532–540, 1983
+
+    That is, it applies the smoothing filter
+    \code
+    [0.25 - centerValue / 2.0, 0.25, centerValue, 0.25, 0.25 - centerValue / 2.0]
+    \endcode
+    to the source image and then copies all pixels with even coordinates to the destination
+    image. The destination image shape must be <tt>dest_shape = ceil(src_shape / 2.0)</tt>.
+    <tt>centerValue</tt> must be between 0.25 and 0.5 and determines the strength of smoothing
+    (bigger values correspond to less smoothing). If <tt>toLevel - fromLevel > 1</tt> in the
+    pyramid variant of the function, this process is repeated until <tt>toLevel</tt> is
+    reached.
+
+    Typically, this functions is used in connection with a \ref vigra::ImagePyramid
+    (last signature below) to perform several levels of reduction in one go.
 
     <b> Declarations:</b>
 
@@ -917,7 +934,8 @@ resamplingConvolveImage(MultiArrayView<2, T1, S1> const & src,
     \code
     namespace vigra {
         template <class Image, class Alloc>
-        void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel,
+        void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid,
+                                     int fromLevel, int toLevel,
                                      double centerValue = 0.4);
     }
     \endcode
@@ -932,32 +950,29 @@ void pyramidReduceBurtFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
 {
     vigra_precondition(0.25 <= centerValue && centerValue <= 0.5,
              "pyramidReduceBurtFilter(): centerValue must be between 0.25 and 0.5.");
-             
+
     int wold = slr.x - sul.x;
     int wnew = dlr.x - dul.x;
     int hold = slr.y - sul.y;
     int hnew = dlr.y - dul.y;
-    
-    vigra_precondition(wnew == (wold + 1) / 2 && hnew == (hold + 1) / 2,
-       "pyramidReduceBurtFilter(): oldSize = ceil(newSize / 2) required.");
-    
+
     vigra_precondition(wnew == (wold + 1) / 2 && hnew == (hold + 1) / 2,
-       "pyramidReduceBurtFilter(): oldSize = ceil(newSize / 2) required.");
-    
+       "pyramidReduceBurtFilter(): destSize = ceil(srcSize / 2) required.");
+
     Rational<int> samplingRatio(1,2), offset(0);
     resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset);
-    
+
     ArrayVector<Kernel1D<double> > kernels(1);
     kernels[0].initExplicitly(-2, 2) = 0.25 - centerValue / 2.0, 0.25, centerValue, 0.25, 0.25 - centerValue / 2.0;
-   
+
     typedef typename
         NumericTraits<typename SrcAccessor::value_type>::RealPromote
         TmpType;
     typedef BasicImage<TmpType> TmpImage;
     typedef typename TmpImage::traverser TmpIterator;
-    
+
     BasicImage<TmpType> tmp(wnew, hold);
-    
+
     TmpIterator tul = tmp.upperLeft();
 
     for(; sul.y < slr.y; ++sul.y, ++tul.y)
@@ -968,7 +983,7 @@ void pyramidReduceBurtFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
         resamplingConvolveLine(sr, sr+wold, src, tr, tr+wnew, tmp.accessor(),
                                kernels, mapCoordinate);
     }
-    
+
     tul  = tmp.upperLeft();
 
     for(; dul.x < dlr.x; ++dul.x, ++tul.x)
@@ -987,13 +1002,14 @@ void pyramidReduceBurtFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                              triple<DestIterator, DestIterator, DestAccessor> dest,
                              double centerValue = 0.4)
 {
-    pyramidReduceBurtFilter(src.first, src.second, src.third, 
+    pyramidReduceBurtFilter(src.first, src.second, src.third,
                             dest.first, dest.second, dest.third, centerValue);
 }
 
 template <class Image, class Alloc>
 inline
-void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel,
+void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid,
+                             int fromLevel, int toLevel,
                              double centerValue = 0.4)
 {
     vigra_precondition(fromLevel  < toLevel,
@@ -1007,7 +1023,27 @@ void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel
 
 /** \brief Two-fold up-sampling for image pyramid reconstruction.
 
-    Sorry, no \ref detailedDocumentation() available yet.
+    This function implements the expansion by one resolution level (first signature)
+    or across several pyramid levels (last signature) of a Gaussian pyramid as described in
+
+    P. Burt, E. Adelson: <i>"The Laplacian Pyramid as a Compact Image Code"</i>, IEEE Trans. Communications, 9(4):532–540, 1983
+
+    That is, the function first places the pixel values of the low-resolution
+    image at the even pixel coordinates of the high-resolution image (pixels with
+    at least one odd coordinate are zero-initialized) and then applies the
+    interpolation filter
+    \code
+    [0.5 - centerValue, 0.5, 2*centerValue, 0.5, 0.5 - centerValue]
+    \endcode
+    to the high-resolution image. The source image shape must be
+    <tt>src_shape = ceil(dest_shape / 2.0)</tt>.
+    <tt>centerValue</tt> must be between 0.25 and 0.5 and determines the sharpness
+    of the interpolation (bigger values correspond to sharper images).
+    If <tt>fromLevel - toLevel > 1</tt> in the pyramid variant of the function,
+    this process is repeated until <tt>toLevel</tt> is reached.
+
+    Typically, this functions is used in connection with a \ref vigra::ImagePyramid
+    (last signature below) to perform several levels of expansion in one go.
 
     <b> Declarations:</b>
 
@@ -1052,7 +1088,8 @@ void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel
     \code
     namespace vigra {
         template <class Image, class Alloc>
-        void pyramidExpandBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel,
+        void pyramidExpandBurtFilter(ImagePyramid<Image, Alloc> & pyramid,
+                                     int fromLevel, int toLevel,
                                      double centerValue = 0.4);
     }
     \endcode
@@ -1067,33 +1104,30 @@ void pyramidExpandBurtFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
 {
     vigra_precondition(0.25 <= centerValue && centerValue <= 0.5,
              "pyramidExpandBurtFilter(): centerValue must be between 0.25 and 0.5.");
-             
+
     int wold = slr.x - sul.x;
     int wnew = dlr.x - dul.x;
     int hold = slr.y - sul.y;
     int hnew = dlr.y - dul.y;
-    
-    vigra_precondition(wold == (wnew + 1) / 2 && hold == (hnew + 1) / 2,
-       "pyramidExpandBurtFilter(): oldSize = ceil(newSize / 2) required.");
-    
+
     vigra_precondition(wold == (wnew + 1) / 2 && hold == (hnew + 1) / 2,
        "pyramidExpandBurtFilter(): oldSize = ceil(newSize / 2) required.");
-    
+
     Rational<int> samplingRatio(2), offset(0);
     resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset);
-    
+
     ArrayVector<Kernel1D<double> > kernels(2);
     kernels[0].initExplicitly(-1, 1) = 0.5 - centerValue, 2.0*centerValue, 0.5 - centerValue;
     kernels[1].initExplicitly(-1, 0) = 0.5, 0.5;
-   
+
     typedef typename
         NumericTraits<typename SrcAccessor::value_type>::RealPromote
         TmpType;
     typedef BasicImage<TmpType> TmpImage;
     typedef typename TmpImage::traverser TmpIterator;
-    
+
     BasicImage<TmpType> tmp(wnew, hold);
-    
+
     TmpIterator tul = tmp.upperLeft();
 
     for(; sul.y < slr.y; ++sul.y, ++tul.y)
@@ -1104,7 +1138,7 @@ void pyramidExpandBurtFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
         resamplingConvolveLine(sr, sr+wold, src, tr, tr+wnew, tmp.accessor(),
                                kernels, mapCoordinate);
     }
-    
+
     tul  = tmp.upperLeft();
 
     for(; dul.x < dlr.x; ++dul.x, ++tul.x)
@@ -1123,7 +1157,7 @@ void pyramidExpandBurtFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
                              triple<DestIterator, DestIterator, DestAccessor> dest,
                              double centerValue = 0.4)
 {
-    pyramidExpandBurtFilter(src.first, src.second, src.third, 
+    pyramidExpandBurtFilter(src.first, src.second, src.third,
                             dest.first, dest.second, dest.third, centerValue);
 }
 
@@ -1144,42 +1178,61 @@ void pyramidExpandBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel
 
 /** \brief Create a Laplacian pyramid.
 
-    Sorry, no \ref detailedDocumentation() available yet.
+    This function implements the reduction across several resolution levels of
+    a Laplacian pyramid as described in
+
+    P. Burt, E. Adelson: <i>"The Laplacian Pyramid as a Compact Image Code"</i>, IEEE Trans. Communications, 9(4):532–540, 1983
+
+    It first creates a Gaussian pyramid using \ref pyramidReduceBurtFilter(), then
+    upsamples each level once using \ref pyramidExpandBurtFilter(), and finally
+    stores the difference between the upsampled and original versions of
+    each level (i.e. the Laplacian of Gaussian is approximated by a difference
+    of Gaussian).
 
     <b>\#include</b> \<vigra/resampling_convolution.hxx\><br>
     Namespace: vigra
 */
 template <class Image, class Alloc>
 inline void
-pyramidReduceBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel,
+pyramidReduceBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid,
+                           int fromLevel, int toLevel,
                            double centerValue = 0.4)
 {
     using namespace functor;
-    
+
     pyramidReduceBurtFilter(pyramid, fromLevel, toLevel, centerValue);
     for(int i=fromLevel; i < toLevel; ++i)
     {
         typename ImagePyramid<Image, Alloc>::value_type tmpImage(pyramid[i].size());
         pyramidExpandBurtFilter(srcImageRange(pyramid[i+1]), destImageRange(tmpImage), centerValue);
         combineTwoImages(srcImageRange(tmpImage), srcImage(pyramid[i]), destImage(pyramid[i]),
-                       Arg1() - Arg2()); 
+                       Arg1() - Arg2());
     }
 }
 
 /** \brief Reconstruct a Laplacian pyramid.
 
-    Sorry, no \ref detailedDocumentation() available yet.
+    This function implements the reconstruction of a Gaussian pyramid
+    across several resolution levels of a Laplacian pyramid as described in
+
+    P. Burt, E. Adelson: <i>"The Laplacian Pyramid as a Compact Image Code"</i>, IEEE Trans. Communications, 9(4):532–540, 1983
+
+    At each level starting from <tt>fromLevel</tt>, this function calls
+    \ref pyramidExpandBurtFilter() to interpolate the image to the next highest
+    resolution, and then adds the interpolated image to the image stored at the
+    next level.
 
     <b>\#include</b> \<vigra/resampling_convolution.hxx\><br>
     Namespace: vigra
 */
 template <class Image, class Alloc>
 inline void
-pyramidExpandBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel,
+pyramidExpandBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid,
+                           int fromLevel, int toLevel,
                            double centerValue = 0.4)
 {
     using namespace functor;
-    
+
     vigra_precondition(fromLevel  > toLevel,
        "pyramidExpandBurtLaplacian(): fromLevel must be larger than toLevel.");
     vigra_precondition(pyramid.lowestLevel() <= toLevel && fromLevel <= pyramid.highestLevel(),
@@ -1190,7 +1243,7 @@ pyramidExpandBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int fromLevel,
         typename ImagePyramid<Image, Alloc>::value_type tmpImage(pyramid[i].size());
         pyramidExpandBurtFilter(srcImageRange(pyramid[i+1]), destImageRange(tmpImage), centerValue);
         combineTwoImages(srcImageRange(tmpImage), srcImage(pyramid[i]), destImage(pyramid[i]),
-                       Arg1() - Arg2()); 
+                       Arg1() - Arg2());
     }
 }
 
diff --git a/include/vigra/resizeimage.hxx b/include/vigra/resizeimage.hxx
index cdd7255..30264f6 100644
--- a/include/vigra/resizeimage.hxx
+++ b/include/vigra/resizeimage.hxx
@@ -148,7 +148,12 @@ ArrayVector<double> CoscotFunction<T>::prefilterCoefficients_;
 /** \addtogroup GeometricTransformations Geometric Transformations
     Zoom up and down by repeating pixels, or using various interpolation schemes.
 
-    See also: \ref resamplingConvolveImage(), \ref resampleImage(), \ref resizeMultiArraySplineInterpolation()
+    See also: 
+    <ul>
+    <li> \ref ResamplingConvolutionFilters to resize by means of pyramids or smoothing filters</li>
+    <li> \ref resampleImage() to just drop or repeat pixels</li>
+    <li> \ref resizeMultiArraySplineInterpolation() for multi-dimensional interpolation</li>
+    </ul>
 
     <b>\#include</b> \<vigra/stdimagefunctions.hxx\><br>
     <b>or</b><br>
diff --git a/include/vigra/rgbvalue.hxx b/include/vigra/rgbvalue.hxx
index dd912ec..42192d5 100644
--- a/include/vigra/rgbvalue.hxx
+++ b/include/vigra/rgbvalue.hxx
@@ -159,7 +159,6 @@ class RGBValue
     typedef typename Base::size_type size_type;
     typedef typename Base::difference_type difference_type;
     typedef typename Base::scalar_multiplier scalar_multiplier;
-    typedef typename Base::ReverseCopyTag ReverseCopyTag;
 
         /** Color index positions
         */
diff --git a/include/vigra/sampling.hxx b/include/vigra/sampling.hxx
index a84531d..11450e0 100644
--- a/include/vigra/sampling.hxx
+++ b/include/vigra/sampling.hxx
@@ -269,7 +269,7 @@ class Sampler
     {
         // compute how many samples to take from each stratum
         // (may be unequal if sample_size_ is not a multiple of strataCount())
-        int strata_sample_size = (int)std::ceil(double(sample_size_) / strataCount());
+        int strata_sample_size = static_cast<int>(std::ceil(double(sample_size_) / strataCount()));
         int strata_total_count = strata_sample_size * strataCount();
 
         for(StrataIndicesType::iterator i = strata_indices_.begin(); 
@@ -299,8 +299,8 @@ class Sampler
             Random const * rnd = 0)
     : total_count_(totalCount),
       sample_size_(opt.sample_size == 0
-                         ? (int)(std::ceil(total_count_ * opt.sample_proportion))
-                         : opt.sample_size),
+                   ? static_cast<int>((std::ceil(total_count_ * opt.sample_proportion)))
+                   : opt.sample_size),
       current_oob_count_(oobInvalid),
       current_sample_(sample_size_),
       current_oob_sample_(total_count_),
@@ -339,8 +339,8 @@ class Sampler
             Random const * rnd = 0)
     : total_count_(strataEnd - strataBegin),
       sample_size_(opt.sample_size == 0
-                         ? (int)(std::ceil(total_count_ * opt.sample_proportion))
-                         : opt.sample_size),
+                   ? static_cast<int>((std::ceil(total_count_ * opt.sample_proportion)))
+                   : opt.sample_size),
       current_oob_count_(oobInvalid),
       current_sample_(sample_size_),
       current_oob_sample_(total_count_),
@@ -367,7 +367,7 @@ class Sampler
                 strata_indices_[0][i] = i;
         }
             
-        vigra_precondition(sample_size_ >= (int)strata_indices_.size(),
+        vigra_precondition(sample_size_ >= static_cast<int>(strata_indices_.size()),
             "Sampler(): Requested sample count must be at least as large as the number of strata.");
 
         initStrataCount();
@@ -479,7 +479,7 @@ void Sampler<Random>::sample()
         {
             // do sampling with replacement in each strata and copy data.
             int stratum_size = iter->second.size();
-            for(int i = 0; i < (int)strata_sample_size_[iter->first]; ++i, ++j)
+            for(int i = 0; i < static_cast<int>(strata_sample_size_[iter->first]); ++i, ++j)
             {
                 current_sample_[j] = iter->second[random_.uniformInt(stratum_size)];
                 is_used_[current_sample_[j]] = true;
@@ -495,7 +495,7 @@ void Sampler<Random>::sample()
         {
             // do sampling without replacement in each strata and copy data.
             int stratum_size = iter->second.size();
-            for(int i = 0; i < (int)strata_sample_size_[iter->first]; ++i, ++j)
+            for(int i = 0; i < static_cast<int>(strata_sample_size_[iter->first]); ++i, ++j)
             {
                 std::swap(iter->second[i], iter->second[i+ random_.uniformInt(stratum_size - i)]);
                 current_sample_[j] = iter->second[i];
diff --git a/include/vigra/seededregiongrowing.hxx b/include/vigra/seededregiongrowing.hxx
index a0dcd4a..53aa003 100644
--- a/include/vigra/seededregiongrowing.hxx
+++ b/include/vigra/seededregiongrowing.hxx
@@ -484,7 +484,7 @@ seededRegionGrowing(SrcIterator srcul,
             }
             else
             {
-                vigra_precondition((LabelType)*irx <= stats.maxRegionLabel(),
+                vigra_precondition((LabelType)*irx <= (LabelType)stats.maxRegionLabel(),
                     "seededRegionGrowing(): Largest label exceeds size of RegionStatisticsArray.");
                 if(maxRegionLabel < *irx)
                     maxRegionLabel = *irx;
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/include/vigra/seg_to_seeds.hxx
similarity index 56%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to include/vigra/seg_to_seeds.hxx
index 37a8c81..c924f3d 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/include/vigra/seg_to_seeds.hxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*               Copyright 2012-2013 by Ullrich Koethe                  */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,61 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
-#include <vigra/numpy_array.hxx>
-#include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
-
-namespace python = boost::python;
+#ifndef VIGRA_SEG_TO_SEED_HXX
+#define VIGRA_SEG_TO_SEED_HXX
 
+#include "multi_array.hxx"
+#include "multi_gridgraph.hxx"
 namespace vigra {
 
-UInt32 pychecksum(python::str const & s)
-{
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+    template<unsigned int DIM, class LABEL_TYPE,class LABEL_TYPE_OUT>
+    void shrinkLabels(
+        MultiArrayView<DIM,LABEL_TYPE>     labels,
+        const size_t shrinkNpixels,
+        MultiArrayView<DIM,LABEL_TYPE_OUT> shrinkedLabels
+    ){
+        shrinkedLabels = labels;
+
+        typedef GridGraph<DIM, undirected_tag> Graph;
+        typedef typename Graph::Node Node;
+        //typedef typename Graph::Edge Edge;
+        typedef typename Graph::NodeIt graph_scanner;
+        typedef typename Graph::OutArcIt neighbor_iterator;
+
+        const Graph g(labels.shape());
+
+        // INITAL LOOP
+        for (graph_scanner n(g); n != lemon::INVALID; ++n){
+            const Node node(*n);
+            for (neighbor_iterator arc(g, node); arc != lemon::INVALID; ++arc){
+                const Node otherNode = g.target(arc);
+
+                if(labels[node]!=labels[otherNode]){
+                    shrinkedLabels[node]=0;
+                    shrinkedLabels[otherNode]=0;
+                }
+            }
+        }
+
+        MultiArray<DIM,bool> visited(labels.shape());
+        for(size_t r=0;r<shrinkNpixels-1;++r){
+            std::fill(visited.begin(),visited.end(),false);
+            for (graph_scanner n(g); n != lemon::INVALID; ++n){
+                const Node node(*n);
+                if(!visited[n] && shrinkedLabels[node]==0){
+                    for (neighbor_iterator arc(g, node); arc != lemon::INVALID; ++arc){
+                        const Node otherNode = g.target(arc);
+                        shrinkedLabels[otherNode]=0;
+                        visited[otherNode]=true;
+                    }
+                }
+            }
+        }
+    }
 
-} // namespace vigra
 
-using namespace boost::python;
-using namespace vigra;
+} // end namespace vigra
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
-{
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
-}
+#endif // VIGRA_SEG_TO_SEED_HXX
diff --git a/include/vigra/separableconvolution.hxx b/include/vigra/separableconvolution.hxx
index 3ae5781..1745ae3 100644
--- a/include/vigra/separableconvolution.hxx
+++ b/include/vigra/separableconvolution.hxx
@@ -59,7 +59,7 @@ class Kernel1D;
 
 // This function assumes that the input array is actually larger than
 // the range [is, iend), so that it can safely access values outside
-// this range. This is useful if (1) we work on a small ROI, or 
+// this range. This is useful if (1) we work on a small ROI, or
 // (2) we enlarge the input by copying with border treatment.
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor,
@@ -96,7 +96,7 @@ namespace detail {
 // dest array must have size = stop - start + kright - kleft
 template <class SrcIterator, class SrcAccessor,
           class DestIterator, class DestAccessor>
-void 
+void
 copyLineWithBorderTreatment(SrcIterator is, SrcIterator iend, SrcAccessor sa,
                             DestIterator id, DestAccessor da,
                             int start, int stop,
@@ -107,7 +107,7 @@ copyLineWithBorderTreatment(SrcIterator is, SrcIterator iend, SrcAccessor sa,
     int leftBorder = start - kright;
     int rightBorder = stop - kleft;
     int copyEnd = std::min(w, rightBorder);
-    
+
     if(leftBorder < 0)
     {
         switch(borderTreatment)
@@ -154,13 +154,13 @@ copyLineWithBorderTreatment(SrcIterator is, SrcIterator iend, SrcAccessor sa,
             }
         }
     }
-    
+
     SrcIterator iss = is + leftBorder;
     vigra_invariant( leftBorder < copyEnd,
         "copyLineWithBorderTreatment(): assertion failed.");
     for(; leftBorder<copyEnd; ++leftBorder, ++id, ++iss)
         da.set(sa(iss), id);
-    
+
     if(copyEnd < rightBorder)
     {
         switch(borderTreatment)
@@ -235,7 +235,7 @@ void internalConvolveLineWrap(SrcIterator is, SrcIterator iend, SrcAccessor sa,
             typename KernelAccessor::value_type>::Promote SumType;
 
     SrcIterator ibegin = is;
-    
+
     if(stop == 0)
         stop = w;
     is += start;
@@ -336,11 +336,11 @@ void internalConvolveLineClip(SrcIterator is, SrcIterator iend, SrcAccessor sa,
             typename KernelAccessor::value_type>::Promote SumType;
 
     SrcIterator ibegin = is;
-    
+
     if(stop == 0)
         stop = w;
     is += start;
-    
+
     for(int x=start; x<stop; ++x, ++is, ++id)
     {
         KernelIterator ik = kernel + kright;
@@ -380,7 +380,7 @@ void internalConvolveLineClip(SrcIterator is, SrcIterator iend, SrcAccessor sa,
                     sum += ka(ik) * sa(iss);
                 }
             }
-            
+
             sum = norm / (norm - clipped) * sum;
         }
         else if(w-x <= -kleft)
@@ -412,7 +412,7 @@ void internalConvolveLineClip(SrcIterator is, SrcIterator iend, SrcAccessor sa,
                 sum += ka(ik) * sa(iss);
             }
         }
-        
+
         da.set(detail::RequiresExplicitCast<typename
                       DestAccessor::value_type>::cast(sum), id);
     }
@@ -430,7 +430,7 @@ template <class SrcIterator, class SrcAccessor,
 void internalConvolveLineZeropad(SrcIterator is, SrcIterator iend, SrcAccessor sa,
                                  DestIterator id, DestAccessor da,
                                  KernelIterator kernel, KernelAccessor ka,
-                                 int kleft, int kright, 
+                                 int kleft, int kright,
                                  int start = 0, int stop = 0)
 {
     int w = std::distance( is, iend );
@@ -440,11 +440,11 @@ void internalConvolveLineZeropad(SrcIterator is, SrcIterator iend, SrcAccessor s
             typename KernelAccessor::value_type>::Promote SumType;
 
     SrcIterator ibegin = is;
-    
+
     if(stop == 0)
         stop = w;
     is += start;
-    
+
     for(int x=start; x<stop; ++x, ++is, ++id)
     {
         SumType sum = NumericTraits<SumType>::zero();
@@ -453,7 +453,7 @@ void internalConvolveLineZeropad(SrcIterator is, SrcIterator iend, SrcAccessor s
         {
             KernelIterator ik = kernel + x;
             SrcIterator iss = ibegin;
-            
+
             if(w-x <= -kleft)
             {
                 SrcIterator isend = iend;
@@ -491,7 +491,7 @@ void internalConvolveLineZeropad(SrcIterator is, SrcIterator iend, SrcAccessor s
                 sum += ka(ik) * sa(iss);
             }
         }
-        
+
         da.set(detail::RequiresExplicitCast<typename
                       DestAccessor::value_type>::cast(sum), id);
     }
@@ -519,11 +519,11 @@ void internalConvolveLineReflect(SrcIterator is, SrcIterator iend, SrcAccessor s
             typename KernelAccessor::value_type>::Promote SumType;
 
     SrcIterator ibegin = is;
-    
+
     if(stop == 0)
         stop = w;
     is += start;
-    
+
     for(int x=start; x<stop; ++x, ++is, ++id)
     {
         KernelIterator ik = kernel + kright;
@@ -618,7 +618,7 @@ void internalConvolveLineRepeat(SrcIterator is, SrcIterator iend, SrcAccessor sa
             typename KernelAccessor::value_type>::Promote SumType;
 
     SrcIterator ibegin = is;
-    
+
     if(stop == 0)
         stop = w;
     is += start;
@@ -785,13 +785,13 @@ void internalConvolveLineAvoid(SrcIterator is, SrcIterator iend, SrcAccessor sa,
     The kernel's value_type must be an algebraic field,
     i.e. the arithmetic operations (+, -, *, /) and NumericTraits must
     be defined.
-    
+
     If <tt>start</tt> and <tt>stop</tt> are non-zero, the relation
     <tt>0 <= start < stop <= width</tt> must hold (where <tt>width</tt>
-    is the length of the input array). The convolution is then restricted to that 
+    is the length of the input array). The convolution is then restricted to that
     subrange, and it is assumed that the output array only refers to that
-    subrange (i.e. <tt>id</tt> points to the element corresponding to 
-    <tt>start</tt>). If <tt>start</tt> and <tt>stop</tt> are both zero 
+    subrange (i.e. <tt>id</tt> points to the element corresponding to
+    <tt>start</tt>). If <tt>start</tt> and <tt>stop</tt> are both zero
     (the default), the entire array is convolved.
 
     <b> Declarations:</b>
@@ -912,7 +912,7 @@ void convolveLine(SrcIterator is, SrcIterator iend, SrcAccessor sa,
 
     vigra_precondition(w >= std::max(kright, -kleft) + 1,
                  "convolveLine(): kernel longer than line.\n");
-                 
+
     if(stop != 0)
         vigra_precondition(0 <= start && start < stop && stop <= w,
                         "convolveLine(): invalid subrange (start, stop).\n");
@@ -920,7 +920,7 @@ void convolveLine(SrcIterator is, SrcIterator iend, SrcAccessor sa,
     typedef typename PromoteTraits<
             typename SrcAccessor::value_type,
             typename KernelAccessor::value_type>::Promote SumType;
-    ArrayVector<SumType> a(iend - is); 
+    ArrayVector<SumType> a(iend - is);
     switch(border)
     {
       case BORDER_TREATMENT_WRAP:
@@ -996,7 +996,7 @@ void convolveLine(triple<SrcIterator, SrcIterator, SrcAccessor> src,
 
 /** \brief Performs a 1 dimensional convolution in x direction.
 
-    It calls \ref convolveLine() for every row of the image. See \ref convolveLine() 
+    It calls \ref convolveLine() for every row of the image. See \ref convolveLine()
     for more information about required interfaces and vigra_preconditions.
 
     <b> Declarations:</b>
@@ -1072,9 +1072,9 @@ void convolveLine(triple<SrcIterator, SrcIterator, SrcAccessor> src,
     vigra::separableConvolveX(srcImageRange(src), destImage(dest), kernel1d(kernel));
     \endcode
     \deprecatedEnd
-    
+
     <b>Preconditions:</b>
-    
+
     <ul>
     <li> The x-axis must be longer than the kernel radius: <tt>w > std::max(kernel.right(), -kernel.left())</tt>.
     <li> If <tt>border == BORDER_TREATMENT_CLIP</tt>: The sum of kernel elements must be != 0.
@@ -1151,7 +1151,7 @@ separableConvolveX(MultiArrayView<2, T1, S1> const & src,
 
 /** \brief Performs a 1 dimensional convolution in y direction.
 
-    It calls \ref convolveLine() for every column of the image. See \ref convolveLine() 
+    It calls \ref convolveLine() for every column of the image. See \ref convolveLine()
     for more information about required interfaces and vigra_preconditions.
 
     <b> Declarations:</b>
@@ -1227,9 +1227,9 @@ separableConvolveX(MultiArrayView<2, T1, S1> const & src,
     vigra::separableConvolveY(srcImageRange(src), destImage(dest), kernel1d(kernel));
     \endcode
     \deprecatedEnd
-    
+
     <b>Preconditions:</b>
-    
+
     <ul>
     <li> The y-axis must be longer than the kernel radius: <tt>h > std::max(kernel.right(), -kernel.left())</tt>.
     <li> If <tt>border == BORDER_TREATMENT_CLIP</tt>: The sum of kernel elements must be != 0.
@@ -1408,9 +1408,11 @@ class Kernel1D
           norm_(norm)
         {}
 
-        ~InitProxy() 
+        ~InitProxy()
 #ifndef _MSC_VER
-             throw(PreconditionViolation)
+            throw(PreconditionViolation)
+#elif _MSC_VER >= 1900
+            noexcept(false)
 #endif
         {
             vigra_precondition(count_ == 1 || count_ == sum_,
@@ -1420,7 +1422,7 @@ class Kernel1D
 
         InitProxy & operator,(value_type const & v)
         {
-            if(sum_ == count_) 
+            if(sum_ == count_)
                 norm_ = *iter_;
 
             norm_ += v;
@@ -1476,7 +1478,7 @@ class Kernel1D
       border_treatment_(k.borderTreatment()),
       norm_(k.norm())
     {}
-    
+
         /** Copy assignment.
         */
     Kernel1D & operator=(Kernel1D const & k)
@@ -1530,10 +1532,10 @@ class Kernel1D
             if <tt>norm</tt> is 0.0, the kernel is normalized to 1 by the analytic
             expression for the Gaussian, and <b>no</b> correction for the windowing
             error is performed. If <tt>windowRatio = 0.0</tt>, the radius of the filter
-            window is <tt>radius = round(3.0 * std_dev)</tt>, otherwise it is 
+            window is <tt>radius = round(3.0 * std_dev)</tt>, otherwise it is
             <tt>radius = round(windowRatio * std_dev)</tt> (where <tt>windowRatio > 0.0</tt>
             is required).
-            
+
             Precondition:
             \code
             std_dev >= 0.0
@@ -1598,9 +1600,9 @@ class Kernel1D
             by windowing the Gaussian to a finite interval. However,
             if <tt>norm</tt> is 0.0, the kernel is normalized to 1 by the analytic
             expression for the Gaussian derivative, and <b>no</b> correction for the
-            windowing error is performed. If <tt>windowRatio = 0.0</tt>, the radius 
-            of the filter window is <tt>radius = round(3.0 * std_dev + 0.5 * order)</tt>, 
-            otherwise it is <tt>radius = round(windowRatio * std_dev)</tt> (where 
+            windowing error is performed. If <tt>windowRatio = 0.0</tt>, the radius
+            of the filter window is <tt>radius = round(3.0 * std_dev + 0.5 * order)</tt>,
+            otherwise it is <tt>radius = round(windowRatio * std_dev)</tt> (where
             <tt>windowRatio > 0.0</tt> is required).
 
             Preconditions:
@@ -1628,16 +1630,16 @@ class Kernel1D
 
         /**
             Init an optimal 3-tap smoothing filter.
-            The filter values are 
-            
+            The filter values are
+
             \code
             [0.216, 0.568, 0.216]
             \endcode
-            
+
             These values are optimal in the sense that the 3x3 filter obtained by separable application
             of this filter is the best possible 3x3 approximation to a Gaussian filter.
             The equivalent Gaussian has sigma = 0.680.
- 
+
             Postconditions:
             \code
             1. left()  == -1
@@ -1654,18 +1656,18 @@ class Kernel1D
 
         /**
             Init an optimal 3-tap smoothing filter to be used in the context of first derivative computation.
-            This filter must be used in conjunction with the symmetric difference filter (see initSymmetricDifference()), 
+            This filter must be used in conjunction with the symmetric difference filter (see initSymmetricDifference()),
             such that the difference filter is applied along one dimension, and the smoothing filter along the other.
-            The filter values are 
-            
+            The filter values are
+
             \code
             [0.224365, 0.55127, 0.224365]
             \endcode
-            
-            These values are optimal in the sense that the 3x3 filter obtained by combining 
-            this filter with the symmetric difference is the best possible 3x3 approximation to a 
+
+            These values are optimal in the sense that the 3x3 filter obtained by combining
+            this filter with the symmetric difference is the best possible 3x3 approximation to a
             Gaussian first derivative filter. The equivalent Gaussian has sigma = 0.675.
- 
+
             Postconditions:
             \code
             1. left()  == -1
@@ -1682,18 +1684,18 @@ class Kernel1D
 
         /**
             Init an optimal 3-tap smoothing filter to be used in the context of second derivative computation.
-            This filter must be used in conjunction with the 3-tap second difference filter (see initSecondDifference3()), 
+            This filter must be used in conjunction with the 3-tap second difference filter (see initSecondDifference3()),
             such that the difference filter is applied along one dimension, and the smoothing filter along the other.
-            The filter values are 
-            
+            The filter values are
+
             \code
             [0.13, 0.74, 0.13]
             \endcode
-            
-            These values are optimal in the sense that the 3x3 filter obtained by combining 
-            this filter with the 3-tap second difference is the best possible 3x3 approximation to a 
+
+            These values are optimal in the sense that the 3x3 filter obtained by combining
+            this filter with the 3-tap second difference is the best possible 3x3 approximation to a
             Gaussian second derivative filter. The equivalent Gaussian has sigma = 0.433.
- 
+
             Postconditions:
             \code
             1. left()  == -1
@@ -1710,16 +1712,16 @@ class Kernel1D
 
         /**
             Init an optimal 5-tap smoothing filter.
-            The filter values are 
-            
+            The filter values are
+
             \code
             [0.03134, 0.24, 0.45732, 0.24, 0.03134]
             \endcode
-            
+
             These values are optimal in the sense that the 5x5 filter obtained by separable application
             of this filter is the best possible 5x5 approximation to a Gaussian filter.
             The equivalent Gaussian has sigma = 0.867.
- 
+
             Postconditions:
             \code
             1. left()  == -2
@@ -1736,18 +1738,18 @@ class Kernel1D
 
         /**
             Init an optimal 5-tap smoothing filter to be used in the context of first derivative computation.
-           This filter must be used in conjunction with the optimal 5-tap first derivative filter 
-           (see initOptimalFirstDerivative5()),  such that the derivative filter is applied along one dimension, 
-           and the smoothing filter along the other. The filter values are 
-            
+           This filter must be used in conjunction with the optimal 5-tap first derivative filter
+           (see initOptimalFirstDerivative5()),  such that the derivative filter is applied along one dimension,
+           and the smoothing filter along the other. The filter values are
+
             \code
             [0.04255, 0.241, 0.4329, 0.241, 0.04255]
             \endcode
-            
-            These values are optimal in the sense that the 5x5 filter obtained by combining 
-            this filter with the optimal 5-tap first derivative is the best possible 5x5 approximation to a 
+
+            These values are optimal in the sense that the 5x5 filter obtained by combining
+            this filter with the optimal 5-tap first derivative is the best possible 5x5 approximation to a
             Gaussian first derivative filter. The equivalent Gaussian has sigma = 0.906.
- 
+
             Postconditions:
             \code
             1. left()  == -2
@@ -1764,18 +1766,18 @@ class Kernel1D
 
         /**
             Init an optimal 5-tap smoothing filter to be used in the context of second derivative computation.
-           This filter must be used in conjunction with the optimal 5-tap second derivative filter 
-           (see initOptimalSecondDerivative5()), such that the derivative filter is applied along one dimension, 
-           and the smoothing filter along the other. The filter values are 
-            
+           This filter must be used in conjunction with the optimal 5-tap second derivative filter
+           (see initOptimalSecondDerivative5()), such that the derivative filter is applied along one dimension,
+           and the smoothing filter along the other. The filter values are
+
             \code
             [0.0243, 0.23556, 0.48028, 0.23556, 0.0243]
             \endcode
-            
-            These values are optimal in the sense that the 5x5 filter obtained by combining 
-            this filter with the optimal 5-tap second derivative is the best possible 5x5 approximation to a 
+
+            These values are optimal in the sense that the 5x5 filter obtained by combining
+            this filter with the optimal 5-tap second derivative is the best possible 5x5 approximation to a
             Gaussian second derivative filter. The equivalent Gaussian has sigma = 0.817.
- 
+
             Postconditions:
             \code
             1. left()  == -2
@@ -1793,19 +1795,19 @@ class Kernel1D
         /**
             Init a 5-tap filter as defined by Peter Burt in the context of pyramid creation.
             The filter values are
-            
+
             \code
             [a, 0.25, 0.5-2*a, 0.25, a]
             \endcode
-            
+
             The default <tt>a = 0.04785</tt> is optimal in the sense that it minimizes the difference
-            to a true Gaussian filter (which would have sigma = 0.975). For other values of <tt>a</tt>, the scale 
+            to a true Gaussian filter (which would have sigma = 0.975). For other values of <tt>a</tt>, the scale
             of the most similar Gaussian can be approximated by
-            
+
             \code
             sigma = 5.1 * a + 0.731
             \endcode
- 
+
             Preconditions:
             \code
             0 <= a <= 0.125
@@ -1882,7 +1884,7 @@ class Kernel1D
         /**
             Init as a symmetric gradient filter of the form
             <TT>[ 0.5 * norm, 0.0 * norm, -0.5 * norm]</TT>
-           
+
             <b>Deprecated</b>. Use initSymmetricDifference() instead.
 
             Postconditions:
@@ -1900,7 +1902,7 @@ class Kernel1D
     }
 
         /** Init as a symmetric gradient filter with norm 1.
-           
+
            <b>Deprecated</b>. Use initSymmetricDifference() instead.
          */
     void initSymmetricGradient()
@@ -1910,11 +1912,11 @@ class Kernel1D
 
         /** Init as the 2-tap forward difference filter.
              The filter values are
-             
+
             \code
             [1.0, -1.0]
             \endcode
-             
+
             (note that filters are reflected by the convolution algorithm,
              and we get a forward difference after reflection).
 
@@ -1934,11 +1936,11 @@ class Kernel1D
 
         /** Init as the 2-tap backward difference filter.
             The filter values are
-             
+
             \code
             [1.0, -1.0]
             \endcode
-             
+
             (note that filters are reflected by the convolution algorithm,
              and we get a forward difference after reflection).
 
@@ -1960,7 +1962,7 @@ class Kernel1D
 
         /** Init as the 3-tap symmetric difference filter
             The filter values are
-             
+
             \code
             [0.5, 0, -0.5]
             \endcode
@@ -1981,7 +1983,7 @@ class Kernel1D
         /**
             Init the 3-tap second difference filter.
             The filter values are
-             
+
             \code
             [1, -2, 1]
             \endcode
@@ -1999,25 +2001,25 @@ class Kernel1D
         this->initExplicitly(-1, 1) = 1.0, -2.0, 1.0;
         this->setBorderTreatment(BORDER_TREATMENT_REFLECT);
     }
-    
+
         /**
             Init an optimal 5-tap first derivative filter.
-            This filter must be used in conjunction with the corresponding 5-tap smoothing filter 
+            This filter must be used in conjunction with the corresponding 5-tap smoothing filter
             (see initOptimalFirstDerivativeSmoothing5()), such that the derivative filter is applied along one dimension,
             and the smoothing filter along the other.
-            The filter values are 
-            
+            The filter values are
+
             \code
             [0.1, 0.3, 0.0, -0.3, -0.1]
             \endcode
-            
-            These values are optimal in the sense that the 5x5 filter obtained by combining 
-            this filter with the corresponding 5-tap smoothing filter is the best possible 5x5 approximation to a 
+
+            These values are optimal in the sense that the 5x5 filter obtained by combining
+            this filter with the corresponding 5-tap smoothing filter is the best possible 5x5 approximation to a
             Gaussian first derivative filter. The equivalent Gaussian has sigma = 0.906.
-            
+
             If the filter is instead separably combined with itself, an almost optimal approximation of the
             mixed second Gaussian derivative at scale sigma = 0.899 results.
- 
+
             Postconditions:
             \code
             1. left()  == -2
@@ -2031,22 +2033,22 @@ class Kernel1D
         this->initExplicitly(-2, 2) = 0.1, 0.3, 0.0, -0.3, -0.1;
         this->setBorderTreatment(BORDER_TREATMENT_REFLECT);
     }
-    
+
         /**
             Init an optimal 5-tap second derivative filter.
-            This filter must be used in conjunction with the corresponding 5-tap smoothing filter 
+            This filter must be used in conjunction with the corresponding 5-tap smoothing filter
             (see initOptimalSecondDerivativeSmoothing5()), such that the derivative filter is applied along one dimension,
             and the smoothing filter along the other.
-            The filter values are 
-            
+            The filter values are
+
             \code
             [0.22075, 0.117, -0.6755, 0.117, 0.22075]
             \endcode
-            
-            These values are optimal in the sense that the 5x5 filter obtained by combining 
-            this filter with the corresponding 5-tap smoothing filter is the best possible 5x5 approximation to a 
+
+            These values are optimal in the sense that the 5x5 filter obtained by combining
+            this filter with the corresponding 5-tap smoothing filter is the best possible 5x5 approximation to a
             Gaussian second derivative filter. The equivalent Gaussian has sigma = 0.817.
- 
+
             Postconditions:
             \code
             1. left()  == -2
@@ -2249,7 +2251,7 @@ void Kernel1D<ARITHTYPE>::normalize(value_type norm,
 template <class ARITHTYPE>
 void
 Kernel1D<ARITHTYPE>::initGaussian(double std_dev,
-                                  value_type norm, 
+                                  value_type norm,
                                   double windowRatio)
 {
     vigra_precondition(std_dev >= 0.0,
@@ -2375,7 +2377,7 @@ template <class ARITHTYPE>
 void
 Kernel1D<ARITHTYPE>::initGaussianDerivative(double std_dev,
                                             int order,
-                                            value_type norm, 
+                                            value_type norm,
                                             double windowRatio)
 {
     vigra_precondition(order >= 0,
@@ -2386,7 +2388,7 @@ Kernel1D<ARITHTYPE>::initGaussianDerivative(double std_dev,
         initGaussian(std_dev, norm, windowRatio);
         return;
     }
-    
+
     vigra_precondition(std_dev > 0.0,
               "Kernel1D::initGaussianDerivative(): "
               "Standard deviation must be > 0.");
diff --git a/include/vigra/shockfilter.hxx b/include/vigra/shockfilter.hxx
new file mode 100644
index 0000000..a49985c
--- /dev/null
+++ b/include/vigra/shockfilter.hxx
@@ -0,0 +1,312 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2007-2014 by Benjamin Seppke                 */
+/*       Cognitive Systems Group, University of Hamburg, Germany        */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_SHOCKFILTER_HXX
+#define VIGRA_SHOCKFILTER_HXX
+
+#include "basicimage.hxx"
+#include "convolution.hxx"
+#include "tensorutilities.hxx"
+
+namespace vigra {
+    
+
+/********************************************************/
+/*                                                      */
+/*           Coherence enhancing shock filter           */
+/*                                                      */
+/********************************************************/
+
+/**  
+    This function calculates of the coherence enhancing shock filter proposed by 
+    J. Weickert (2002): Coherence-Enhancing Show Filters. 
+    It uses the structure tensor information of an image and an iterative discrete upwinding scheme
+    instead of pure dilation and erosion to perform the necessary morphological operations
+    on the image. 
+*/
+//@{
+
+/** \brief This function calculates discrete upwinding scheme proposed by J. Weickert (2002) in Coherence-Enhancing Show Filters.
+
+    An image is upwinded positively (dilation), if the given second src is positive.
+    Otherwise it is upwinds negatively (eroded). The effect can be steered by an upwinding
+    factor.
+    
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2
+                  class T3, class S3>
+        void
+        upwindImage(MultiArrayView<2, T1, S1> const & src,
+                    MultiArrayView<2, T2, S2> const & src2,
+                    MultiArrayView<2, T3, S3> dest,
+                    float upwind_factor_h);
+
+    }
+    \endcode
+
+    \deprecatedAPI{upwindImage}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator,  class SrcAccessor, 
+                  class Src2Iterator, class Src2Accessor,
+                  class DestIterator, class DestAccessor>
+        void upwindImage(SrcIterator s_ul, SrcIterator s_lr, SrcAccessor s_acc,
+                         Src2Iterator s2_ul, Src2Accessor s2_acc, 
+                         DestIterator d_ul, DestAccessor d_acc,
+                         float upwind_factor_h)
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator,  class SrcAccessor, 
+                  class Src2Iterator, class Src2Accessor,
+                  class DestIterator, class DestAccessor>
+        void
+        upwindImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                    pair<Src2Iterator, Src2Accessor> src2,
+                    pair<DestIterator, DestAccessor> dest,
+                    float upwind_factor_h);
+    }
+    \endcode
+    \deprecatedEnd
+*/
+
+
+doxygen_overloaded_function(template <...> void upwindImage)
+
+template <class SrcIterator,  class SrcAccessor, 
+          class Src2Iterator, class Src2Accessor,
+          class DestIterator, class DestAccessor>
+void upwindImage(SrcIterator s_ul, SrcIterator s_lr, SrcAccessor s_acc,
+                 Src2Iterator s2_ul, Src2Accessor s2_acc, 
+                 DestIterator d_ul, DestAccessor d_acc,
+                 float upwind_factor_h)
+{
+    using namespace std;
+    
+    typedef typename SrcIterator::difference_type  DiffType;
+    
+    DiffType shape = s_lr - s_ul;
+    
+    typedef typename SrcAccessor::value_type  SrcType;
+    typedef typename DestAccessor::value_type ResultType;
+    
+    SrcType upper, lower, left, right, center;
+    ResultType fx, fy;  
+    
+    
+    for(int y=0; y<shape[1]; ++y)
+    {
+        for(int x=0; x<shape[0]; ++x)
+        {
+            upper  = s_acc(s_ul + Diff2D(x, max(0, y-1)));
+            lower  = s_acc(s_ul + Diff2D(x, min(shape[1]-1, y+1)));
+            left   = s_acc(s_ul + Diff2D(max(0, x-1), y));
+            right  = s_acc(s_ul + Diff2D(min(shape[0]-1, x+1), y));
+            center = s_acc(s_ul + Diff2D(x, y));
+            
+            if(s2_acc(s2_ul+Diff2D(x,y))<0)
+            {
+                fx = max(max(right - center, left  - center), 0.0f);
+                fy = max(max(lower - center, upper - center), 0.0f);
+                d_acc.set (center + upwind_factor_h*sqrt( fx*fx + fy*fy), d_ul+Diff2D(x,y));
+            }
+            else
+            {
+                fx = max(max(center - right, center - left), 0.0f);
+                fy = max(max(center - lower, center - upper), 0.0f);
+                d_acc.set (center - upwind_factor_h*sqrt( fx*fx + fy*fy), d_ul+Diff2D(x,y));
+            }               
+        }
+    }
+}
+
+template <class SrcIterator,  class SrcAccessor, 
+          class Src2Iterator, class Src2Accessor, 
+          class DestIterator, class DestAccessor>
+inline void upwindImage(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+                        pair<Src2Iterator, Src2Accessor> s2, 
+                        pair<DestIterator, DestAccessor> d,
+                        float upwind_factor_h)
+{
+    upwindImage(s.first, s.second, s.third, s2.first, s2.second, d.first, d.second, upwind_factor_h);
+}
+
+template <class T1, class S1, 
+          class T2, class S2,
+          class T3, class S3>
+inline void upwindImage(MultiArrayView<2, T1, S1> const & src,
+                        MultiArrayView<2, T2, S2> const & src2,
+                        MultiArrayView<2, T3, S3> dest,
+                        float upwind_factor_h)
+{
+    vigra_precondition(src.shape() == src2.shape() && src.shape() == dest.shape(),
+                        "vigra::upwindImage(): shape mismatch between input and output.");
+    upwindImage(srcImageRange(src),
+                srcImage(src2),
+                destImage(dest), 
+                upwind_factor_h);
+}
+
+
+/** \brief This function calculates of the coherence enhancing shock filter proposed by J. Weickert (2002) in Coherence-Enhancing Show Filters.
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2>
+        void
+        shockFilter(MultiArrayView<2, T1, S1> const & src,
+                    MultiArrayView<2, T2, S2> dest,
+                    float sigma, float rho, float upwind_factor_h, 
+                    unsigned int iterations);
+
+    }
+    \endcode
+
+    \deprecatedAPI{shockFilter}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void shockFilter(SrcIterator supperleft,
+                         SrcIterator slowerright, SrcAccessor sa,
+                         DestIterator dupperleft, DestAccessor da,
+                         float sigma, float rho, float upwind_factor_h, 
+                         unsigned int iterations);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        shockFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                    pair<DestIterator, DestAccessor> dest,
+                    float sigma, float rho, float upwind_factor_h, 
+                    unsigned int iterations);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/shockilter.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> src(w,h), dest(w,h);
+    ...
+    
+ 
+    
+    // apply a shock-filter:
+    shockFilter(src, dest, 1.0, 5.0, 0.3, 5);
+    \endcode
+
+    <b> Preconditions:</b>
+
+    The image must be larger than the window size of the filter.
+*/
+
+doxygen_overloaded_function(template <...> void upwindImage)
+
+template <class SrcIterator,  class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+void shockFilter(SrcIterator s_ul, SrcIterator s_lr, SrcAccessor s_acc,
+                 DestIterator d_ul, DestAccessor d_acc,
+                 float sigma, float rho, float upwind_factor_h, 
+                 unsigned int iterations)
+{
+    
+    typedef typename SrcIterator::difference_type  DiffType;
+    DiffType shape = s_lr - s_ul;
+        
+    unsigned int    w = shape[0],
+                    h = shape[1];
+    
+    FVector3Image tensor(w,h);
+    FVector3Image eigen(w,h);
+    FImage hxx(w,h), hxy(w,h), hyy(w,h), temp(w,h) ,result(w,h);
+    
+    float c, s, v_xx, v_xy, v_yy;
+    
+    copyImage(srcIterRange(s_ul, s_lr, s_acc), destImage(result));
+                     
+    for(unsigned int i = 0; i<iterations; ++i)
+    {   
+        
+        structureTensor(srcImageRange(result), destImage(tensor), sigma, rho);
+        tensorEigenRepresentation(srcImageRange(tensor), destImage(eigen));
+        hessianMatrixOfGaussian(srcImageRange(result),
+                                destImage(hxx), destImage(hxy), destImage(hyy), sigma);
+        
+        for(int y=0; y<shape[1]; ++y)
+        {
+            for(int x=0; x<shape[0]; ++x)
+            {
+                c = cos(eigen(x,y)[2]);
+                s = sin(eigen(x,y)[2]);
+                v_xx = hxx(x,y);
+                v_xy = hxy(x,y);
+                v_yy = hyy(x,y);
+                //store signum image in hxx (safe, because no other will ever access hxx(x,y)
+                hxx(x,y) = c*c*v_xx + 2*c*s*v_xy + s*s*v_yy;
+            }
+        }
+        upwindImage(srcImageRange(result),srcImage(hxx), destImage(temp), upwind_factor_h);
+        result = temp;
+
+    }
+    copyImage(srcImageRange(result), destIter(d_ul, d_acc));
+}
+
+template <class SrcIterator,  class SrcAccessor,
+          class DestIterator, class DestAccessor>
+inline void shockFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+                                        pair<DestIterator, DestAccessor> d,
+                                        float sigma, float rho, float upwind_factor_h, 
+                                        unsigned int iterations)
+{
+    shockFilter(s.first, s.second, s.third, 
+                d.first, d.second, 
+                sigma, rho, upwind_factor_h, 
+                iterations);
+}       
+
+template <class T1, class S1, 
+          class T2, class S2>
+inline void shockFilter(MultiArrayView<2, T1, S1> const & src,
+                        MultiArrayView<2, T2, S2> dest,
+                        float sigma, float rho, float upwind_factor_h, 
+                        unsigned int iterations)
+{
+    vigra_precondition(src.shape() == dest.shape(),
+                        "vigra::shockFilter(): shape mismatch between input and output.");
+    shockFilter(srcImageRange(src),
+                destImage(dest), 
+                sigma, rho, upwind_factor_h, 
+                iterations);
+}
+
+} //end of namespace vigra
+
+#endif //VIGRA_SHOCKFILTER_HXX
diff --git a/include/vigra/singular_value_decomposition.hxx b/include/vigra/singular_value_decomposition.hxx
index 86ddff3..10b396a 100644
--- a/include/vigra/singular_value_decomposition.hxx
+++ b/include/vigra/singular_value_decomposition.hxx
@@ -96,8 +96,8 @@ singularValueDecomposition(MultiArrayView<2, T, C1> const & A,
     S.init(0.0);
     V.init(0.0);
 
-    ArrayVector<Real> e((unsigned int)n);
-    ArrayVector<Real> work((unsigned int)m);
+    ArrayVector<Real> e(static_cast<unsigned int>(n));
+    ArrayVector<Real> work(static_cast<unsigned int>(m));
     Matrix<Real> a(A);
     MultiArrayView<1, T, C3> s = S.bindOuter(0);
 
@@ -106,7 +106,7 @@ singularValueDecomposition(MultiArrayView<2, T, C1> const & A,
     // Reduce a to bidiagonal form, storing the diagonal elements
     // in s and the super-diagonal elements in e.
     MultiArrayIndex nct = std::min(m-1,n);
-    MultiArrayIndex nrt = std::max((MultiArrayIndex)0,n-2);
+    MultiArrayIndex nrt = std::max(static_cast<MultiArrayIndex>(0),n-2);
     for (k = 0; k < std::max(nct,nrt); ++k)
     {
         if (k < nct)
@@ -316,7 +316,7 @@ singularValueDecomposition(MultiArrayView<2, T, C1> const & A,
     Real eps = NumericTraits<Real>::epsilon()*2.0;
     while (p > 0)
     {
-        MultiArrayIndex k=0;
+        k=0;
         int kase=0;
 
         // Here is where a test for too many iterations would go.
@@ -546,7 +546,7 @@ singularValueDecomposition(MultiArrayView<2, T, C1> const & A,
     }
     Real tol = std::max(m,n)*s(0)*eps;
     unsigned int rank = 0;
-    for (MultiArrayIndex i = 0; i < n; ++i)
+    for (i = 0; i < n; ++i)
     {
         if (s(i) > tol)
         {
diff --git a/include/vigra/skeleton.hxx b/include/vigra/skeleton.hxx
new file mode 100644
index 0000000..78e0a96
--- /dev/null
+++ b/include/vigra/skeleton.hxx
@@ -0,0 +1,974 @@
+/************************************************************************/
+/*                                                                      */
+/*    Copyright 2013-2014 by Ullrich Koethe                             */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_SKELETON_HXX
+#define VIGRA_SKELETON_HXX
+
+#include <vector>
+#include <set>
+#include <map>
+#include "vector_distance.hxx"
+#include "iteratorfacade.hxx"
+#include "pixelneighborhood.hxx"
+#include "graph_algorithms.hxx"
+
+namespace vigra
+{
+
+namespace detail {
+
+template <class Node>
+struct SkeletonNode
+{
+    Node parent, principal_child;
+    double length, salience;
+    MultiArrayIndex partial_area;
+    bool is_loop;
+    
+    SkeletonNode()
+    : parent(lemon::INVALID)
+    , principal_child(lemon::INVALID)
+    , length(0.0)
+    , salience(1.0)
+    , partial_area(0)
+    , is_loop(false)
+    {}
+    
+    SkeletonNode(Node const & s)
+    : parent(s)
+    , principal_child(lemon::INVALID)
+    , length(0.0)
+    , salience(1.0)
+    , partial_area(0)
+    , is_loop(false)
+    {}
+};
+
+template <class Node>
+struct SkeletonRegion
+{
+    typedef SkeletonNode<Node>                 SNode;
+    typedef std::map<Node, SNode>              Skeleton;
+    
+    Node anchor, lower, upper;
+    Skeleton skeleton;
+    
+    SkeletonRegion()
+    : anchor(lemon::INVALID)
+    , lower(NumericTraits<MultiArrayIndex>::max())
+    , upper(NumericTraits<MultiArrayIndex>::min())
+    {}
+    
+    void addNode(Node const & n)
+    {
+        skeleton[n] = SNode(n);
+        anchor = n;
+        lower = min(lower, n);
+        upper = max(upper, n);
+    }
+};
+
+template <class Graph, class Node, class NodeMap>
+inline unsigned int 
+neighborhoodConfiguration(Graph const & g, Node const & n, NodeMap const & labels)
+{
+    typedef typename Graph::OutArcIt      ArcIt;
+    typedef typename NodeMap::value_type  LabelType;
+    
+    LabelType label = labels[n];
+    unsigned int v = 0;
+    for(ArcIt arc(g, n); arc != lemon::INVALID; ++arc)
+    {
+        v = (v << 1) | (labels[g.target(*arc)] == label ? 1 : 0);
+    }
+    return v;
+}
+
+template <class Node, class Cost>
+struct SkeletonSimplePoint
+{
+    Node point;
+    Cost cost;
+
+    SkeletonSimplePoint(Node const & p, Cost c)
+    : point(p), cost(c)
+    {}
+
+    bool operator<(SkeletonSimplePoint const & o) const
+    {
+        return cost < o.cost;
+    }
+
+    bool operator>(SkeletonSimplePoint const & o) const
+    {
+        return cost > o.cost;
+    }
+};
+
+template <class CostMap, class LabelMap>
+void
+skeletonThinning(CostMap const & cost, LabelMap & labels,
+                 bool preserve_endpoints=true)
+{
+    typedef GridGraph<CostMap::actual_dimension> Graph;
+    typedef typename Graph::Node           Node;
+    typedef typename Graph::NodeIt         NodeIt;
+    typedef typename Graph::OutArcIt       ArcIt;
+
+    Graph g(labels.shape(), IndirectNeighborhood);
+    typedef SkeletonSimplePoint<Node, double> SP;
+    // use std::greater because we need the smallest distances at the top of the queue
+    // (std::priority_queue is a max queue by default)
+    std::priority_queue<SP, std::vector<SP>, std::greater<SP> >  pqueue;
+    
+    bool isSimpleStrong[256] = {
+        0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 
+        0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 
+        1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 
+        1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 
+        1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+        1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 
+        1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 
+        1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 
+        1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 
+    };
+    
+    bool isSimplePreserveEndPoints[256] = {
+        0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+        1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+        0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 
+        1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    
+    bool * isSimplePoint = preserve_endpoints
+                               ? isSimplePreserveEndPoints
+                               : isSimpleStrong;
+    
+    int max_degree = g.maxDegree();
+    double epsilon = 0.5/labels.size(), offset = 0;
+    for (NodeIt node(g); node != lemon::INVALID; ++node)
+    {
+        Node p = *node;
+        if(g.out_degree(p) == max_degree &&
+           labels[p] > 0 &&
+           isSimplePoint[neighborhoodConfiguration(g, p, labels)])
+        {
+            // add an offset to break ties in a FIFI manner
+            pqueue.push(SP(p, cost[p]+offset));
+            offset += epsilon;
+        }
+    }
+
+    while(pqueue.size())
+    {
+        Node p = pqueue.top().point;
+        pqueue.pop();
+
+        if(labels[p] == 0 ||
+           !isSimplePoint[neighborhoodConfiguration(g, p, labels)])
+        {
+            continue; // point already deleted or no longer simple
+        }
+        
+        labels[p] = 0; // delete simple point
+
+        for (ArcIt arc(g, p); arc != lemon::INVALID; ++arc)
+        {
+            Node q = g.target(*arc);
+            if(g.out_degree(q) == max_degree &&
+               labels[q] > 0 &&
+               isSimplePoint[neighborhoodConfiguration(g, q, labels)])
+            {
+                pqueue.push(SP(q, cost[q]+offset));
+                offset += epsilon;
+            }
+        }
+    }
+}
+
+template <class Label, class Labels>
+struct CheckForHole
+{
+    Label label;
+    Labels const & labels;
+    
+    CheckForHole(Label l, Labels const & ls)
+    : label(l)
+    , labels(ls)
+    {}
+    
+    template <class Node>
+    bool operator()(Node const & n) const
+    {
+        return labels[n] == label;
+    }
+};
+
+} // namespace detail 
+
+/** \addtogroup MultiArrayDistanceTransform
+*/
+//@{
+
+    /** \brief Option object for \ref skeletonizeImage()
+    */
+struct SkeletonOptions
+{
+    enum SkeletonMode {
+         DontPrune = 0,
+         Prune = 1,
+         Relative = 2,
+         PreserveTopology = 4,
+         Length = 8,
+         Salience = 16,
+         PruneCenterLine = 32,
+         PruneLength = Length + Prune,
+         PruneLengthRelative = PruneLength + Relative,
+         PruneSalience = Salience + Prune,
+         PruneSalienceRelative = PruneSalience + Relative,
+         PruneTopology = PreserveTopology + Prune
+    };
+    
+    SkeletonMode mode;
+    double pruning_threshold;
+    
+        /** \brief construct with default settings
+        
+            (default: <tt>pruneSalienceRelative(0.2, true)</tt>)
+        */
+    SkeletonOptions()
+    : mode(SkeletonMode(PruneSalienceRelative | PreserveTopology))
+    , pruning_threshold(0.2)
+    {}
+    
+        /** \brief return the un-pruned skeletong
+        */
+    SkeletonOptions & dontPrune()
+    {
+        mode = DontPrune;
+        return *this;
+    }
+    
+        /** \brief return only the region's center line (i.e. skeleton graph diameter)
+        */
+    SkeletonOptions & pruneCenterLine()
+    {
+        mode = PruneCenterLine;
+        return *this;
+    }
+    
+        /** \brief Don't prune and return the length of each skeleton segment.
+        */
+    SkeletonOptions & returnLength()
+    {
+        mode = Length;
+        return *this;
+    }
+    
+        /** \brief prune skeleton segments whose length is below the given threshold
+        
+            If \a preserve_topology is <tt>true</tt> (default), skeleton loops
+            (i.e. parts enclosing a hole in the region) are preserved even if their 
+            length is below the threshold. Otherwise, loops are pruned as well.
+        */
+    SkeletonOptions & pruneLength(double threshold, bool preserve_topology=true)
+    {
+        mode = PruneLength;
+        if(preserve_topology)
+            mode = SkeletonMode(mode | PreserveTopology);
+        pruning_threshold = threshold;
+        return *this;
+    }
+    
+        /** \brief prune skeleton segments whose relative length is below the given threshold
+        
+            This works like <tt>pruneLength()</tt>, but the threshold is specified as a 
+            fraction of the maximum segment length in the skeleton.
+        */
+    SkeletonOptions & pruneLengthRelative(double threshold, bool preserve_topology=true)
+    {
+        mode = PruneLengthRelative;
+        if(preserve_topology)
+            mode = SkeletonMode(mode | PreserveTopology);
+        pruning_threshold = threshold;
+        return *this;
+    }
+    
+        /** \brief Don't prune and return the salience of each skeleton segment.
+        */
+    SkeletonOptions & returnSalience()
+    {
+        mode = Salience;
+        return *this;
+    }
+    
+        /** \brief prune skeleton segments whose salience is below the given threshold
+        
+            If \a preserve_topology is <tt>true</tt> (default), skeleton loops
+            (i.e. parts enclosing a hole in the region) are preserved even if their 
+            salience is below the threshold. Otherwise, loops are pruned as well.
+        */
+    SkeletonOptions & pruneSalience(double threshold, bool preserve_topology=true)
+    {
+        mode = PruneSalience;
+        if(preserve_topology)
+            mode = SkeletonMode(mode | PreserveTopology);
+        pruning_threshold = threshold;
+        return *this;
+    }
+    
+        /** \brief prune skeleton segments whose relative salience is below the given threshold
+        
+            This works like <tt>pruneSalience()</tt>, but the threshold is specified as a 
+            fraction of the maximum segment salience in the skeleton.
+        */
+    SkeletonOptions & pruneSalienceRelative(double threshold, bool preserve_topology=true)
+    {
+        mode = PruneSalienceRelative;
+        if(preserve_topology)
+            mode = SkeletonMode(mode | PreserveTopology);
+        pruning_threshold = threshold;
+        return *this;
+    }
+    
+        /** \brief prune such that only the topology is preserved
+        
+            If \a preserve_center is <tt>true</tt> (default), the eccentricity center
+            of the skeleton will not be pruned, even if it is not essential for the topology.
+            Otherwise, the center is only preserved if it is essential. The center is always 
+            preserved (and is the only remaining point) when the region has no holes.
+        */
+    SkeletonOptions & pruneTopology(bool preserve_center=true)
+    {
+        if(preserve_center)
+            mode = PruneTopology;
+        else
+            mode = Prune;
+        return *this;
+    }
+};
+
+template <class T1, class S1,
+          class T2, class S2,
+          class ArrayLike>
+void
+skeletonizeImageImpl(MultiArrayView<2, T1, S1> const & labels,
+                MultiArrayView<2, T2, S2> dest,
+                ArrayLike * features,
+                SkeletonOptions const & options)
+{
+    static const unsigned int N = 2;
+    typedef typename MultiArrayShape<N>::type  Shape;
+    typedef GridGraph<N>                       Graph;
+    typedef typename Graph::Node               Node;
+    typedef typename Graph::NodeIt             NodeIt;
+    typedef typename Graph::EdgeIt             EdgeIt;
+    typedef typename Graph::OutArcIt           ArcIt;
+    typedef typename Graph::OutBackArcIt       BackArcIt;
+    typedef double                             WeightType;
+    typedef detail::SkeletonNode<Node>         SNode;
+    typedef std::map<Node, SNode>              Skeleton;
+    
+    vigra_precondition(labels.shape() == dest.shape(),
+        "skeleton(): shape mismatch between input and output.");
+        
+    MultiArray<N, MultiArrayIndex> squared_distance;
+    dest = 0;
+    T1 maxLabel = 0;
+    // find skeleton points
+    {
+        using namespace multi_math;
+        
+        MultiArray<N, Shape> vectors(labels.shape());
+        boundaryVectorDistance(labels, vectors, false, OuterBoundary);
+        squared_distance = squaredNorm(vectors);
+    
+        ArrayVector<Node> ends_to_be_checked;
+        Graph g(labels.shape());
+        for (EdgeIt edge(g); edge != lemon::INVALID; ++edge)
+        {
+            Node p1 = g.u(*edge),
+                 p2 = g.v(*edge);
+            T1 l1 = labels[p1], 
+               l2 = labels[p2];
+            maxLabel = max(maxLabel, max(l1, l2));
+            if(l1 == l2)
+            {
+                if(l1 <= 0)  // only consider positive labels
+                    continue;
+                
+                const Node v1 = vectors[p1],
+                           v2 = vectors[p2],
+                           dp = p2 - p1,
+                           dv = v2 - v1 + dp;
+                if(max(abs(dv)) <= 1)  // points whose support points coincide or are adjacent
+                    continue;          // don't belong to the skeleton
+                
+                // among p1 and p2, the point which is closer to the bisector 
+                // of the support points p1 + v1 and p2 + v2 belongs to the skeleton
+                const MultiArrayIndex d1 = dot(dv, dp),
+                                      d2 = dot(dv, v1+v2);
+                if(d1*d2 <= 0)
+                {
+                    dest[p1] = l1;
+                    if(squared_distance[p1] == 4)
+                        ends_to_be_checked.push_back(p1);
+                }
+                else
+                {
+                    dest[p2] = l2;
+                    if(squared_distance[p2] == 4)
+                        ends_to_be_checked.push_back(p2);
+                }
+            }
+            else
+            {
+                if(l1 > 0 && max(abs(vectors[p1] + p1 - p2)) > 1)
+                    dest[p1] = l1;
+                if(l2 > 0 && max(abs(vectors[p2] + p2 - p1)) > 1)
+                    dest[p2] = l2;
+            }
+        }
+        
+        
+        // add a point when a skeleton line stops short of the shape boundary
+        // FIXME: can this be solved during the initial detection above?
+        Graph g8(labels.shape(), IndirectNeighborhood);
+        for (unsigned k=0; k<ends_to_be_checked.size(); ++k)
+        {
+            // The phenomenon only occurs at points whose distance from the background is 2.
+            // We've put these points into ends_to_be_checked. 
+            Node p1 = ends_to_be_checked[k];
+            T2 label = dest[p1];
+            int count = 0;
+            for (ArcIt arc(g8, p1); arc != lemon::INVALID; ++arc)
+            {
+                Node p2 = g8.target(*arc);
+                if(dest[p2] == label && squared_distance[p2] < 4)
+                    ++count;
+            }
+            if(count == 0) // point p1 has no neighbor at the boundary => activate one
+                dest[p1+vectors[p1]/2] = label;
+        }
+
+        // from here on, we only need the squared DT, not the vector DT
+    }
+    
+    // The true skeleton is defined by the interpixel edges between the
+    // Voronoi regions of the DT. Our skeleton detection algorithm affectively
+    // rounds the interpixel edges to the nearest pixel such that the result
+    // is mainly 8-connected and thin. However, thick skeleton pieces may still 
+    // arise when two interpixel contours are only one pixel apart, i.e. a
+    // Voronoi region is only one pixel wide. Since this happens rarely, we 
+    // can simply remove these cases by thinning.
+    detail::skeletonThinning(squared_distance, dest);
+    
+    if(options.mode == SkeletonOptions::PruneCenterLine)
+        dest = 0;
+        
+    // Reduce the full grid graph to a skeleton graph by inserting infinite
+    // edge weights between skeleton pixels and non-skeleton pixels.
+    if(features)
+        features->resize((size_t)maxLabel + 1);
+    ArrayVector<detail::SkeletonRegion<Node> > regions((size_t)maxLabel + 1);
+    Graph g(labels.shape(), IndirectNeighborhood);
+    WeightType maxWeight = g.edgeNum()*sqrt(N),
+               infiniteWeight = 0.5*NumericTraits<WeightType>::max();
+    typename Graph::template EdgeMap<WeightType> weights(g);
+    for (NodeIt node(g); node != lemon::INVALID; ++node)
+    {
+        Node p1 = *node;
+        T2 label = dest[p1];
+        if(label <= 0)
+            continue;
+            
+        // FIXME: consider using an AdjacencyListGraph from here on
+        regions[(size_t)label].addNode(p1);
+
+        for (ArcIt arc(g, p1); arc != lemon::INVALID; ++arc)
+        {
+            Node p2 = g.target(*arc);
+            if(dest[p2] == label)
+                weights[*arc] = norm(p1-p2);
+            else
+                weights[*arc] = infiniteWeight;
+        }
+    }
+    
+    ShortestPathDijkstra<Graph, WeightType> pathFinder(g);
+    // Handle the skeleton of each region individually.
+    for(std::size_t label=1; label < regions.size(); ++label)
+    {
+        Skeleton & skeleton = regions[label].skeleton;
+        if(skeleton.size() == 0) // label doesn't exist
+            continue;
+        
+        // Find a diameter (longest path) in the skeleton.
+        Node anchor = regions[label].anchor,
+             lower  = regions[label].lower,
+             upper  = regions[label].upper + Shape(1);
+             
+        pathFinder.run(lower, upper, weights, anchor, lemon::INVALID, maxWeight);
+        anchor = pathFinder.target();
+        pathFinder.reRun(weights, anchor, lemon::INVALID, maxWeight);
+        anchor = pathFinder.target();
+        
+        Polygon<Shape> center_line;
+        center_line.push_back_unsafe(anchor);
+        while(pathFinder.predecessors()[center_line.back()] != center_line.back())
+            center_line.push_back_unsafe(pathFinder.predecessors()[center_line.back()]);
+            
+        if(options.mode == SkeletonOptions::PruneCenterLine)
+        {
+            for(unsigned int k=0; k<center_line.size(); ++k)
+                dest[center_line[k]] = (T2)label;
+            continue; // to next label
+        }
+        
+        // Perform the eccentricity transform of the skeleton
+        Node center = center_line[roundi(center_line.arcLengthQuantile(0.5))];
+        pathFinder.reRun(weights, center, lemon::INVALID, maxWeight);
+        
+        bool compute_salience = (options.mode & SkeletonOptions::Salience) != 0;
+        ArrayVector<Node> raw_skeleton(pathFinder.discoveryOrder());
+        // from periphery to center: create skeleton tree and compute salience
+        for(int k=raw_skeleton.size()-1; k >= 0; --k)
+        {
+            Node p1 = raw_skeleton[k],
+                 p2 = pathFinder.predecessors()[p1];
+            SNode & n1 = skeleton[p1];
+            SNode & n2 = skeleton[p2];
+            n1.parent = p2;
+            
+
+            // remove non-skeleton edges (i.e. set weight = infiniteWeight)
+            for (BackArcIt arc(g, p1); arc != lemon::INVALID; ++arc)
+            {
+                Node p = g.target(*arc);
+                if(weights[*arc] == infiniteWeight)
+                    continue; // edge never was in the graph
+                if(p == p2)
+                    continue; // edge belongs to the skeleton
+                if(pathFinder.predecessors()[p] == p1)
+                    continue; // edge belongs to the skeleton
+                if(n1.principal_child == lemon::INVALID || 
+                   skeleton[p].principal_child == lemon::INVALID)
+                    continue; // edge may belong to a loop => test later
+                weights[*arc] = infiniteWeight;
+            }
+
+            // propagate length to parent if this is the longest subtree
+            WeightType l = n1.length + norm(p1-p2);
+            if(n2.length < l)
+            {
+                n2.length = l;
+                n2.principal_child = p1;
+            }
+            
+            if(compute_salience)
+            {
+                const double min_length = 4.0; // salience is meaningless for shorter segments due
+                                               // to quantization noise (staircasing) of the boundary
+                if(n1.length >= min_length)
+                {
+                    n1.salience = max(n1.salience, (n1.length + 0.5) / sqrt(squared_distance[p1]));
+                
+                    // propagate salience to parent if this is the most salient subtree
+                    if(n2.salience < n1.salience)
+                        n2.salience = n1.salience;
+                }
+            }
+            else if(options.mode == SkeletonOptions::DontPrune)
+                n1.salience = dest[p1];
+            else
+                n1.salience = n1.length;
+        }
+        
+        // from center to periphery: propagate salience and compute twice the partial area
+        for(int k=0; k < (int)raw_skeleton.size(); ++k)
+        {
+            Node p1 = raw_skeleton[k];
+            SNode & n1 = skeleton[p1];
+            Node p2 = n1.parent;
+            SNode & n2 = skeleton[p2];
+            
+            if(p1 == n2.principal_child)
+            {
+                n1.length = n2.length;
+                n1.salience = n2.salience;
+            }
+            else
+            {
+                n1.length += norm(p2-p1);
+            }
+            n1.partial_area = n2.partial_area + (p1[0]*p2[1] - p1[1]*p2[0]);
+        }
+
+        // always treat eccentricity center as a loop, so that it cannot be pruned 
+        // away unless (options.mode & PreserveTopology) is false.
+        skeleton[center].is_loop = true;
+        
+        // from periphery to center: * find and propagate loops
+        //                           * delete branches not reaching the boundary
+        detail::CheckForHole<std::size_t, MultiArrayView<2, T1, S1> > hasNoHole(label, labels);
+        int hole_count = 0;
+        double total_length = 0.0;
+        for(int k=raw_skeleton.size()-1; k >= 0; --k)
+        {
+            Node p1 = raw_skeleton[k];
+            SNode & n1 = skeleton[p1];
+
+            if(n1.principal_child == lemon::INVALID)
+            {
+                for (ArcIt arc(g, p1); arc != lemon::INVALID; ++arc)
+                {
+                    Node p2 = g.target(*arc);
+                    SNode * n2 = &skeleton[p2];
+                    
+                    if(n1.parent == p2)
+                        continue; // going back to the parent can't result in a loop
+                    if(weights[*arc] == infiniteWeight)
+                        continue; // p2 is not in the tree or the loop has already been handled
+                    // compute twice the area exclosed by the potential loop
+                    MultiArrayIndex area2 = abs(n1.partial_area - (p1[0]*p2[1] - p1[1]*p2[0]) - n2->partial_area);
+                    if(area2 <= 3) // area is too small to enclose a hole => loop is a discretization artifact
+                        continue;
+                    
+                    // use Dijkstra to find the loop
+                    WeightType edge_length = weights[*arc];
+                    weights[*arc] = infiniteWeight;
+                    pathFinder.reRun(weights, p1, p2);
+                    Polygon<Shape2> poly;
+                    {
+                        poly.push_back_unsafe(p1);
+                        poly.push_back_unsafe(p2);
+                        Node p = p2;
+                        do 
+                        {
+                            p = pathFinder.predecessors()[p];
+                            poly.push_back_unsafe(p);
+                        }
+                        while(p != pathFinder.predecessors()[p]);
+                    }
+                    // check if the loop contains a hole or is just a discretization artifact
+                    if(!inspectPolygon(poly, hasNoHole))
+                    {
+                        // it's a genuine loop => mark it and propagate salience
+                        ++hole_count;
+                        total_length += n1.length + n2->length;
+                        double max_salience = max(n1.salience, n2->salience);
+                        for(int p=1; p<poly.size(); ++p)
+                        {
+                            SNode & n = skeleton[poly[p]];
+                            n.is_loop = true;
+                            n.salience = max(n.salience, max_salience);
+                        }
+                    }
+                }
+                // delete skeleton branches that are not loops and don't reach the shape border
+                // (these branches are discretization artifacts)
+                if(!n1.is_loop && squared_distance[p1] >= 4)
+                {
+                    SNode * n = &n1;
+                    while(true)
+                    {
+                        n->salience = 0;
+                        // remove all of p1's edges
+                        for(ArcIt arc(g, p1); arc != lemon::INVALID; ++arc)
+                        {
+                            weights[*arc] = infiniteWeight;
+                        }
+                        if(skeleton[n->parent].principal_child != p1)
+                            break;
+                        p1 = n->parent;
+                        n = &skeleton[p1];
+                    }
+                }
+            }
+            
+            if(n1.is_loop)
+                skeleton[n1.parent].is_loop = true;
+        }
+        
+        bool dont_prune = (options.mode & SkeletonOptions::Prune) == 0;
+        bool preserve_topology = (options.mode & SkeletonOptions::PreserveTopology) != 0 ||
+                                 options.mode == SkeletonOptions::Prune;
+        bool relative_pruning = (options.mode & SkeletonOptions::Relative) != 0;
+        WeightType threshold = (options.mode == SkeletonOptions::PruneTopology ||
+                                options.mode == SkeletonOptions::Prune)
+                                   ? infiniteWeight
+                                   : relative_pruning
+                                       ? options.pruning_threshold*skeleton[center].salience
+                                       : options.pruning_threshold;
+        // from center to periphery: write result
+        int branch_count = 0;
+        double average_length = 0;
+        for(int k=0; k < (int)raw_skeleton.size(); ++k)
+        {
+            Node p1 = raw_skeleton[k];
+            SNode & n1 = skeleton[p1];
+            Node p2 = n1.parent;
+            SNode & n2 = skeleton[p2];
+            if(n1.principal_child == lemon::INVALID && 
+               n1.salience >= threshold && 
+               !n1.is_loop)
+            {
+                ++branch_count;
+                average_length += n1.length;
+                total_length += n1.length;
+            }
+            if(dont_prune)
+                dest[p1] = n1.salience;
+            else if(preserve_topology)
+            {
+                if(!n1.is_loop && n1.salience < threshold)
+                    dest[p1] = 0;
+            }
+            else if(p1 != center && n1.salience < threshold)
+                dest[p1] = 0;
+        }
+        if(branch_count > 0)
+            average_length /= branch_count;
+        
+        if(features)
+        {
+            (*features)[label].diameter = center_line.length();
+            (*features)[label].total_length = total_length;
+            (*features)[label].average_length = average_length;
+            (*features)[label].branch_count = branch_count;
+            (*features)[label].hole_count = hole_count;
+            (*features)[label].center = center;
+            (*features)[label].terminal1 = center_line.front();
+            (*features)[label].terminal2 = center_line.back();
+            (*features)[label].euclidean_diameter = norm(center_line.back()-center_line.front());
+        }
+    }
+        
+    if(options.mode == SkeletonOptions::Prune)
+        detail::skeletonThinning(squared_distance, dest, false);
+}
+
+class SkeletonFeatures
+{
+  public:
+    double diameter, total_length, average_length, euclidean_diameter;
+    UInt32 branch_count, hole_count;
+    Shape2 center, terminal1, terminal2;
+    
+    SkeletonFeatures()
+    : diameter(0)
+    , total_length(0)
+    , average_length(0)
+    , euclidean_diameter(0)
+    , branch_count(0)
+    , hole_count(0)
+    {}
+};
+
+/********************************************************/
+/*                                                      */
+/*                     skeletonizeImage                      */
+/*                                                      */
+/********************************************************/
+
+    /*
+    To compute the skeleton reliably in higher dimensions, we have to work on 
+    a topological grid. The tricks to work with rounded skeletons on the 
+    pixel grid probably don't generalize from 2D to 3D and higher. Specifically:
+    
+    * Compute Voronoi regions of the vector distance transformation according to
+      identical support point to make sure that disconnected Voronoi regions
+      still get only a single label.
+    * Merge Voronoi regions whose support points are adjacent.
+    * Mark skeleton candidates on the interpixel grid after the basic merge.
+    * Detect skeleton segments simply by connected components labeling in the interpixel grid.
+    * Skeleton segments form hyperplanes => use this property to compute segment 
+      attributes.
+    * Detect holes (and therefore, skeleton segments that are critical for topology)
+      by computing the depth of each region/surface in the homotopy tree.
+    * Add a pruning mode where holes are only preserved if their size exceeds a threshold. 
+    
+    To implement this cleanly, we first need a good implementation of the topological grid graph.
+    */
+// template <unsigned int N, class T1, class S1,
+                          // class T2, class S2>
+// void
+// skeletonizeImage(MultiArrayView<N, T1, S1> const & labels,
+            // MultiArrayView<N, T2, S2> dest,
+            // SkeletonOptions const & options = SkeletonOptions())
+// {
+
+    /** \brief Skeletonization of all regions in a labeled 2D image.
+
+        <b> Declarations:</b>
+
+        \code
+        namespace vigra {
+            template <class T1, class S1,
+                      class T2, class S2>
+            void
+            skeletonizeImage(MultiArrayView<2, T1, S1> const & labels,
+                             MultiArrayView<2, T2, S2> dest,
+                             SkeletonOptions const & options = SkeletonOptions());
+        }
+        \endcode
+
+        This function computes the skeleton for each region in the 2D label image \a labels 
+        and paints the results into the result image \a dest. Input label 
+        <tt>0</tt> is interpreted as background and always ignored. Skeletons will be 
+        marked with the same label as the corresponding region (unless options 
+        <tt>returnLength()</tt> or <tt>returnSalience()</tt> are selected, see below). 
+        Non-skeleton pixels will receive label <tt>0</tt>.
+
+        For each region, the algorithm proceeds in the following steps:
+        <ol>
+        <li>Compute the \ref boundaryVectorDistance() relative to the \ref OuterBoundary of the region.</li>
+        <li>Mark the raw skeleton: find 4-adjacent pixel pairs whose nearest boundary points are neither equal 
+            nor adjacent and mark one pixel of the pair as a skeleton candidate. The resulting raw skeleton
+            is 8-connected and thin. Skip the remaining steps when option <tt>dontPrune()</tt> is selected.</li>
+        <li>Compute the eccentricity transform of the raw skeleton and turn the skeleton into a tree 
+            whose root is the eccentricity center. When option <tt>pruneCenterLine()</tt> is selected,
+            delete all skeleton points that do not belong to the two longest tree branches and 
+            skip the remaining steps.</li>
+        <li>For each pixel on the skeleton, compute its <tt>length</tt> attribute as the depth of the
+            pixel's longest subtree. Compute its <tt>salience</tt> attribute as the ratio between 
+            <tt>length</tt> and <tt>distance</tt>, where <tt>distance</tt> is the pixel's distance to 
+            the nearest boundary point according to the distance transform. It holds that <tt>length >= 0.5</tt>
+            and <tt>salience >= 1.0</tt>.</li>
+        <li>Detect skeleton branching points and define <i>skeleton segments</i> as maximal connected pieces 
+            without branching points.</li>
+        <li>Compute <tt>length</tt> and <tt>salience</tt> of each segment as the maximum of these
+            attributes among the pixels in the segment. When options <tt>returnLength()</tt> or 
+            <tt>returnSalience()</tt> are selected, skip the remaining steps and return the 
+            requested segment attribute in <tt>dest</tt>. In this case, <tt>dest</tt>'s 
+            <tt>value_type</tt> should be a floating point type to exactly accomodate the 
+            attribute values.</li>
+        <li>Detect minimal cycles in the raw skeleton that enclose holes in the region (if any) and mark
+            the corresponding pixels as critical for skeleton topology.</li>
+        <li>Prune skeleton segments according to the selected pruning strategy and return the result. 
+            The following pruning strategies are available:
+            <ul>
+            <li><tt>pruneLength(threshold, preserve_topology)</tt>: Retain only segments whose length attribute
+                            exceeds the given <tt>threshold</tt>. When <tt>preserve_topology</tt> is true
+                            (the defult), cycles around holes are preserved regardless of their length.
+                            Otherwise, they are pruned as well.</li>
+            <li><tt>pruneLengthRelative(threshold, preserve_topology)</tt>: Like <tt>pruneLength()</tt>,
+                            but the threshold is specified as a fraction of the maximum segment length in  
+                            the present region.</li>
+            <li><tt>pruneSalience(threshold, preserve_topology)</tt>: Retain only segments whose salience attribute
+                            exceeds the given <tt>threshold</tt>. When <tt>preserve_topology</tt> is true
+                            (the defult), cycles around holes are preserved regardless of their salience.
+                            Otherwise, they are pruned as well.</li>
+            <li><tt>pruneSalienceRelative(threshold, preserve_topology)</tt>: Like <tt>pruneSalience()</tt>,
+                            but the threshold is specified as a fraction of the maximum segment salience in 
+                            the present region.</li>
+            <li><tt>pruneTopology(preserve_center)</tt>: Retain only segments that are essential for the region's
+                            topology. If <tt>preserve_center</tt> is true (the default), the eccentricity
+                            center is also preserved, even if it is not essential. Otherwise, it might be 
+                            removed. The eccentricity center is always the only remaining point when
+                            the region has no holes.</li>
+            </ul></li>
+        </ol>
+        
+        The skeleton has the following properties:
+        <ul>
+        <li>It is 8-connected and thin (except when two independent branches happen to run alongside 
+            before they divert). Skeleton points are defined by rounding the exact Euclidean skeleton
+            locations to the nearest pixel.</li>
+        <li>Skeleton branches terminate either at the region boundary or at a cycle. There are no branch 
+            end points in the region interior.</li>
+        <li>The salience threshold acts as a scale parameter: Large thresholds only retain skeleton 
+            branches characterizing the general region shape. When the threshold gets smaller, ever
+            more detailed boundary bulges will be represented by a skeleton branch.</li>
+        </ul>
+        
+        Remark: If you have an application where a skeleton graph would be more useful
+        than a skeleton image, function <tt>skeletonizeImage()</tt> can be changed/extended easily.
+
+        <b> Usage:</b>
+
+        <b>\#include</b> \<vigra/skeleton.hxx\><br/>
+        Namespace: vigra
+
+        \code
+        Shape2 shape(width, height);
+        MultiArray<2, UInt32> source(shape);
+        MultiArray<2, UInt32> dest(shape);
+        ...
+
+        // Skeletonize and keep only those segments that are at least 10% of the maximum
+        // length (the maximum length is half the skeleton diameter).
+        skeletonizeImage(source, dest,
+                    SkeletonOptions().pruneLengthRelative(0.1));
+        \endcode
+
+        \see vigra::boundaryVectorDistance()
+    */
+doxygen_overloaded_function(template <...> void skeletonizeImage)
+
+template <class T1, class S1,
+          class T2, class S2>
+void
+skeletonizeImage(MultiArrayView<2, T1, S1> const & labels,
+            MultiArrayView<2, T2, S2> dest,
+            SkeletonOptions const & options = SkeletonOptions())
+{
+    skeletonizeImageImpl(labels, dest, (ArrayVector<SkeletonFeatures>*)0, options);
+}
+
+template <class T, class S>
+void
+extractSkeletonFeatures(MultiArrayView<2, T, S> const & labels, 
+                        ArrayVector<SkeletonFeatures> & features,
+                        SkeletonOptions const & options = SkeletonOptions())
+{
+    MultiArray<2, float> skeleton(labels.shape());
+    skeletonizeImageImpl(labels, skeleton, &features, options);
+}
+
+//@}
+
+} //-- namespace vigra
+
+#endif        //-- VIGRA_SKELETON_HXX
diff --git a/include/vigra/slanted_edge_mtf.hxx b/include/vigra/slanted_edge_mtf.hxx
index 2195e18..ca1488b 100644
--- a/include/vigra/slanted_edge_mtf.hxx
+++ b/include/vigra/slanted_edge_mtf.hxx
@@ -58,8 +58,8 @@ namespace vigra {
 /** \addtogroup SlantedEdgeMTF Camera MTF Estimation
     Determine the magnitude transfer function (MTF) of a camera using the slanted edge method.
 */
-//@{ 
-                                    
+//@{
+
 /********************************************************/
 /*                                                      */
 /*                  SlantedEdgeMTFOptions               */
@@ -70,22 +70,22 @@ namespace vigra {
 
     <tt>SlantedEdgeMTFOptions</tt>  is an argument objects that holds various optional
     parameters used by the \ref slantedEdgeMTF() functions. If a parameter is not explicitly
-    set, a suitable default will be used. Changing the defaults is only necessary if you can't 
+    set, a suitable default will be used. Changing the defaults is only necessary if you can't
     obtain good input data, but absolutely need an MTF estimate.
-    
+
     <b> Usage:</b>
-    
+
     <b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br>
     Namespace: vigra
-    
+
     \code
     MultiArray<2, float> src(w,h);
     std::vector<vigra::TinyVector<double, 2> > mtf;
-    
+
     ...
     slantedEdgeMTF(src, mtf,
                    SlantedEdgeMTFOptions().mtfSmoothingScale(1.0));
-    
+
     // print the frequency / attenuation pairs found
     for(int k=0; k<result.size(); ++k)
         std::cout << "frequency: " << mtf[k][0] << ", estimated attenuation: " << mtf[k][1] << std::endl;
@@ -105,7 +105,7 @@ class SlantedEdgeMTFOptions
     {}
 
         /** Minimum number of pixels the edge must cross.
-        
+
             The longer the edge the more accurate the resulting MTF estimate. If you don't have good
             data, but absolutely have to compute an MTF, you may force a lower value here.<br>
             Default: 20
@@ -117,8 +117,8 @@ class SlantedEdgeMTFOptions
     }
 
         /** Desired number of pixels perpendicular to the edge.
-        
-            The larger the regions to either side of the edge, 
+
+            The larger the regions to either side of the edge,
             the more accurate the resulting MTF estimate. If you don't have good
             data, but absolutely have to compute an MTF, you may force a lower value here.<br>
             Default: 10
@@ -130,8 +130,8 @@ class SlantedEdgeMTFOptions
     }
 
         /** Minimum acceptable number of pixels perpendicular to the edge.
-        
-            The larger the regions to either side of the edge, 
+
+            The larger the regions to either side of the edge,
             the more accurate the resulting MTF estimate. If you don't have good
             data, but absolutely have to compute an MTF, you may force a lower value here.<br>
             Default: 5
@@ -143,7 +143,7 @@ class SlantedEdgeMTFOptions
     }
 
         /** Amount of smoothing of the computed MTF.
-        
+
             If the data is noisy, so will be the MTF. Thus, some smoothing is useful.<br>
             Default: 2.0
         */
@@ -175,12 +175,12 @@ struct SortEdgelsByStrength
        of the image, and white is on the left.
     */
 template <class SrcIterator, class SrcAccessor, class DestImage>
-unsigned int
+ptrdiff_t
 prepareSlantedEdgeInput(SrcIterator sul, SrcIterator slr, SrcAccessor src, DestImage & res,
                         SlantedEdgeMTFOptions const & options)
 {
-    unsigned int w = slr.x - sul.x;
-    unsigned int h = slr.y - sul.y;
+    ptrdiff_t w = slr.x - sul.x;
+    ptrdiff_t h = slr.y - sul.y;
 
     // find rough estimate of the edge
     ArrayVector<Edgel> edgels;
@@ -188,9 +188,9 @@ prepareSlantedEdgeInput(SrcIterator sul, SrcIterator slr, SrcAccessor src, DestI
     std::sort(edgels.begin(), edgels.end(), SortEdgelsByStrength());
 
     double x = 0.0, y = 0.0, x2 = 0.0, y2 = 0.0, xy = 0.0;
-    unsigned int c = std::min(w, h);
+    ptrdiff_t c = std::min(w, h);
 
-    for(unsigned int k = 0; k < c; ++k)
+    for(ptrdiff_t k = 0; k < c; ++k)
     {
         x += edgels[k].x;
         y += edgels[k].y;
@@ -228,26 +228,26 @@ prepareSlantedEdgeInput(SrcIterator sul, SrcIterator slr, SrcAccessor src, DestI
           "slantedEdgeMTF(): Input edge is not slanted");
 
     // trim image so that the edge only intersects the top and bottom border
-    unsigned int minimumNumberOfLines = options.minimum_number_of_lines, //20,
+    ptrdiff_t minimumNumberOfLines = options.minimum_number_of_lines, //20,
                  edgeWidth = options.desired_edge_width, // 10
                  minimumEdgeWidth = options.minimum_edge_width; // 5
 
-    int y0 = 0, y1 = h;
+    ptrdiff_t y0 = 0, y1 = h;
     for(; edgeWidth >= minimumEdgeWidth; --edgeWidth)
     {
-        y0 = int(VIGRA_CSTD::floor((edgeWidth - xc) / slope + yc + 0.5));
-        y1 = int(VIGRA_CSTD::floor((w - edgeWidth - 1 - xc) / slope + yc + 0.5));
+        y0 = ptrdiff_t(VIGRA_CSTD::floor((edgeWidth - xc) / slope + yc + 0.5));
+        y1 = ptrdiff_t(VIGRA_CSTD::floor((w - edgeWidth - 1 - xc) / slope + yc + 0.5));
         if(slope < 0.0)
             std::swap(y0, y1);
-        if(y1 - y0 >= (int)minimumNumberOfLines)
+        if(y1 - y0 >= (ptrdiff_t)minimumNumberOfLines)
             break;
     }
 
     vigra_precondition(edgeWidth >= minimumEdgeWidth,
         "slantedEdgeMTF(): Input edge is too slanted or image is too small");
 
-    y0 = std::max(y0, 0);
-    y1 = std::min(y1+1, (int)h);
+    y0 = std::max(y0, ptrdiff_t(0));
+    y1 = std::min(y1+1, h);
 
     res.resize(w, y1-y0);
 
@@ -265,7 +265,7 @@ prepareSlantedEdgeInput(SrcIterator sul, SrcIterator slr, SrcAccessor src, DestI
 }
 
 template <class Image>
-void slantedEdgeShadingCorrection(Image & i, unsigned int edgeWidth)
+void slantedEdgeShadingCorrection(Image & i, ptrdiff_t edgeWidth)
 {
     using namespace functor;
 
@@ -274,13 +274,13 @@ void slantedEdgeShadingCorrection(Image & i, unsigned int edgeWidth)
 
     transformImage(srcImageRange(i), destImage(i), log(Arg1() + Param(1.0)));
 
-    unsigned int w = i.width(),
-                 h = i.height();
+    ptrdiff_t w = i.width(),
+              h = i.height();
 
     Matrix<double> m(3,3), r(3, 1), l(3, 1);
-    for(unsigned int y = 0; y < h; ++y)
+    for(ptrdiff_t y = 0; y < h; ++y)
     {
-        for(unsigned int x = 0; x < edgeWidth; ++x)
+        for(ptrdiff_t x = 0; x < edgeWidth; ++x)
         {
             l(0,0) = x;
             l(1,0) = y;
@@ -296,9 +296,9 @@ void slantedEdgeShadingCorrection(Image & i, unsigned int edgeWidth)
            c = l(2,0);
 
     // subtract the plane and go back to the non-logarithmic representation
-    for(unsigned int y = 0; y < h; ++y)
+    for(ptrdiff_t y = 0; y < h; ++y)
     {
-        for(unsigned int x = 0; x < w; ++x)
+        for(ptrdiff_t x = 0; x < w; ++x)
         {
             i(x, y) = VIGRA_CSTD::exp(i(x,y) - a*x - b*y - c);
         }
@@ -309,8 +309,8 @@ template <class Image, class BackInsertable>
 void slantedEdgeSubpixelShift(Image const & img, BackInsertable & centers, double & angle,
                               SlantedEdgeMTFOptions const & options)
 {
-    unsigned int w = img.width();
-    unsigned int h = img.height();
+    ptrdiff_t w = img.width();
+    ptrdiff_t h = img.height();
 
     Image grad(w, h);
     Kernel1D<double> kgrad;
@@ -318,28 +318,28 @@ void slantedEdgeSubpixelShift(Image const & img, BackInsertable & centers, doubl
 
     separableConvolveX(srcImageRange(img), destImage(grad), kernel1d(kgrad));
 
-    int desiredEdgeWidth = (int)options.desired_edge_width;
+    ptrdiff_t desiredEdgeWidth = (ptrdiff_t)options.desired_edge_width;
     double sy = 0.0, sx = 0.0, syy = 0.0, sxy = 0.0;
-    for(unsigned int y = 0; y < h; ++y)
+    for(ptrdiff_t y = 0; y < h; ++y)
     {
         double a = 0.0,
                b = 0.0;
-        for(unsigned int x = 0; x < w; ++x)
+        for(ptrdiff_t x = 0; x < w; ++x)
         {
             a += x*grad(x,y);
             b += grad(x,y);
         }
-        int c = int(a / b);
+        ptrdiff_t c = ptrdiff_t(a / b);
         // c is biased because the numbers of black and white pixels differ
         // repeat the analysis with a symmetric window around the edge
         a = 0.0;
         b = 0.0;
-        int ew = desiredEdgeWidth;
+        ptrdiff_t ew = desiredEdgeWidth;
         if(c-desiredEdgeWidth < 0)
             ew = c;
-        if(c + ew + 1 >= (int)w)
+        if(c + ew + 1 >= w)
             ew = w - c - 1;
-        for(int x = c-ew; x < c+ew+1; ++x)
+        for(ptrdiff_t x = c-ew; x < c+ew+1; ++x)
         {
             a += x*grad(x,y);
             b += grad(x,y);
@@ -356,7 +356,7 @@ void slantedEdgeSubpixelShift(Image const & img, BackInsertable & centers, doubl
 
     // compute the regularized subpixel values of the edge location
     angle = VIGRA_CSTD::atan(a);
-    for(unsigned int y = 0; y < h; ++y)
+    for(ptrdiff_t y = 0; y < h; ++y)
     {
         centers.push_back(a * y + b);
     }
@@ -366,18 +366,19 @@ template <class Image, class Vector>
 void slantedEdgeCreateOversampledLine(Image const & img, Vector const & centers,
                                       Image & result)
 {
-    unsigned int w = img.width();
-    unsigned int h = img.height();
-    unsigned int w2 = std::min(std::min(int(centers[0]), int(centers[h-1])),
-                               std::min(int(w - centers[0]) - 1, int(w - centers[h-1]) - 1));
-    unsigned int ww = 8*w2;
+    ptrdiff_t w = img.width();
+    ptrdiff_t h = img.height();
+    ptrdiff_t w2 = std::min(std::min(ptrdiff_t(centers[0]), ptrdiff_t(centers[h-1])),
+                            std::min(ptrdiff_t(w - centers[0]) - 1,
+                                     ptrdiff_t(w - centers[h-1]) - 1));
+    ptrdiff_t ww = 8*w2;
 
     Image r(ww, 1), s(ww, 1);
-    for(unsigned int y = 0; y < h; ++y)
+    for(ptrdiff_t y = 0; y < h; ++y)
     {
-        int x0 = int(centers[y]) - w2;
-        int x1 = int((VIGRA_CSTD::ceil(centers[y]) - centers[y])*4);
-        for(; x1 < (int)ww; x1 += 4)
+        ptrdiff_t x0 = ptrdiff_t(centers[y]) - w2;
+        ptrdiff_t x1 = ptrdiff_t((VIGRA_CSTD::ceil(centers[y]) - centers[y])*4);
+        for(; x1 < ww; x1 += 4)
         {
             r(x1, 0) += img(x0, y);
             ++s(x1, 0);
@@ -385,7 +386,7 @@ void slantedEdgeCreateOversampledLine(Image const & img, Vector const & centers,
         }
     }
 
-    for(unsigned int x = 0; x < ww; ++x)
+    for(ptrdiff_t x = 0; x < ww; ++x)
     {
         vigra_precondition(s(x,0) > 0.0,
            "slantedEdgeMTF(): Input edge is not slanted enough");
@@ -393,7 +394,7 @@ void slantedEdgeCreateOversampledLine(Image const & img, Vector const & centers,
     }
 
     result.resize(ww-1, 1);
-    for(unsigned int x = 0; x < ww-1; ++x)
+    for(ptrdiff_t x = 0; x < ww-1; ++x)
     {
         result(x,0) = r(x+1,0) - r(x,0);
     }
@@ -403,11 +404,11 @@ template <class Image, class BackInsertable>
 void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
                         SlantedEdgeMTFOptions const & options)
 {
-    unsigned int w = i.width();
-    unsigned int h = i.height();
+    ptrdiff_t w = i.width();
+    ptrdiff_t h = i.height();
 
     double slantCorrection = VIGRA_CSTD::cos(angle);
-    int desiredEdgeWidth = 4*options.desired_edge_width;
+    ptrdiff_t desiredEdgeWidth = 4*options.desired_edge_width;
 
     Image magnitude;
 
@@ -417,9 +418,9 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
         fourierTransform(srcImageRange(i), destImage(otf));
 
         magnitude.resize(w, h);
-        for(unsigned int y = 0; y < h; ++y)
+        for(ptrdiff_t y = 0; y < h; ++y)
         {
-            for(unsigned int x = 0; x < w; ++x)
+            for(ptrdiff_t x = 0; x < w; ++x)
             {
                 magnitude(x, y) = norm(otf(x, y));
             }
@@ -444,9 +445,9 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
 
         // subtract the noise power spectrum from the total power spectrum
         magnitude.resize(w, h);
-        for(unsigned int y = 0; y < h; ++y)
+        for(ptrdiff_t y = 0; y < h; ++y)
         {
-            for(unsigned int x = 0; x < w; ++x)
+            for(ptrdiff_t x = 0; x < w; ++x)
             {
                 magnitude(x, y) = VIGRA_CSTD::sqrt(std::max(0.0, squaredNorm(otf(x, y))-squaredNorm(fnoise(x, y))));
             }
@@ -458,10 +459,10 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
     Image smooth(w,h);
     separableConvolveX(srcImageRange(magnitude), destImage(smooth), kernel1d(gauss));
 
-    unsigned int ww = w/4;
+    ptrdiff_t ww = w/4;
     double maxVal = smooth(0,0),
            minVal = maxVal;
-    for(unsigned int k = 1; k < ww; ++k)
+    for(ptrdiff_t k = 1; k < ww; ++k)
     {
         if(smooth(k,0) >= 0.0 && smooth(k,0) < minVal)
             minVal = smooth(k,0);
@@ -470,7 +471,7 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
 
     typedef typename BackInsertable::value_type Result;
     mtf.push_back(Result(0.0, 1.0));
-    for(unsigned int k = 1; k < ww; ++k)
+    for(ptrdiff_t k = 1; k < ww; ++k)
     {
         double n = (smooth(k,0) - minVal)/norm*sq(M_PI*k/w/VIGRA_CSTD::sin(M_PI*k/w));
         double xx = 4.0*k/w/slantCorrection;
@@ -485,8 +486,8 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
 /** \addtogroup SlantedEdgeMTF Camera MTF Estimation
     Determine the magnitude transfer function (MTF) of a camera using the slanted edge method.
 */
-//@{ 
-                                    
+//@{
+
 /********************************************************/
 /*                                                      */
 /*                     slantedEdgeMTF                   */
@@ -495,48 +496,48 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
 
 /** \brief Determine the magnitude transfer function of the camera.
 
-    This operator estimates the magnitude transfer function (MTF) of a camera by means of the 
+    This operator estimates the magnitude transfer function (MTF) of a camera by means of the
     slanted edge method described in:
-    
+
     ISO Standard No. 12233: <i>"Photography - Electronic still picture cameras - Resolution measurements"</i>, 2000
-    
-    The input must be an image that contains a single step edge with bright pixels on one side and dark pixels on 
+
+    The input must be an image that contains a single step edge with bright pixels on one side and dark pixels on
     the other. However, the intensity values must be neither saturated nor zero. The algorithms computes the MTF
-    from the Fourier transform of the edge's derivative. Thus, if the actual MTF is anisotropic, the estimated 
-    MTF does actually only apply in the direction perpendicular to the edge - several edges at different 
+    from the Fourier transform of the edge's derivative. Thus, if the actual MTF is anisotropic, the estimated
+    MTF does actually only apply in the direction perpendicular to the edge - several edges at different
     orientations are required to estimate an anisotropic MTF.
-    
+
     The algorithm returns a sequence of frequency / attenuation pairs. The frequency axis is normalized so that the
     Nyquist frequency of the original image is 0.5. Since the edge's derivative is computed with subpixel accuracy,
-    the attenuation can usually be computed for frequencies significantly above the Nyquist frequency as well. The 
+    the attenuation can usually be computed for frequencies significantly above the Nyquist frequency as well. The
     MTF estimate ends at either the first zero crossing of the MTF or at frequency 1, whichever comes earlier.
-    
+
     The present implementation improves the original slanted edge algorithm according to ISO 12233 in a number of
     ways:
-    
+
     <ul>
     <li> The edge is not required to run nearly vertically or horizontally (i.e. with a slant of approximately 5 degrees).
-         The algorithm will automatically compute the edge's actual angle and adjust estimates accordingly. 
-         However, it is still necessary for the edge to be somewhat slanted, because subpixel-accurate estimation 
-         of the derivative is impossible otherwise (i.e. the edge position perpendicular to the edge direction must 
-         differ by at least 1 pixel between the two ends of the edge). 
-         
-    <li> Our implementation uses a more accurate subpixel derivative algorithm. In addition, we first perform a shading 
+         The algorithm will automatically compute the edge's actual angle and adjust estimates accordingly.
+         However, it is still necessary for the edge to be somewhat slanted, because subpixel-accurate estimation
+         of the derivative is impossible otherwise (i.e. the edge position perpendicular to the edge direction must
+         differ by at least 1 pixel between the two ends of the edge).
+
+    <li> Our implementation uses a more accurate subpixel derivative algorithm. In addition, we first perform a shading
          correction in order to reduce possible derivative bias due to nonuniform illumination.
 
     <li> If the input image is large enough (i.e. there are at least 20 pixels on either side of the edge over
          the edge's entire length), our algorithm attempts to subtract the estimated noise power spectrum
          from the estimated MTF.
     </ul>
-    
+
     The source value type <TT>T1</TT> must be a scalar type which is convertible to <tt>double</tt>.
     The result is written into the \a result sequence, which must be back-insertable (supports <tt>push_back()</tt>)
-    and whose <tt>value_type</tt> must be constructible 
-    from two <tt>double</tt> values. Algorithm options can be set via the \a options object 
+    and whose <tt>value_type</tt> must be constructible
+    from two <tt>double</tt> values. Algorithm options can be set via the \a options object
     (see \ref vigra::NoiseNormalizationOptions for details).
-    
+
     <b> Declarations:</b>
-    
+
     pass 2D array views:
     \code
     namespace vigra {
@@ -546,7 +547,7 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
                        SlantedEdgeMTFOptions const & options = SlantedEdgeMTFOptions());
     }
     \endcode
-    
+
     \deprecatedAPI{slantedEdgeMTF}
     pass \ref ImageIterators and \ref DataAccessors :
     \code
@@ -567,20 +568,20 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
     }
     \endcode
     \deprecatedEnd
-    
+
     <b> Usage:</b>
-    
+
     <b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br>
     Namespace: vigra
 
     \code
     MultiArray<2, float> src(w,h);
     std::vector<vigra::TinyVector<double, 2> > mtf;
-    
+
     ...
     // keep all options at their default values
     slantedEdgeMTF(src, mtf);
-    
+
     // print the frequency / attenuation pairs found
     for(int k=0; k<result.size(); ++k)
         std::cout << "frequency: " << mtf[k][0] << ", estimated attenuation: " << mtf[k][1] << std::endl;
@@ -590,10 +591,10 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
     \code
     vigra::BImage src(w,h);
     std::vector<vigra::TinyVector<double, 2> > mtf;
-    
+
     ...
     vigra::slantedEdgeMTF(srcImageRange(src), mtf);
-    
+
     // print the frequency / attenuation pairs found
     for(int k=0; k<result.size(); ++k)
         std::cout << "frequency: " << mtf[k][0] << ", estimated attenuation: " << mtf[k][1] << std::endl;
@@ -602,15 +603,15 @@ void slantedEdgeMTFImpl(Image const & i, BackInsertable & mtf, double angle,
     \code
     SrcIterator upperleft, lowerright;
     SrcAccessor src;
-    
+
     typedef SrcAccessor::value_type SrcType;
     typedef NumericTraits<SrcType>::isScalar isScalar;
     assert(isScalar::asBool == true);
-    
+
     double value = src(uperleft);
-    
+
     BackInsertable result;
-    typedef BackInsertable::value_type ResultType;    
+    typedef BackInsertable::value_type ResultType;
     double intensity, variance;
     result.push_back(ResultType(intensity, variance));
     \endcode
@@ -624,7 +625,7 @@ slantedEdgeMTF(SrcIterator sul, SrcIterator slr, SrcAccessor src, BackInsertable
                SlantedEdgeMTFOptions const & options = SlantedEdgeMTFOptions())
 {
     DImage preparedInput;
-    unsigned int edgeWidth = detail::prepareSlantedEdgeInput(sul, slr, src, preparedInput, options);
+    ptrdiff_t edgeWidth = detail::prepareSlantedEdgeInput(sul, slr, src, preparedInput, options);
     detail::slantedEdgeShadingCorrection(preparedInput, edgeWidth);
 
     ArrayVector<double> centers;
@@ -662,43 +663,43 @@ slantedEdgeMTF(MultiArrayView<2, T1, S1> const & src, BackInsertable & mtf,
 /** \brief Fit a Gaussian function to a given MTF.
 
     This function expects a sequence of frequency / attenuation pairs as produced by \ref slantedEdgeMTF()
-    and finds the best fitting Gaussian point spread function (Gaussian functions are good approximations 
+    and finds the best fitting Gaussian point spread function (Gaussian functions are good approximations
     of the PSF of many real cameras). It returns the standard deviation (scale) of this function. The algorithm
     computes the standard deviation by means of a linear least square on the logarithm of the MTF, i.e.
-    an algebraic fit rather than a Euclidean fit - thus, the resulting Gaussian may not be the one that 
+    an algebraic fit rather than a Euclidean fit - thus, the resulting Gaussian may not be the one that
     intuitively fits the data optimally.
-    
+
     <b> Declaration:</b>
-    
+
     \code
     namespace vigra {
         template <class Vector>
         double mtfFitGaussian(Vector const & mtf);
     }
     \endcode
-    
+
     <b> Usage:</b>
-    
+
     <b>\#include</b> \<vigra/slanted_edge_mtf.hxx\><br>
     Namespace: vigra
-    
+
     \code
     MultiArray<2, float> src(w,h);
     std::vector<vigra::TinyVector<double, 2> > mtf;
-    
+
     ...
     slantedEdgeMTF(src, mtf);
     double scale = vigra::mtfFitGaussian(mtf)
-    
+
     std::cout << "The camera PSF is approximately a Gaussian at scale " << scale << std::endl;
     \endcode
 
     <b> Required Interface:</b>
-    
+
     \code
     Vector mtf;
     int numberOfMeasurements = mtf.size()
-    
+
     double frequency = mtf[0][0];
     double attenuation = mtf[0][1];
     \endcode
@@ -707,14 +708,14 @@ template <class Vector>
 double mtfFitGaussian(Vector const & mtf)
 {
     double minVal = mtf[0][1];
-    for(unsigned int k = 1; k < mtf.size(); ++k)
+    for(ptrdiff_t k = 1; k < (ptrdiff_t)mtf.size(); ++k)
     {
         if(mtf[k][1] < minVal)
             minVal = mtf[k][1];
     }
     double x2 = 0.0,
            xy = 0.0;
-    for(unsigned int k = 1; k < mtf.size(); ++k)
+    for(ptrdiff_t k = 1; k < (ptrdiff_t)mtf.size(); ++k)
     {
         if(mtf[k][1] <= 0.0)
             break;
diff --git a/include/vigra/slic.hxx b/include/vigra/slic.hxx
index b0864d3..db92466 100644
--- a/include/vigra/slic.hxx
+++ b/include/vigra/slic.hxx
@@ -362,12 +362,12 @@ Slic<N, T, Label>::postProcessing()
     }
     
     // make labels contiguous after possible merging
-    maxLabel = 0; 
+    unsigned int newMaxLabel = 0; 
     for(unsigned int i=1; i<=maxLabel; ++i)
     {
         if(regions[i] == i)
         {
-                regions[i] = (Label)++maxLabel;
+                regions[i] = (Label)++newMaxLabel;
         }
         else
         {
@@ -381,7 +381,7 @@ Slic<N, T, Label>::postProcessing()
         labelImage_[*node] = regions[labelImage_[*node]];
     }
     
-    return maxLabel;
+    return newMaxLabel;
 }
 
 } // namespace detail
diff --git a/include/vigra/specklefilters.hxx b/include/vigra/specklefilters.hxx
new file mode 100644
index 0000000..69574fa
--- /dev/null
+++ b/include/vigra/specklefilters.hxx
@@ -0,0 +1,1197 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2007-2014 by Benjamin Seppke                 */
+/*       Cognitive Systems Group, University of Hamburg, Germany        */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_SPECKLEFILTER_HXX
+#define VIGRA_SPECKLEFILTER_HXX
+
+#include "basicimage.hxx"
+#include "inspectimage.hxx"
+
+#include "applywindowfunction.hxx"
+
+namespace vigra {
+
+namespace detail 
+{
+
+/**
+ * Helper to store distances in lookuptable (LUT)    
+ */
+vigra::FImage distanceLUT(vigra::Diff2D const & window_shape)
+{
+    vigra::FImage res(window_shape);
+    
+    int y, x;
+    double  w_half = window_shape.x/2.0,
+            h_half = window_shape.y/2.0,
+            x_diff, y_diff;
+    
+    for(y=0; y != window_shape.y; y++)
+    {   
+        for(x=0; x != window_shape.x; x++)
+        {
+            x_diff = x-w_half;
+            y_diff = y-h_half;
+            res(x,y) = sqrt(x_diff*x_diff + y_diff*y_diff);
+        }
+    }
+    
+    return res;
+}
+
+} //end namespace detail
+
+/*********************************************************************
+ *                                                                   *
+ * The (Basic) Frost Filter                                          *
+ *                                                                   *
+ *     Parameters:      window_shape   The size of the filter        *
+ *                      k              The damping factor (0,...,1)  *
+ *********************************************************************/
+ 
+/**  
+    This function tries to reduce the speckle noise of an image by means of applying the 
+    basic Frost filter using a window of given size and a damping factor k. The implementation
+    is according to the article by 
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+*/
+//@{
+
+/** \brief  This function tries to reduce the speckle noise of an image by applying the basic Frost filter.
+
+    The user has to provide a window size and a damping factor k. The implementation is
+    according to the article by  
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+    
+    All restrictions of the called functions \ref applyWindowFunction apply.
+    
+    <b> Preconditions:</b>
+    \code  
+    0.0 < k <= 1.0
+    \endcode
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2>
+        void
+        frostFilter(MultiArrayView<2, T1, S1> const & src,
+                    MultiArrayView<2, T2, S2> dest,
+                    Diff2D window_shape, float k,
+                    BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+
+    }
+    \endcode
+
+    \deprecatedAPI{frostFilter}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void frostFilter(SrcIterator supperleft,
+                         SrcIterator slowerright, SrcAccessor sa,
+                         DestIterator dupperleft, DestAccessor da,
+                         Diff2D window_shape, float k,
+                         BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        frostFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                    pair<DestIterator, DestAccessor> dest,
+                    Diff2D window_shape, float k,
+                    BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/specklefilters.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> src(w,h), dest(w,h);
+    ...
+    
+    // apply a (basic) frost filter with a window size of 5x5 and a damping factor of 0.5
+    frostFilter(src, dest, Diff2D(5,5), 0.5);
+    \endcode
+*/
+
+doxygen_overloaded_function(template <...> void frostFilter)
+    
+template<typename VALUETYPE>
+class FrostFunctor
+{
+public:
+    FrostFunctor(Diff2D window_shape, float k)
+    : m_window_shape(window_shape),
+      m_k(k),
+      m_dist(detail::distanceLUT(window_shape))
+    {
+        using namespace vigra;      
+        vigra_precondition( k>0 && k<=1 , "vigra::FrostFunctor(): Damping factor k has to be: 0 < k <= 1!");
+    }
+    
+    template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+    void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)
+    {       
+        using namespace vigra;
+        
+        SrcIterator s_ul = s - m_window_shape/2,
+                    s_lr = s_ul + m_window_shape;
+        
+        FindAverageAndVariance<VALUETYPE> averageAndVariance;   // init functor
+        
+        inspectImage(s_ul, s_lr, s_acc, averageAndVariance);
+        
+        /*As defined in: Lopez & Touzi & Nezry: Adaptive speckle filters and scene heterogenity*/
+        VALUETYPE   C_I2 = averageAndVariance.variance() / (averageAndVariance.average() * averageAndVariance.average()),
+                    sum_m = 0.0,
+                    sum_pm = 0.0,
+                    m = 0.0,
+                    dist = 0.0,
+                    p = 0.0;
+        
+        SrcIterator ys = s_ul;
+        SrcIterator xs = ys;
+        
+        FImage::const_traverser ydist = m_dist.upperLeft();
+        FImage::const_traverser xdist = ydist;
+        FImage::Accessor   dist_acc = m_dist.accessor();
+        
+        //convolve mask with each impulse response to compute the result of the frost filter
+        int y, x;
+        for(y=0 ; ys.y!=s_lr.y; ys.y++, ydist.y++, y++)
+        {   
+            for(xs=ys, xdist=ydist, x=0; xs.x!=s_lr.x; xs.x++, xdist.x++, x++)
+            {
+                p = s_acc(xs);
+                
+                //impuls response of the frost filter
+                m = exp(-1 * m_k * C_I2 * dist_acc(xdist));
+                
+                //convolve
+                sum_pm += m * p;
+                sum_m += m;
+            }
+        }
+        //normalize
+        d_acc.set(sum_pm/sum_m, d);
+    }
+    
+    Diff2D windowShape() const
+    {
+        return m_window_shape;
+    }
+    
+private:
+    Diff2D m_window_shape;
+    float m_k;  
+    FImage m_dist;
+};
+
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+inline void frostFilter(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+                        DestIterator d_ul, DestAccessor d_acc, 
+                        Diff2D window_shape, float k,
+                        BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    FrostFunctor<typename SrcIterator::value_type> func(window_shape, k);
+    applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
+}
+
+template <class SrcIterator, class SrcAccessor, 
+class DestIterator, class DestAccessor>
+inline void frostFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+                        pair<DestIterator, DestAccessor> d, 
+                        Diff2D window_shape, float k,
+                        BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    frostFilter(s.first, s.second, s.third,
+                d.first, d.second, 
+                window_shape, k,
+                border);
+}
+
+
+template <class T1, class S1, 
+          class T2, class S2>
+inline void frostFilter(MultiArrayView<2, T1, S1> const & src,
+                        MultiArrayView<2, T2, S2> dest,
+                        Diff2D window_shape, float k,
+                        BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    vigra_precondition(src.shape() == dest.shape(),
+                        "vigra::frostFilter(): Shape mismatch between input and output.");
+    frostFilter(srcImageRange(src),
+                destImage(dest),  
+                window_shape, k,
+                border);
+}
+
+
+/*********************************************************************
+ *                                                                   *
+ * The Enhanced Frost Filter                                         *
+ *                                                                   *
+ *     Parameters:      window_shape   The size of the filter        *
+ *                      k              The damping factor (0,...,1)  *
+ *                      enl            Eq. Num. Looks for comp. of   *
+ *                                     the thresholds C_u and C_max  *
+ *********************************************************************/
+ 
+/**  
+    This function tries to reduce the speckle noise of an image by means of applying the 
+    enhanced Frost filter using a window of given size, a damping factor k, and the equivalent
+    numbers of look (enl). The implementation is according to the article by 
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+*/
+
+/** \brief  This function tries to reduce the speckle noise of an image by applying the Enhanced Frost filter.
+
+    The user has to provide a window size, a damping factor k, and the equivalent
+    numbers of look (enl). The implementation is according to the article by  
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+    
+    All restrictions of the called functions \ref applyWindowFunction apply.
+    
+    <b> Preconditions:</b>
+    \code  
+    1. 0.0 < k <= 1.0
+    2. enl > 0
+    \endcode
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2>
+        void
+        enhancedFrostFilter(MultiArrayView<2, T1, S1> const & src,
+                             MultiArrayView<2, T2, S2> dest,
+                             Diff2D window_shape, float k, int enl,
+                             BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+
+    }
+    \endcode
+
+    \deprecatedAPI{enhancedFrostFilter}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void enhancedFrostFilter(SrcIterator supperleft,
+                                  SrcIterator slowerright, SrcAccessor sa,
+                                  DestIterator dupperleft, DestAccessor da,
+                                  Diff2D window_shape, float k, int enl,
+                                  BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        enhancedFrostFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                             pair<DestIterator, DestAccessor> dest,
+                             Diff2D window_shape, float k, int enl,
+                             BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/specklefilters.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> src(w,h), dest(w,h);
+    ...
+    
+    // apply an enhanced frost filter with a window size of 5x5 and a damping factor of 0.5, where
+    // the image was composed by 3 equivalent looks:
+    enhancedFrostFilter(src, dest, Diff2D(5,5), 0.5, 3);
+    \endcode
+*/
+
+template<typename VALUETYPE>
+class EnhancedFrostFunctor
+{
+public:
+    EnhancedFrostFunctor(Diff2D window_shape, float k, int enl)
+    : m_window_shape(window_shape),
+      m_k(k),
+    m_enl(enl),
+    m_dist(detail::distanceLUT(window_shape))
+
+    {
+        using namespace vigra;
+        vigra_precondition( k>0 && k<=1 , "vigra::EnhancedFrostFunctor(): Damping factor k has to be: 0 < k <= 1!");
+        vigra_precondition( enl>0, "vigra::EnhancedFrostFunctor(): Equivalent number of looks (enl) must be larger than zero!");
+    }
+    
+    template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+    void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)
+    {
+        using namespace vigra;
+        
+        SrcIterator s_ul = s - m_window_shape/2,
+                    s_lr = s_ul + m_window_shape;
+        
+        FindAverageAndVariance<VALUETYPE> averageAndVariance;   // init functor
+        
+        inspectImage(s_ul, s_lr, s_acc, averageAndVariance);
+        
+        /*As defined in: Lopez & Touzi & Nezry: Adaptive speckle filters and scene heterogenity*/
+        /* With ENL -> C_u and ENL -> C_max from ENVI: online_help/Using_Adaptive_Filters.html */
+        VALUETYPE       C_u    = 0.523/sqrt((double)m_enl),
+                        C_max  = sqrt(1+2.0/m_enl),
+                        C_I = sqrt(averageAndVariance.variance()) / averageAndVariance.average(),
+                        sum_m = 0.0,
+                        sum_pm = 0.0,
+                        m = 0.0,
+                        dist = 0.0,
+                        p = 0.0;
+        
+        SrcIterator ys = s_ul;
+        SrcIterator xs = ys;
+        
+        FImage::const_traverser ydist = m_dist.upperLeft();
+        FImage::const_traverser xdist = ydist;
+        FImage::Accessor   dist_acc = m_dist.accessor();
+        
+        //convolve mask with each impulse response to compute the result of the frost filter
+        int y, x;
+        for(y=0 ; ys.y!=s_lr.y; ys.y++, ydist.y++, y++)
+        {   
+            for(xs=ys, xdist=ydist, x=0; xs.x!=s_lr.x; xs.x++, xdist.x++, x++)
+            {
+                p = s_acc(xs);
+                
+                //impuls response of the frost filter
+                m = exp(-m_k * func(C_I, C_max, C_u) * dist_acc(xdist));
+                
+                //convolve
+                sum_pm += m * p;
+                sum_m += m;
+            }
+        }
+        //normalize
+        d_acc.set(sum_pm/sum_m, d);
+    }
+    
+    Diff2D windowShape() const
+    {
+        return m_window_shape;
+    }
+    
+private:
+    //The penalisier function:
+    //As defined in: Shi & Fung: A comparison of Digital Speckle Filters
+    inline double func(double C_I, double C_max, double C_u) const
+    {
+        if(C_I < C_u)
+        {
+            return 0;
+        }
+        else if (C_I <= C_max)
+        {
+            return (C_I - C_u)/(C_max - C_I);
+        }
+        else
+        {
+            return 1.0e100;
+        }
+    }
+    
+    Diff2D m_window_shape;
+    float m_k;  
+    int m_enl;
+    FImage m_dist;
+};
+    
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+inline void enhancedFrostFilter(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+                                DestIterator d_ul, DestAccessor d_acc, 
+                                Diff2D window_shape, float k, int enl,
+                                BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    EnhancedFrostFunctor<typename SrcIterator::value_type> func(window_shape, k, enl);
+    applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
+}
+
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+inline void enhancedFrostFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+                                pair<DestIterator, DestAccessor> d, 
+                                Diff2D window_shape, float k, int enl,
+                                BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    enhancedFrostFilter(s.first, s.second, s.third,
+                        d.first, d.second, 
+                        window_shape, k, enl,
+                        border);
+}
+
+
+template <class T1, class S1, 
+          class T2, class S2>
+inline void enhancedFrostFilter(MultiArrayView<2, T1, S1> const & src,
+                        MultiArrayView<2, T2, S2> dest,
+                        Diff2D window_shape, float k, int enl,
+                        BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    vigra_precondition(src.shape() == dest.shape(),
+                        "vigra::enhancedFrostFilter(): Shape mismatch between input and output.");
+    enhancedFrostFilter(srcImageRange(src),
+                        destImage(dest),  
+                        window_shape, k, enl,
+                        border);
+}
+
+
+
+/*********************************************************************
+ *                                                                   *
+ * The Gamma Maximum A Posteriori (MAP) Filter                       *
+ *                                                                   *
+ *     Parameters:      window_shape   The size of the filter        *
+ *                      enl            Eq. Num. Looks for comp. of   *
+ *                                     the thresholds C_u and C_max  *
+ *********************************************************************/
+
+/**  
+    This function tries to reduce the speckle noise of an image by means of applying the 
+    Gamma Maximum A Posteriori (MAP) filter using a window of given size, and the equivalent
+    numbers of look (enl). The implementation is according to the article by 
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+*/
+
+/** \brief  This function tries to reduce the speckle noise of an image by applying the Gamma Maximum A Posteriori (MAP) filter.
+
+    The user has to provide a window size and the equivalent numbers of look (enl).
+    The implementation is according to the article by  
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+    
+    All restrictions of the called functions \ref applyWindowFunction apply.
+    
+    <b> Preconditions:</b>
+    \code  
+    enl > 0
+    \endcode
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2>
+        void
+        gammaMAPFilter(MultiArrayView<2, T1, S1> const & src,
+                             MultiArrayView<2, T2, S2> dest,
+                             Diff2D window_shape, int enl,
+                             BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+
+    }
+    \endcode
+
+    \deprecatedAPI{gammaMAPFilter}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void gammaMAPFilter(SrcIterator supperleft,
+                                  SrcIterator slowerright, SrcAccessor sa,
+                                  DestIterator dupperleft, DestAccessor da,
+                                  Diff2D window_shape, int enl,
+                                  BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        gammaMAPFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                             pair<DestIterator, DestAccessor> dest,
+                             Diff2D window_shape, int enl,
+                             BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/specklefilters.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> src(w,h), dest(w,h);
+    ...
+    
+    // apply a Gamma MAP filter with a window size of 5x5, where
+    // the image was composed by 3 equivalent looks:
+    gammaMAPFilter(src, dest, Diff2D(5,5), 3);
+    \endcode
+*/
+
+template<typename VALUETYPE>
+class GammaMAPFunctor
+{
+public:
+    GammaMAPFunctor(Diff2D window_shape, int enl)
+    : m_window_shape(window_shape),
+      m_enl(enl)
+    {
+        using namespace vigra;      
+        vigra_precondition( enl>0, "vigra::GamaMAPFunctor(): Equivalent number of looks (enl) must be larger than zero!");
+    }
+    
+    template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+    void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)
+    {
+        using namespace vigra;
+        
+        SrcIterator s_ul = s - m_window_shape/2,
+                    s_lr = s_ul + m_window_shape;
+        
+        FindAverageAndVariance<VALUETYPE> averageAndVariance;   // init functor
+        inspectImage(s_ul, s_lr, s_acc, averageAndVariance);
+        
+        //As defined in: Shi & Fung: A comparison of Digital Speckle Filters
+        /* With ENL -> C_u and ENL -> C_max from ENVI: online_help/Using_Adaptive_Filters.html */
+        VALUETYPE       C_u    = 0.523/sqrt((double)m_enl),
+                        C_max  = sqrt(1+2.0/m_enl),
+                        I_mean = averageAndVariance.average(),
+                        C_I = sqrt(averageAndVariance.variance()) / I_mean;
+        
+        if(C_I <= C_u)
+        {           
+            d_acc.set(averageAndVariance.average(), d);
+        }
+        else if(C_I < C_max)
+        {
+            double  alpha = (1 + C_u*C_u) / (C_I*C_I - C_u*C_u),
+                    aL1   = alpha - m_enl - 1,
+                    result =        (aL1 * I_mean + sqrt(I_mean*I_mean * aL1*aL1 + 4*alpha*m_enl*I_mean)) 
+                                /   (2 * alpha); 
+            d_acc.set(result, d);
+        }
+        else {
+            d_acc.set(s_acc(s), d);
+        }
+
+    }
+    
+    Diff2D windowShape() const
+    {
+        return m_window_shape;
+    }
+    
+private:
+    Diff2D m_window_shape;
+    int m_enl;
+};
+
+    
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+inline void gammaMAPFilter(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+                           DestIterator d_ul, DestAccessor d_acc, 
+                           Diff2D window_shape, int enl,
+                           BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    GammaMAPFunctor<typename SrcIterator::value_type> func(window_shape, enl);
+    applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
+}
+
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+inline void gammaMAPFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+                           pair<DestIterator, DestAccessor> d, 
+                           Diff2D window_shape, int enl,
+                           BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    gammaMAPFilter(s.first, s.second, s.third,
+                        d.first, d.second, 
+                        window_shape, enl,
+                        border);
+}
+
+template <class T1, class S1, 
+          class T2, class S2>
+inline void gammaMAPFilter(MultiArrayView<2, T1, S1> const & src,
+                            MultiArrayView<2, T2, S2> dest,
+                            Diff2D window_shape, int enl,
+                            BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    vigra_precondition(src.shape() == dest.shape(),
+                        "vigra::gammaMAPFilter(): Shape mismatch between input and output.");
+    gammaMAPFilter(srcImageRange(src),
+                        destImage(dest),  
+                        window_shape, enl,
+                        border);
+}
+
+
+
+/*********************************************************************
+ *                                                                   *
+ * The Kuan Filter (with parameter window_shape)                     *
+ *                                                                   *
+ *     Parameters:      window_shape   The size of the filter        *
+ *                      enl            Eq. Num. Looks                *
+ *********************************************************************/
+
+/**  
+    This function tries to reduce the speckle noise of an image by means of applying the 
+    Kuan filter using a window of given size, and the equivalent
+    numbers of look (enl). The implementation is according to the article by 
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+*/
+
+/** \brief  This function tries to reduce the speckle noise of an image by applying the Kuan filter.
+
+    The user has to provide a window size and the equivalent numbers of look (enl).
+    The implementation is according to the article by  
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+    
+    All restrictions of the called functions \ref applyWindowFunction apply.
+    
+    <b> Preconditions:</b>
+    \code  
+    enl > 0
+    \endcode
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2>
+        void
+        kuanFilter(MultiArrayView<2, T1, S1> const & src,
+                   MultiArrayView<2, T2, S2> dest,
+                   Diff2D window_shape, int enl,
+                   BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+
+    }
+    \endcode
+
+    \deprecatedAPI{kuanFilter}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void kuanFilter(SrcIterator supperleft,
+                        SrcIterator slowerright, SrcAccessor sa,
+                        DestIterator dupperleft, DestAccessor da,
+                        Diff2D window_shape, int enl,
+                        BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        kuanFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                   pair<DestIterator, DestAccessor> dest,
+                   Diff2D window_shape, int enl,
+                   BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/specklefilters.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> src(w,h), dest(w,h);
+    ...
+    
+    // apply a Kuan filter with a window size of 5x5, where
+    // the image was composed by 3 equivalent looks:
+    kuanFilter(src, dest, Diff2D(5,5), 3);
+    \endcode
+*/
+template<typename VALUETYPE>
+class KuanFunctor
+{
+public:
+    KuanFunctor(Diff2D window_shape, int enl)
+    : m_window_shape(window_shape),
+      m_enl(enl)
+    {
+        using namespace vigra;      
+        vigra_precondition( enl>0, "vigra::KuanFunctor(): Equivalent number of looks (enl) must be larger than zero!");
+    }
+
+    template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+    void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)
+    {
+        using namespace vigra;
+        
+        SrcIterator s_ul = s - m_window_shape/2,
+                    s_lr = s_ul + m_window_shape;
+        
+        FindAverageAndVariance<VALUETYPE> averageAndVariance;   // init functor
+        inspectImage(s_ul, s_lr, s_acc, averageAndVariance);
+        
+        /*As defined in: Lopez & Touzi & Nezry: Adaptive speckle filters and scene heterogenity*/
+        VALUETYPE   /*C_u2 = m_var_u/(m_mean_u*m_mean_u),*/
+                    C_u2    = (0.523*0.523)/m_enl,                   
+                    C_I2 = averageAndVariance.variance() / (averageAndVariance.average()*averageAndVariance.average()), 
+                    W    = (1 - C_u2/C_I2)/(1 + C_u2),
+                    I    = s_acc(s),
+                    R    = I * W + averageAndVariance.average() * (1 - W);
+        
+        d_acc.set(R, d);
+    }
+    
+    Diff2D windowShape() const
+    {
+        return m_window_shape;
+    }
+    
+private:
+    Diff2D m_window_shape;
+    int m_enl;
+};
+    
+template <class SrcIterator, class SrcAccessor, 
+class DestIterator, class DestAccessor>
+inline void kuanFilter(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+                       DestIterator d_ul, DestAccessor d_acc, 
+                       Diff2D window_shape, int enl,
+                       BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    KuanFunctor<typename SrcIterator::value_type> func(window_shape, enl);
+    applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
+}
+
+template <class SrcIterator, class SrcAccessor, 
+class DestIterator, class DestAccessor>
+inline void kuanFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+                       pair<DestIterator, DestAccessor> d, 
+                       Diff2D window_shape, int enl,
+                       BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    kuanFilter(s.first, s.second, s.third,
+               d.first, d.second, 
+               window_shape, enl,
+               border);
+}
+
+template <class T1, class S1, 
+          class T2, class S2>
+inline void kuanFilter(MultiArrayView<2, T1, S1> const & src,
+                       MultiArrayView<2, T2, S2> dest,
+                       Diff2D window_shape, int enl,
+                       BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    vigra_precondition(src.shape() == dest.shape(),
+                        "vigra::kuanFilter(): Shape mismatch between input and output.");
+    kuanFilter(srcImageRange(src),
+               destImage(dest),  
+               window_shape, enl,
+               border);
+}
+
+
+/*********************************************************************
+ *                                                                   *
+ * The (Basic) Lee Filter                                            *
+ *                                                                   *
+ *     Parameters:      window_shape   The size of the filter        *
+ *                      enl            Eq. Num. Looks                *
+ *********************************************************************/
+
+/**  
+    This function tries to reduce the speckle noise of an image by means of applying the 
+    (basic) Lee filter using a window of given size, and the equivalent
+    numbers of look (enl). The implementation is according to the article by 
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+*/
+
+/** \brief  This function tries to reduce the speckle noise of an image by applying the basic Lee filter.
+
+    The user has to provide a window size and the equivalent numbers of look (enl).
+    The implementation is according to the article by  
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+    
+    All restrictions of the called functions \ref applyWindowFunction apply.
+    
+    <b> Preconditions:</b>
+    \code  
+    enl > 0
+    \endcode
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2>
+        void
+        leeFilter(MultiArrayView<2, T1, S1> const & src,
+                   MultiArrayView<2, T2, S2> dest,
+                   Diff2D window_shape, int enl,
+                   BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+
+    }
+    \endcode
+
+    \deprecatedAPI{leeFilter}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void leeFilter(SrcIterator supperleft,
+                        SrcIterator slowerright, SrcAccessor sa,
+                        DestIterator dupperleft, DestAccessor da,
+                        Diff2D window_shape, int enl,
+                        BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        leeFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                   pair<DestIterator, DestAccessor> dest,
+                   Diff2D window_shape, int enl,
+                   BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/specklefilters.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> src(w,h), dest(w,h);
+    ...
+    
+    // apply a basic Lee filter with a window size of 5x5, where
+    // the image was composed by 3 equivalent looks:
+    leeFilter(src, dest, Diff2D(5,5), 3);
+    \endcode
+*/
+template<typename VALUETYPE = float>
+class LeeFunctor
+{
+public:
+    LeeFunctor(Diff2D window_shape, int enl)
+    : m_window_shape(window_shape),
+      m_enl(enl)
+    {
+        using namespace vigra;      
+        vigra_precondition( enl>0, "vigra::LeeFunctor(): Equivalent number of looks (enl) must be larger than zero!");
+    }
+    
+    
+    template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+    void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)
+    {
+        using namespace vigra;
+        
+        SrcIterator s_ul = s - m_window_shape/2,
+                    s_lr = s_ul + m_window_shape;
+        
+        FindAverageAndVariance<VALUETYPE> averageAndVariance;   // init functor
+        inspectImage(s_ul, s_lr, s_acc, averageAndVariance);
+        
+        /*As defined in: Lopez & Touzi & Nezry: Adaptive speckle filters and scene heterogenity*/
+        VALUETYPE   C_u2    = (0.523*0.523)/m_enl,
+                    C_I2 = averageAndVariance.variance() / (averageAndVariance.average()*averageAndVariance.average()), 
+                    W    = (1.0 - C_u2/C_I2),
+                    I    = s_acc(s),
+                    R    = I * W + averageAndVariance.average() * (1 - W);
+        
+        d_acc.set(R, d);
+    }
+    
+    Diff2D windowShape() const
+    {
+        return m_window_shape;
+    }
+    
+private:
+    Diff2D m_window_shape;
+    int m_enl;
+};
+
+template <class SrcIterator, class SrcAccessor, 
+class DestIterator, class DestAccessor>
+void leeFilter(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+               DestIterator d_ul, DestAccessor d_acc, 
+               Diff2D window_shape, int enl,
+               BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    LeeFunctor<typename SrcIterator::value_type> func(window_shape, enl);
+    applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
+}
+
+template <class SrcIterator, class SrcAccessor, 
+class DestIterator, class DestAccessor>
+void leeFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+               pair<DestIterator, DestAccessor> d, 
+               Diff2D window_shape, int enl,
+               BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    leeFilter(s.first, s.second, s.third,
+              d.first, d.second, 
+              window_shape, enl,
+              border);
+}
+
+template <class T1, class S1, 
+          class T2, class S2>
+inline void leeFilter(MultiArrayView<2, T1, S1> const & src,
+                       MultiArrayView<2, T2, S2> dest,
+                       Diff2D window_shape, int enl,
+                       BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    vigra_precondition(src.shape() == dest.shape(),
+                        "vigra::leeFilter(): Shape mismatch between input and output.");
+    leeFilter(srcImageRange(src),
+              destImage(dest),  
+              window_shape, enl,
+              border);
+}
+
+
+/*********************************************************************
+ *                                                                   *
+ * The Enhanced Lee Filter                                           *
+ *                                                                   *
+ *     Parameters:      window_shape   The size of the filter        *
+ *                      k              The damping factor (0,...,1)  *
+ *                      enl            Eq. Num. Looks for comp. of   *
+ *                                     the thresholds C_u and C_max  *
+ *********************************************************************/
+ 
+/**  
+    This function tries to reduce the speckle noise of an image by means of applying the 
+    enhanced Lee filter using a window of given size, a damping factor k, and the equivalent
+    numbers of look (enl). The implementation is according to the article by 
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+*/
+
+/** \brief  This function tries to reduce the speckle noise of an image by applying the Enhanced Lee filter.
+
+    The user has to provide a window size, a damping factor k, and the equivalent
+    numbers of look (enl). The implementation is according to the article by  
+    Lopez & Touzi & Nezry (1990): Adaptive speckle filters and scene heterogenity.
+    
+    All restrictions of the called functions \ref applyWindowFunction apply.
+    
+    <b> Preconditions:</b>
+    \code  
+    1. 0.0 < k <= 1.0
+    2. enl > 0
+    \endcode
+    
+    <b> Declarations:</b>
+
+    pass 2D array views:
+    \code
+    namespace vigra {
+        template <class T1, class S1,
+                  class T2, class S2>
+        void
+        enhancedLeeFilter(MultiArrayView<2, T1, S1> const & src,
+                             MultiArrayView<2, T2, S2> dest,
+                             Diff2D window_shape, float k, int enl,
+                             BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+
+    }
+    \endcode
+
+    \deprecatedAPI{enhancedLeeFilter}
+    pass \ref ImageIterators and \ref DataAccessors :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void enhancedLeeFilter(SrcIterator supperleft,
+                                  SrcIterator slowerright, SrcAccessor sa,
+                                  DestIterator dupperleft, DestAccessor da,
+                                  Diff2D window_shape, float k, int enl,
+                                  BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    use argument objects in conjunction with \ref ArgumentObjectFactories :
+    \code
+    namespace vigra {
+        template <class SrcIterator, class SrcAccessor,
+                  class DestIterator, class DestAccessor>
+        void
+        enhancedLeeFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
+                             pair<DestIterator, DestAccessor> dest,
+                             Diff2D window_shape, float k, int enl,
+                             BorderTreatmentMode border = BORDER_TREATMENT_REPEAT);
+    }
+    \endcode
+    \deprecatedEnd
+
+    <b> Usage:</b>
+
+    <b>\#include</b> \<vigra/specklefilters.hxx\><br/>
+    Namespace: vigra
+
+    \code
+    unsigned int w=1000, h=1000;
+    MultiArray<2, float> src(w,h), dest(w,h);
+    ...
+    
+    // apply an enhanced Lee filter with a window size of 5x5 and a damping factor of 0.5, where
+    // the image was composed by 3 equivalent looks:
+    enhancedLeeFilter(src, dest, Diff2D(5,5), 0.5, 3);
+    \endcode
+*/
+
+template<typename VALUETYPE>
+class EnhancedLeeFunctor
+{
+public:
+    EnhancedLeeFunctor(Diff2D window_shape, float k, int enl)
+    : m_window_shape(window_shape),
+      m_k(k),
+      m_enl(enl)
+    {
+        using namespace vigra;      
+        vigra_precondition( k>0 && k<=1 , "vigra::EnhancedLeeFunctor(): Damping factor k has to be: 0 < k <= 1!");
+        vigra_precondition( enl>0, "vigra::EnhancedLeeFunctor(): Equivalent number of looks (enl) must be larger than zero!");
+    }
+    
+    template <class SrcIterator,  class SrcAccessor, class DestIterator,  class DestAccessor>
+    void operator()(SrcIterator s, SrcAccessor s_acc, DestIterator d, DestAccessor d_acc)
+    {   
+        using namespace vigra;
+        
+        SrcIterator s_ul = s - m_window_shape/2,
+                    s_lr = s_ul + m_window_shape;
+        
+        
+        FindAverageAndVariance<VALUETYPE> averageAndVariance;   // init functor
+        inspectImage(s_ul, s_lr, s_acc, averageAndVariance);
+        
+        /*As defined in: Lopez & Touzi & Nezry: Adaptive speckle filters and scene heterogenity*/
+        /* With ENL -> C_u and ENL -> C_max from ENVI: online_help/Using_Adaptive_Filters.html */
+        VALUETYPE   C_u    = 0.523/sqrt((double)m_enl),
+                    C_max  = sqrt(1+2.0/m_enl),
+                    C_A    = sqrt(averageAndVariance.variance()) / averageAndVariance.average(), 
+                    W      = exp(-m_k * (C_A - C_u)/(C_max - C_A)),
+                    I      = s_acc(s);
+        
+        if( C_A <= C_u )
+        {
+            d_acc.set(averageAndVariance.average(), d);
+        }
+        else if(C_A < C_max)
+        {
+            d_acc.set(I * W + averageAndVariance.average() * (1 - W), d);
+        }
+        else {
+            d_acc.set(I, d);
+        }
+    }
+    
+    Diff2D windowShape() const
+    {
+        return m_window_shape;
+    }
+    
+private:
+    
+    Diff2D m_window_shape;
+    float m_k;
+    int m_enl;
+};
+    
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+void enhancedLeeFilter(SrcIterator s_ul,  SrcIterator s_lr,   SrcAccessor s_acc,
+                       DestIterator d_ul, DestAccessor d_acc, 
+                       Diff2D window_shape, float k, int enl,
+                       BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    EnhancedLeeFunctor<typename SrcIterator::value_type> func(window_shape, k, enl);
+    applyWindowFunction(s_ul, s_lr, s_acc, d_ul, d_acc, func, border);
+}
+
+template <class SrcIterator, class SrcAccessor, 
+          class DestIterator, class DestAccessor>
+void enhancedLeeFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
+                       pair<DestIterator, DestAccessor> d, 
+                       Diff2D window_shape, float k, int enl,
+                       BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    enhancedLeeFilter(s.first, s.second, s.third,
+                      d.first, d.second, 
+                      window_shape, k, enl,
+                      border);
+}
+
+template <class T1, class S1, 
+          class T2, class S2>
+inline void enhancedLeeFilter(MultiArrayView<2, T1, S1> const & src,
+                              MultiArrayView<2, T2, S2> dest,
+                              Diff2D window_shape, float k, int enl,
+                              BorderTreatmentMode border = BORDER_TREATMENT_REPEAT)
+{
+    vigra_precondition(src.shape() == dest.shape(),
+                        "vigra::enhancedLeeFilter(): Shape mismatch between input and output.");
+    enhancedLeeFilter(srcImageRange(src),
+                        destImage(dest),  
+                        window_shape, k, enl,
+                        border);
+}
+
+//@}
+
+} //end of namespace vigra
+
+#endif //VIGRA_SPECKLEFILTERS_HXX
\ No newline at end of file
diff --git a/include/vigra/stdconvolution.hxx b/include/vigra/stdconvolution.hxx
index af229d3..b5d4c43 100644
--- a/include/vigra/stdconvolution.hxx
+++ b/include/vigra/stdconvolution.hxx
@@ -139,7 +139,7 @@ void convolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
             // init the sum
             SumType sum = NumericTraits<SumType>::zero();
             KernelIterator ykernel  = ki + klr;
-            
+
             if(x >= klr.x && y >= klr.y && x < w + kul.x && y < h + kul.y)
             {
                 // kernel is entirely inside the image
@@ -227,7 +227,7 @@ void convolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
                         sum += ak(xkernel) * src_acc(src_ul, diff);
                     }
                 }
-                
+
                 sum *= norm / ksum;
             }
             else if(border == BORDER_TREATMENT_ZEROPAD)
@@ -445,7 +445,7 @@ convolveImage(MultiArrayView<2, T1, S1> const & src,
     <b> Preconditions:</b>
 
     <ul>
-    <li> The image must be longer than the kernel radius: <tt>w > std::max(kernel.lowerRight().x, -kernel.upperLeft().x)</tt> and 
+    <li> The image must be longer than the kernel radius: <tt>w > std::max(kernel.lowerRight().x, -kernel.upperLeft().x)</tt> and
          <tt>h > std::max(kernel.lowerRight().y, -kernel.upperLeft().y)</tt>.
     <li> The sum of kernel elements must be != 0.
     <li> <tt>border == BORDER_TREATMENT_CLIP || border == BORDER_TREATMENT_AVOID</tt>
@@ -792,6 +792,11 @@ public:
         {}
 
         ~InitProxy()
+#ifndef _MSC_VER
+            throw(PreconditionViolation)
+#elif _MSC_VER >= 1900
+            noexcept(false)
+#endif
         {
             vigra_precondition(count_ == 1 || count_ == sum_,
                                "Kernel2D::initExplicitly(): "
@@ -997,21 +1002,17 @@ public:
         }
     }
 
-        /** \brief Init as a 2D box filter with given radius.
-        
-            The function returns a reference to the kernel.
-         */    
+        /** Init as a 2D box filter with given radius.
+         */
     void initAveraging(int radius)
     {
         Kernel1D<value_type> avg;
         avg.initAveraging(radius);
         return initSeparable(avg, avg);
     }
-    
-        /** \brief Init as a 2D Gaussian function with given standard deviation and norm.
-        
-            The function returns a reference to the kernel.
-         */    
+
+        /** Init as a 2D Gaussian function with given standard deviation and norm.
+         */
     void initGaussian(double std_dev, value_type norm)
     {
         Kernel1D<value_type> gauss;
@@ -1019,9 +1020,7 @@ public:
         return initSeparable(gauss, gauss);
     }
 
-        /** \brief Init as a 2D Gaussian function with given standard deviation and unit norm.
-        
-            The function returns a reference to the kernel.
+        /** Init as a 2D Gaussian function with given standard deviation and unit norm.
          */
     void initGaussian(double std_dev)
     {
@@ -1032,7 +1031,7 @@ public:
             calculated as
             <TT>NumericTraits<value_type>::one() / (number of non-zero kernel values)</TT>.
             The kernel's value_type must be a linear space.
-        
+
             <b> Required Interface:</b>
 
             \code
@@ -1092,7 +1091,7 @@ public:
 
         /** Init the kernel by an explicit initializer list.
             The upper left and lower right corners (inclusive) of the kernel must be passed
-            either as <tt>Shape2</tt> or <tt>Diff2D</tt> objects. A comma-separated initializer 
+            either as <tt>Shape2</tt> or <tt>Diff2D</tt> objects. A comma-separated initializer
             list for the kernel's weights is given after the assignment operator like this:
 
             \code
diff --git a/include/vigra/threading.hxx b/include/vigra/threading.hxx
new file mode 100644
index 0000000..fa371ed
--- /dev/null
+++ b/include/vigra/threading.hxx
@@ -0,0 +1,381 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2013-2014 by Ullrich Koethe                  */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_THREADING_HXX
+#define VIGRA_THREADING_HXX
+
+/* Compatibility header to import threading-related functionality from boost
+   when the compiler doesn't yet support C++11.
+*/
+
+    // ignore all threading if VIGRA_SINGLE_THREADED is defined
+#ifndef VIGRA_SINGLE_THREADED
+
+#ifndef VIGRA_NO_STD_THREADING 
+# if defined(__clang__)
+#  if (!__has_include(<thread>) || !__has_include(<mutex>) || !__has_include(<atomic>))
+#    define VIGRA_NO_STD_THREADING
+#  endif
+# else
+#  if defined(__GNUC__) && (!defined(_GLIBCXX_HAS_GTHREADS) || !defined(_GLIBCXX_USE_C99_STDINT_TR1) || !defined(_GLIBCXX_USE_SCHED_YIELD))
+#    define VIGRA_NO_STD_THREADING
+#  endif
+# endif
+
+# if defined(_MSC_VER) && _MSC_VER <= 1600
+#  define VIGRA_NO_STD_THREADING
+# endif
+#endif
+
+#ifdef USE_BOOST_THREAD
+#  include <boost/thread.hpp>
+#  if BOOST_VERSION >= 105300
+#    include <boost/atomic.hpp>
+#    define VIGRA_HAS_ATOMIC 1
+#  endif
+#  define VIGRA_THREADING_NAMESPACE boost
+#elif defined(VIGRA_NO_STD_THREADING)
+#  error "Your compiler does not support std::thread. If the boost libraries are available, consider running cmake with -DWITH_BOOST_THREAD=1"
+#else
+#  include <thread>
+#  include <mutex>
+// #  include <shared_mutex>  // C++14
+#  include <atomic>
+#  define VIGRA_HAS_ATOMIC 1
+#  define VIGRA_THREADING_NAMESPACE std
+#endif
+
+#if defined(_MSC_VER) && !defined(VIGRA_HAS_ATOMIC)
+#  include "windows.h"
+#endif
+
+namespace vigra { namespace threading {
+
+// contents of <thread>
+
+using VIGRA_THREADING_NAMESPACE::thread;
+
+namespace this_thread {
+
+using VIGRA_THREADING_NAMESPACE::this_thread::yield;
+using VIGRA_THREADING_NAMESPACE::this_thread::get_id;
+using VIGRA_THREADING_NAMESPACE::this_thread::sleep_for;
+using VIGRA_THREADING_NAMESPACE::this_thread::sleep_until;
+
+} // namespace this_thread
+
+// contents of <mutex>
+
+using VIGRA_THREADING_NAMESPACE::mutex;
+using VIGRA_THREADING_NAMESPACE::timed_mutex;
+using VIGRA_THREADING_NAMESPACE::recursive_mutex;
+using VIGRA_THREADING_NAMESPACE::recursive_timed_mutex;
+
+using VIGRA_THREADING_NAMESPACE::lock_guard;
+using VIGRA_THREADING_NAMESPACE::unique_lock;
+
+using VIGRA_THREADING_NAMESPACE::defer_lock_t;
+using VIGRA_THREADING_NAMESPACE::try_to_lock_t;
+using VIGRA_THREADING_NAMESPACE::adopt_lock_t;
+
+using VIGRA_THREADING_NAMESPACE::defer_lock;
+using VIGRA_THREADING_NAMESPACE::try_to_lock;
+using VIGRA_THREADING_NAMESPACE::adopt_lock;
+
+using VIGRA_THREADING_NAMESPACE::try_lock;
+using VIGRA_THREADING_NAMESPACE::lock;
+
+using VIGRA_THREADING_NAMESPACE::once_flag;
+using VIGRA_THREADING_NAMESPACE::call_once;
+
+// contents of <shared_mutex>
+
+// using VIGRA_THREADING_NAMESPACE::shared_mutex;   // C++14
+// using VIGRA_THREADING_NAMESPACE::shared_lock;  // C++14
+
+#ifdef VIGRA_HAS_ATOMIC
+
+// contents of <atomic>
+
+using VIGRA_THREADING_NAMESPACE::atomic_flag;
+using VIGRA_THREADING_NAMESPACE::atomic;
+
+using VIGRA_THREADING_NAMESPACE::atomic_char;
+using VIGRA_THREADING_NAMESPACE::atomic_schar;
+using VIGRA_THREADING_NAMESPACE::atomic_uchar;
+using VIGRA_THREADING_NAMESPACE::atomic_short;
+using VIGRA_THREADING_NAMESPACE::atomic_ushort;
+using VIGRA_THREADING_NAMESPACE::atomic_int;
+using VIGRA_THREADING_NAMESPACE::atomic_uint;
+using VIGRA_THREADING_NAMESPACE::atomic_long;
+using VIGRA_THREADING_NAMESPACE::atomic_ulong;
+using VIGRA_THREADING_NAMESPACE::atomic_llong;
+using VIGRA_THREADING_NAMESPACE::atomic_ullong;
+// using VIGRA_THREADING_NAMESPACE::atomic_char16_t; // not in boost
+// using VIGRA_THREADING_NAMESPACE::atomic_char32_t; // not in boost
+using VIGRA_THREADING_NAMESPACE::atomic_wchar_t;
+using VIGRA_THREADING_NAMESPACE::atomic_int_least8_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uint_least8_t;
+using VIGRA_THREADING_NAMESPACE::atomic_int_least16_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uint_least16_t;
+using VIGRA_THREADING_NAMESPACE::atomic_int_least32_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uint_least32_t;
+using VIGRA_THREADING_NAMESPACE::atomic_int_least64_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uint_least64_t;
+using VIGRA_THREADING_NAMESPACE::atomic_int_fast8_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uint_fast8_t;
+using VIGRA_THREADING_NAMESPACE::atomic_int_fast16_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uint_fast16_t;
+using VIGRA_THREADING_NAMESPACE::atomic_int_fast32_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uint_fast32_t;
+using VIGRA_THREADING_NAMESPACE::atomic_int_fast64_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uint_fast64_t;
+using VIGRA_THREADING_NAMESPACE::atomic_intptr_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uintptr_t;
+using VIGRA_THREADING_NAMESPACE::atomic_size_t;
+using VIGRA_THREADING_NAMESPACE::atomic_ptrdiff_t;
+using VIGRA_THREADING_NAMESPACE::atomic_intmax_t;
+using VIGRA_THREADING_NAMESPACE::atomic_uintmax_t;
+
+using VIGRA_THREADING_NAMESPACE::memory_order;
+using VIGRA_THREADING_NAMESPACE::memory_order_relaxed;
+using VIGRA_THREADING_NAMESPACE::memory_order_release;
+using VIGRA_THREADING_NAMESPACE::memory_order_acquire;
+using VIGRA_THREADING_NAMESPACE::memory_order_consume;
+using VIGRA_THREADING_NAMESPACE::memory_order_acq_rel;
+using VIGRA_THREADING_NAMESPACE::memory_order_seq_cst;
+
+using VIGRA_THREADING_NAMESPACE::atomic_thread_fence;
+using VIGRA_THREADING_NAMESPACE::atomic_signal_fence;
+
+// using VIGRA_THREADING_NAMESPACE::atomic_is_lock_free;
+// using VIGRA_THREADING_NAMESPACE::atomic_storeatomic_store_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_loadatomic_load_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_exchangeatomic_exchange_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_weak;
+// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_weak_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_strong;
+// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_strong_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_fetch_addatomic_fetch_add_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_fetch_subatomic_fetch_sub_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_fetch_andatomic_fetch_and_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_fetch_oratomic_fetch_or_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_fetch_xoratomic_fetch_xor_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_flag_test_and_setatomic_flag_test_and_set_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_flag_clearatomic_flag_clear_explicit;
+// using VIGRA_THREADING_NAMESPACE::atomic_init;
+// using VIGRA_THREADING_NAMESPACE::kill_dependency;
+    
+#else  // VIGRA_HAS_ATOMIC not defined
+
+enum memory_order {
+    memory_order_relaxed,
+    memory_order_release,
+    memory_order_acquire,
+    memory_order_consume,
+    memory_order_acq_rel,
+    memory_order_seq_cst
+};
+
+#ifdef _MSC_VER
+
+template <int SIZE=4>
+struct atomic_long_impl
+{
+    typedef LONG value_type;
+    
+    static long load(value_type const & val)
+    {
+        long res = val;
+        MemoryBarrier();
+        return res;
+    }
+    
+    static void store(value_type & dest, long val)
+    {
+        MemoryBarrier();
+        dest = val;
+    }
+    
+    static long add(value_type & dest, long val)
+    {
+        return InterlockedExchangeAdd(&dest, val);
+    }
+    
+    static long sub(value_type & dest, long val)
+    {
+        return InterlockedExchangeAdd(&dest, -val);
+    }
+    
+    static bool compare_exchange(value_type & dest, long & old_val, long new_val)
+    {
+        long check_val = old_val;
+        old_val = InterlockedCompareExchange(&dest, new_val, old_val);
+        return check_val == old_val;
+    }
+};
+
+template <>
+struct atomic_long_impl<8>
+{
+    typedef LONGLONG value_type;
+    
+    static long load(value_type const & val)
+    {
+        long res = val;
+        MemoryBarrier();
+        return res;
+    }
+    
+    static void store(value_type & dest, long val)
+    {
+        MemoryBarrier();
+        dest = val;
+    }
+    
+    static long add(value_type & dest, long val)
+    {
+        return InterlockedExchangeAdd64(&dest, val);
+    }
+    
+    static long sub(value_type & dest, long val)
+    {
+        return InterlockedExchangeAdd64(&dest, -val);
+    }
+    
+    static bool compare_exchange(value_type & dest, long & old_val, long new_val)
+    {
+        long check_val = old_val;
+        old_val = InterlockedCompareExchange64(&dest, new_val, old_val);
+        return check_val == old_val;
+    }
+};
+
+#else
+
+template <int SIZE=4>
+struct atomic_long_impl
+{
+    typedef long value_type;
+    
+    static long load(value_type const & val)
+    {
+        long res = val;
+        __sync_synchronize();
+        return res;
+    }
+    
+    static void store(value_type & dest, long val)
+    {
+        __sync_synchronize();
+        dest = val;
+    }
+    
+    static long add(value_type & dest, long val)
+    {
+        return __sync_fetch_and_add(&dest, val);
+    }
+    
+    static long sub(value_type & dest, long val)
+    {
+        return __sync_fetch_and_sub(&dest, val);
+    }
+    
+    static bool compare_exchange(value_type & dest, long & old_val, long new_val)
+    {
+        long check_val = old_val;
+        old_val = __sync_val_compare_and_swap(&dest, old_val, new_val);
+        return check_val == old_val;
+    }
+};
+
+#endif // _MSC_VER
+
+struct atomic_long
+{
+    typedef atomic_long_impl<sizeof(long)>::value_type value_type;
+    
+    atomic_long(long v = 0)
+    : value_(v)
+    {}
+    
+    atomic_long & operator=(long val)
+    {
+        store(val);
+        return *this;
+    }
+    
+    long load(memory_order = memory_order_seq_cst) const
+    {
+        return atomic_long_impl<sizeof(long)>::load(value_);
+    }
+    
+    void store(long v, memory_order = memory_order_seq_cst)
+    {
+        atomic_long_impl<sizeof(long)>::store(value_, v);
+    }
+    
+    long fetch_add(long v, memory_order = memory_order_seq_cst)
+    {
+        return atomic_long_impl<sizeof(long)>::add(value_, v);
+    }
+    
+    long fetch_sub(long v, memory_order = memory_order_seq_cst)
+    {
+        return atomic_long_impl<sizeof(long)>::sub(value_, v);
+    }
+    
+    bool compare_exchange_strong(long & old_val, long new_val, memory_order = memory_order_seq_cst)
+    {
+        return atomic_long_impl<sizeof(long)>::compare_exchange(value_, old_val, new_val);
+    }
+    
+    bool compare_exchange_weak(long & old_val, long new_val, memory_order = memory_order_seq_cst)
+    {
+        return atomic_long_impl<sizeof(long)>::compare_exchange(value_, old_val, new_val);
+    }
+
+    value_type value_;
+};
+
+#endif // VIGRA_HAS_ATOMIC
+
+}} // namespace vigra::threading
+
+#undef VIGRA_THREADING_NAMESPACE
+
+#endif // not VIGRA_SINGLE_THREADED
+
+#endif // VIGRA_THREADING_HXX
diff --git a/include/vigra/threadpool.hxx b/include/vigra/threadpool.hxx
new file mode 100644
index 0000000..e65545b
--- /dev/null
+++ b/include/vigra/threadpool.hxx
@@ -0,0 +1,665 @@
+/************************************************************************/
+/*                                                                      */
+/*        Copyright 2014-2015 by Thorsten Beier, Philip Schill          */
+/*                               and Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+#ifndef VIGRA_THREADPOOL_HXX
+#define VIGRA_THREADPOOL_HXX
+
+#include <functional>
+#include <thread>
+#include <atomic>
+#include <vector>
+#include <future>
+#include <mutex>
+#include <queue>
+#include <condition_variable>
+#include <stdexcept>
+#include <cmath>
+#include "mathutil.hxx"
+#include "counting_iterator.hxx"
+
+
+namespace vigra
+{
+
+/** \addtogroup ParallelProcessing Functions and classes for parallel processing.
+*/
+
+//@{
+
+    /**\brief Option base class for parallel algorithms.
+
+        <b>\#include</b> \<vigra/threadpool.hxx\><br>
+        Namespace: vigra
+    */
+class ParallelOptions
+{
+  public:
+
+        /** Constants for special settings.
+        */
+    enum {
+        Auto       = -1, ///< Determine number of threads automatically (from <tt>std::thread::hardware_concurrency()</tt>)
+        Nice       = -2, ///< Use half as many threads as <tt>Auto</tt> would.
+        NoThreads  =  0  ///< Switch off multi-threading (i.e. execute tasks sequentially)
+    };
+
+    ParallelOptions()
+    :   numThreads_(actualNumThreads(Auto))
+    {}
+
+        /** \brief Get desired number of threads.
+
+            <b>Note:</b> This function may return 0, which means that multi-threading
+            shall be switched off entirely. If an algorithm receives this value,
+            it should revert to a sequential implementation. In contrast, if
+            <tt>numThread() == 1</tt>, the parallel algorithm version shall be
+            executed with a single thread.
+        */
+    int getNumThreads() const
+    {
+        return numThreads_;
+    }
+
+        /** \brief Get desired number of threads.
+
+            In contrast to <tt>numThread()</tt>, this will always return a value <tt>>=1</tt>.
+        */
+    int getActualNumThreads() const
+    {
+        return std::max(1,numThreads_);
+    }
+
+        /** \brief Set the number of threads or one of the constants <tt>Auto</tt>,
+                   <tt>Nice</tt> and <tt>NoThreads</tt>.
+
+            Default: <tt>ParallelOptions::Auto</tt> (use system default)
+
+            This setting is ignored if the preprocessor flag <tt>VIGRA_SINGLE_THREADED</tt>
+            is defined. Then, the number of threads is set to 0 and all tasks revert to
+            sequential algorithm implementations. The same can be achieved at runtime
+            by passing <tt>n = 0</tt> to this function. In contrast, passing <tt>n = 1</tt>
+            causes the parallel algorithm versions to be executed with a single thread.
+            Both possibilities are mainly useful for debugging.
+        */
+    ParallelOptions & numThreads(const int n)
+    {
+        numThreads_ = actualNumThreads(n);
+        return *this;
+    }
+
+
+  private:
+        // helper function to compute the actual number of threads
+    static size_t actualNumThreads(const int userNThreads)
+    {
+        #ifdef VIGRA_SINGLE_THREADED
+            return 0;
+        #else
+            return userNThreads >= 0
+                       ? userNThreads
+                       : userNThreads == Nice
+                               ? std::thread::hardware_concurrency() / 2
+                               : std::thread::hardware_concurrency();
+        #endif
+    }
+
+    int numThreads_;
+};
+
+/********************************************************/
+/*                                                      */
+/*                      ThreadPool                      */
+/*                                                      */
+/********************************************************/
+
+    /**\brief Thread pool class to manage a set of parallel workers.
+
+        <b>\#include</b> \<vigra/threadpool.hxx\><br>
+        Namespace: vigra
+    */
+class ThreadPool
+{
+  public:
+
+    /** Create a thread pool from ParallelOptions. The constructor just launches
+        the desired number of workers. If the number of threads is zero,
+        no workers are started, and all tasks will be executed in synchronously
+        in the present thread.
+     */
+    ThreadPool(const ParallelOptions & options)
+    :   stop(false),
+        busy(0),
+        processed(0)
+    {
+        init(options);
+    }
+
+    /** Create a thread pool with n threads. The constructor just launches
+        the desired number of workers. If \arg n is <tt>ParallelOptions::Auto</tt>,
+        the number of threads is determined by <tt>std::thread::hardware_concurrency()</tt>.
+        <tt>ParallelOptions::Nice</tt> will create half as many threads.
+        If <tt>n = 0</tt>, no workers are started, and all tasks will be executed
+        synchronously in the present thread. If the preprocessor flag
+        <tt>VIGRA_SINGLE_THREADED</tt> is defined, the number of threads is always set
+        to zero (i.e. synchronous execution), regardless of the value of \arg n. This
+        is useful for debugging.
+     */
+    ThreadPool(const int n)
+    :   stop(false),
+        busy(0),
+        processed(0)
+    {
+        init(ParallelOptions().numThreads(n));
+    }
+
+    /**
+     * The destructor joins all threads.
+     */
+    ~ThreadPool();
+
+    /**
+     * Enqueue a task that will be executed by the thread pool.
+     * The task result can be obtained using the get() function of the returned future.
+     * If the task throws an exception, it will be raised on the call to get().
+     */
+    template<class F>
+    std::future<typename std::result_of<F(int)>::type>  enqueueReturning(F&& f) ;
+
+    /**
+     * Enqueue function for tasks without return value.
+     * This is a special case of the enqueueReturning template function, but
+     * some compilers fail on <tt>std::result_of<F(int)>::type</tt> for void(int) functions.
+     */
+    template<class F>
+    std::future<void> enqueue(F&& f) ;
+
+    /**
+     * Block until all tasks are finished.
+     */
+    void waitFinished()
+    {
+        std::unique_lock<std::mutex> lock(queue_mutex);
+        finish_condition.wait(lock, [this](){ return tasks.empty() && (busy == 0); });
+    }
+
+    /**
+     * Return the number of worker threads.
+     */
+    size_t nThreads() const
+    {
+        return workers.size();
+    }
+
+private:
+
+    // helper function to init the thread pool
+    void init(const ParallelOptions & options);
+
+    // need to keep track of threads so we can join them
+    std::vector<std::thread> workers;
+
+    // the task queue
+    std::queue<std::function<void(int)> > tasks;
+
+    // synchronization
+    std::mutex queue_mutex;
+    std::condition_variable worker_condition;
+    std::condition_variable finish_condition;
+    bool stop;
+    std::atomic<unsigned int> busy, processed;
+};
+
+inline void ThreadPool::init(const ParallelOptions & options)
+{
+    const size_t actualNThreads = options.getNumThreads();
+    for(size_t ti = 0; ti<actualNThreads; ++ti)
+    {
+        workers.emplace_back(
+            [ti,this]
+            {
+                for(;;)
+                {
+                    std::function<void(int)> task;
+                    {
+                        std::unique_lock<std::mutex> lock(this->queue_mutex);
+
+                        // will wait if : stop == false  AND queue is empty
+                        // if stop == true AND queue is empty thread function will return later
+                        //
+                        // so the idea of this wait, is : If where are not in the destructor
+                        // (which sets stop to true, we wait here for new jobs)
+                        this->worker_condition.wait(lock, [this]{ return this->stop || !this->tasks.empty(); });
+                        if(!this->tasks.empty())
+                        {
+                            ++busy;
+                            task = std::move(this->tasks.front());
+                            this->tasks.pop();
+                            lock.unlock();
+                            task(ti);
+                            ++processed;
+                            --busy;
+                            finish_condition.notify_one();
+                        }
+                        else if(stop)
+                        {
+                            return;
+                        }
+                    }
+                }
+            }
+        );
+    }
+}
+
+inline ThreadPool::~ThreadPool()
+{
+    {
+        std::unique_lock<std::mutex> lock(queue_mutex);
+        stop = true;
+    }
+    worker_condition.notify_all();
+    for(std::thread &worker: workers)
+        worker.join();
+}
+
+template<class F>
+inline std::future<typename std::result_of<F(int)>::type>
+ThreadPool::enqueueReturning(F&& f)
+{
+    typedef typename std::result_of<F(int)>::type result_type;
+    typedef std::packaged_task<result_type(int)> PackageType;
+
+    auto task = std::make_shared<PackageType>(f);
+    auto res = task->get_future();
+
+    if(workers.size()>0){
+        {
+            std::unique_lock<std::mutex> lock(queue_mutex);
+
+            // don't allow enqueueing after stopping the pool
+            if(stop)
+                throw std::runtime_error("enqueue on stopped ThreadPool");
+
+            tasks.emplace(
+                [task](int tid)
+                {
+                    (*task)(tid);
+                }
+            );
+        }
+        worker_condition.notify_one();
+    }
+    else{
+        (*task)(0);
+    }
+
+    return res;
+}
+
+template<class F>
+inline std::future<void>
+ThreadPool::enqueue(F&& f)
+{
+    typedef std::packaged_task<void(int)> PackageType;
+
+    auto task = std::make_shared<PackageType>(f);
+    auto res = task->get_future();
+    if(workers.size()>0){
+        {
+            std::unique_lock<std::mutex> lock(queue_mutex);
+
+            // don't allow enqueueing after stopping the pool
+            if(stop)
+                throw std::runtime_error("enqueue on stopped ThreadPool");
+
+            tasks.emplace(
+                [task](int tid)
+                {
+                    (*task)(tid);
+                }
+            );
+        }
+        worker_condition.notify_one();
+    }
+    else{
+        (*task)(0);
+    }
+    return res;
+}
+
+/********************************************************/
+/*                                                      */
+/*                   parallel_foreach                   */
+/*                                                      */
+/********************************************************/
+
+// nItems must be either zero or std::distance(iter, end).
+template<class ITER, class F>
+inline void parallel_foreach_impl(
+    ThreadPool & pool,
+    const std::ptrdiff_t nItems,
+    ITER iter,
+    ITER end,
+    F && f,
+    std::random_access_iterator_tag
+){
+    std::ptrdiff_t workload = std::distance(iter, end);
+    vigra_precondition(workload == nItems || nItems == 0, "parallel_foreach(): Mismatch between num items and begin/end.");
+    const float workPerThread = float(workload)/pool.nThreads();
+    const std::ptrdiff_t chunkedWorkPerThread = std::max<std::ptrdiff_t>(roundi(workPerThread/3.0), 1);
+
+    std::vector<std::future<void> > futures;
+    for( ;iter<end; iter+=chunkedWorkPerThread)
+    {
+        const size_t lc = std::min(workload, chunkedWorkPerThread);
+        workload-=lc;
+        futures.emplace_back(
+            pool.enqueue(
+                [&f, iter, lc]
+                (int id)
+                {
+                    for(size_t i=0; i<lc; ++i)
+                        f(id, iter[i]);
+                }
+            )
+        );
+    }
+    for (auto & fut : futures)
+    {
+        fut.get();
+    }
+}
+
+
+
+// nItems must be either zero or std::distance(iter, end).
+template<class ITER, class F>
+inline void parallel_foreach_impl(
+    ThreadPool & pool,
+    const std::ptrdiff_t nItems,
+    ITER iter,
+    ITER end,
+    F && f,
+    std::forward_iterator_tag
+){
+    if (nItems == 0)
+        nItems = std::distance(iter, end);
+
+    std::ptrdiff_t workload = nItems;
+    const float workPerThread = float(workload)/pool.nThreads();
+    const std::ptrdiff_t chunkedWorkPerThread = std::max<std::ptrdiff_t>(roundi(workPerThread/3.0), 1);
+
+    std::vector<std::future<void> > futures;
+    for(;;)
+    {
+        const size_t lc = std::min(chunkedWorkPerThread, workload);
+        workload -= lc;
+        futures.emplace_back(
+            pool.enqueue(
+                [&f, iter, lc]
+                (int id)
+                {
+                    auto iterCopy = iter;
+                    for(size_t i=0; i<lc; ++i){
+                        f(id, *iterCopy);
+                        ++iterCopy;
+                    }
+                }
+            )
+        );
+        for (size_t i = 0; i < lc; ++i)
+        {
+            ++iter;
+            if (iter == end)
+            {
+                vigra_postcondition(workload == 0, "parallel_foreach(): Mismatch between num items and begin/end.");
+                break;
+            }
+        }
+        if(workload==0)
+            break;
+    }
+    for (auto & fut : futures)
+        fut.get();
+}
+
+
+
+// nItems must be either zero or std::distance(iter, end).
+template<class ITER, class F>
+inline void parallel_foreach_impl(
+    ThreadPool & pool,
+    const std::ptrdiff_t nItems,
+    ITER iter,
+    ITER end,
+    F && f,
+    std::input_iterator_tag
+){
+    size_t num_items = 0;
+    std::vector<std::future<void> > futures;
+    for (; iter != end; ++iter)
+    {
+        auto item = *iter;
+        futures.emplace_back(
+            pool.enqueue(
+                [&f, &item](int id){
+                    f(id, item);
+                }
+            )
+        );
+        ++num_items;
+    }
+    vigra_postcondition(num_items == nItems || nItems == 0, "parallel_foreach(): Mismatch between num items and begin/end.");
+    for (auto & fut : futures)
+        fut.get();
+}
+
+// Runs foreach on a single thread.
+// Used for API compatibility when the numbe of threads is 0.
+template<class ITER, class F>
+inline void parallel_foreach_single_thread(
+    ITER begin,
+    ITER end,
+    F && f,
+    const std::ptrdiff_t nItems = 0
+){
+    size_t n = 0;
+    for (; begin != end; ++begin)
+    {
+        f(0, *begin);
+        ++n;
+    }
+    vigra_postcondition(n == nItems || nItems == 0, "parallel_foreach(): Mismatch between num items and begin/end.");
+}
+
+/** \brief Apply a functor to all items in a range in parallel.
+
+    Create a thread pool (or use an existing one) to apply the functor \arg f
+    to all items in the range <tt>[begin, end)</tt> in parallel. \arg f must
+    be callable with two arguments of type <tt>size_t</tt> and <tt>T</tt>, where
+    the first argument is the thread index (starting at 0) and T is convertible
+    from the iterator's <tt>reference_type</tt> (i.e. the result of <tt>*begin</tt>).
+
+    If the iterators are forward iterators (<tt>std::forward_iterator_tag</tt>), you
+    can provide the optional argument <tt>nItems</tt> to avoid the a
+    <tt>std::distance(begin, end)</tt> call to compute the range's length.
+
+    Parameter <tt>nThreads</tt> controls the number of threads. <tt>parallel_foreach</tt>
+    will split the work into about three times as many parallel tasks.
+    If <tt>nThreads = ParallelOptions::Auto</tt>, the number of threads is set to
+    the machine default (<tt>std::thread::hardware_concurrency()</tt>).
+
+    If <tt>nThreads = 0</tt>, the function will not use threads,
+    but will call the functor sequentially. This can also be enforced by setting the
+    preprocessor flag <tt>VIGRA_SINGLE_THREADED</tt>, ignoring the value of
+    <tt>nThreads</tt> (useful for debugging).
+
+    <b> Declarations:</b>
+
+    \code
+    namespace vigra {
+        // pass the desired number of threads or ParallelOptions::Auto
+        // (creates an internal thread pool accordingly)
+        template<class ITER, class F>
+        void parallel_foreach(int64_t nThreads,
+                              ITER begin, ITER end,
+                              F && f,
+                              const uint64_t nItems = 0);
+
+        // use an existing thread pool
+        template<class ITER, class F>
+        void parallel_foreach(ThreadPool & pool,
+                              ITER begin, ITER end,
+                              F && f,
+                              const uint64_t nItems = 0);
+
+        // pass the integers from 0 ... (nItems-1) to the functor f,
+        // using the given number of threads or ParallelOptions::Auto
+        template<class F>
+        void parallel_foreach(int64_t nThreads,
+                              uint64_t nItems,
+                              F && f);
+
+        // likewise with an existing thread pool
+        template<class F>
+        void parallel_foreach(ThreadPool & threadpool,
+                              uint64_t nItems,
+                              F && f);
+    }
+    \endcode
+
+    <b>Usage:</b>
+
+    \code
+    #include <iostream>
+    #include <algorithm>
+    #include <vector>
+    #include <vigra/threadpool.hxx>
+
+    using namespace std;
+    using namespace vigra;
+
+    int main()
+    {
+        size_t const n_threads = 4;
+        size_t const n = 2000;
+        vector<int> input(n);
+
+        auto iter = input.begin(),
+             end  = input.end();
+
+        // fill input with 0, 1, 2, ...
+        iota(iter, end, 0);
+
+        // compute the sum of the elements in the input vector.
+        // (each thread computes the partial sum of the items it sees
+        //  and stores the sum at the appropriate index of 'results')
+        vector<int> results(n_threads, 0);
+        parallel_foreach(n_threads, iter, end,
+            // the functor to be executed, defined as a lambda function
+            // (first argument: thread ID, second argument: result of *iter)
+            [&results](size_t thread_id, int items)
+            {
+                results[thread_id] += items;
+            }
+        );
+
+        // collect the partial sums of all threads
+        int sum = accumulate(results.begin(), results.end(), 0);
+
+        cout << "The sum " << sum << " should be equal to " << (n*(n-1))/2 << endl;
+    }
+    \endcode
+ */
+doxygen_overloaded_function(template <...> void parallel_foreach)
+
+template<class ITER, class F>
+inline void parallel_foreach(
+    ThreadPool & pool,
+    ITER begin,
+    ITER end,
+    F && f,
+    const std::ptrdiff_t nItems = 0)
+{
+    if(pool.nThreads()>1)
+    {
+        parallel_foreach_impl(pool,nItems, begin, end, f,
+            typename std::iterator_traits<ITER>::iterator_category());
+    }
+    else
+    {
+        parallel_foreach_single_thread(begin, end, f, nItems);
+    }
+}
+
+template<class ITER, class F>
+inline void parallel_foreach(
+    int64_t nThreads,
+    ITER begin,
+    ITER end,
+    F && f,
+    const std::ptrdiff_t nItems = 0)
+{
+
+    ThreadPool pool(nThreads);
+    parallel_foreach(pool, begin, end, f, nItems);
+}
+
+template<class F>
+inline void parallel_foreach(
+    int64_t nThreads,
+    std::ptrdiff_t nItems,
+    F && f)
+{
+    auto iter = range(nItems);
+    parallel_foreach(nThreads, iter, iter.end(), f, nItems);
+}
+
+
+template<class F>
+inline void parallel_foreach(
+    ThreadPool & threadpool,
+    std::ptrdiff_t nItems,
+    F && f)
+{
+    auto iter = range(nItems);
+    parallel_foreach(threadpool, iter, iter.end(), f, nItems);
+}
+
+//@}
+
+} // namespace vigra
+
+#endif // VIGRA_THREADPOOL_HXX
diff --git a/include/vigra/tinyvector.hxx b/include/vigra/tinyvector.hxx
index 1f9d53f..cfa64e8 100644
--- a/include/vigra/tinyvector.hxx
+++ b/include/vigra/tinyvector.hxx
@@ -54,6 +54,7 @@ struct Invalid;
 #include "memory.hxx"
 #include "mathutil.hxx"
 #include "diff2d.hxx"
+#include "static_assert.hxx"
 
 #ifdef VIGRA_CHECK_BOUNDS
 #define VIGRA_ASSERT_INSIDE(diff) \
@@ -158,9 +159,11 @@ struct ExecLoop
     VIGRA_EXEC_LOOP(sqrt, = vigra::sqrt)
     VIGRA_EXEC_LOOP(fromPromote, = NumericTraits<T1>::fromPromote)
     VIGRA_EXEC_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote)
+    VIGRA_EXEC_LOOP_SCALAR(addScalar, +)
+    VIGRA_EXEC_LOOP_SCALAR(subScalar, -)
     VIGRA_EXEC_LOOP_SCALAR(mulScalar, *)
     VIGRA_EXEC_LOOP_SCALAR(divScalar, /)
-    
+
     VIGRA_EXEC_LOOP_MINMAX(min, >)
     VIGRA_EXEC_LOOP_MINMAX(max, <)
 
@@ -204,7 +207,7 @@ struct ExecLoop
     }
 
     template <class T1, class T2>
-    static bool less(T1 const * left, T2 const * right)
+    static bool lexicographicLessThan(T1 const * left, T2 const * right)
     {
         for(int i=0; i<LEVEL; ++i)
         {
@@ -215,7 +218,7 @@ struct ExecLoop
         }
         return false;
     }
-    
+
     template <class T>
     static bool closeAtTolerance(T const * left, T const * right, T epsilon)
     {
@@ -226,7 +229,7 @@ struct ExecLoop
         }
         return res;
     }
-    
+
     template <class T>
     static typename NumericTraits<T>::Promote
     dot(T const * d)
@@ -274,7 +277,7 @@ struct UnrollScalarResult
     {
         return *left * *right + UnrollScalarResult<LEVEL-1>::dot(left+1, right+1);
     }
-    
+
     template <class T>
     static typename NormTraits<T>::SquaredNormType
     squaredNorm(T const * d)
@@ -287,7 +290,7 @@ struct UnrollScalarResult
     {
         return (*d)*(*d) + UnrollScalarResult<LEVEL-1>::squaredNorm(d+1);
     }
-    
+
     template <class T>
     static T const & minimum(T const * p)
     {
@@ -449,9 +452,11 @@ struct UnrollLoop
     VIGRA_UNROLL_LOOP(sqrt, = vigra::sqrt)
     VIGRA_UNROLL_LOOP(fromPromote, = NumericTraits<T1>::fromPromote)
     VIGRA_UNROLL_LOOP(fromRealPromote, = NumericTraits<T1>::fromRealPromote)
+    VIGRA_UNROLL_LOOP_SCALAR(addScalar, +)
+    VIGRA_UNROLL_LOOP_SCALAR(subScalar, -)
     VIGRA_UNROLL_LOOP_SCALAR(mulScalar, *)
     VIGRA_UNROLL_LOOP_SCALAR(divScalar, /)
-    
+
     VIGRA_UNROLL_LOOP_MINMAX(min, >)
     VIGRA_UNROLL_LOOP_MINMAX(max, <)
 
@@ -486,22 +491,22 @@ struct UnrollLoop
     }
 
     template <class T1, class T2>
-    static bool less(T1 const * left, T2 const * right)
+    static bool lexicographicLessThan(T1 const * left, T2 const * right)
     {
         if(*left < *right)
             return true;
         if(*right < *left)
             return false;
-        return UnrollLoop<LEVEL - 1>::less(left+1, right+1);
+        return UnrollLoop<LEVEL - 1>::lexicographicLessThan(left+1, right+1);
     }
 
     template <class T>
     static bool closeAtTolerance(T const * left, T const * right, T epsilon)
     {
-        return vigra::closeAtTolerance(*left, *right, epsilon) && 
+        return vigra::closeAtTolerance(*left, *right, epsilon) &&
                   UnrollLoop<LEVEL - 1>::closeAtTolerance(left+1, right+1, epsilon);
     }
-    
+
     template <class T>
     static typename NumericTraits<T>::Promote
     dot(T const * d)
@@ -544,8 +549,12 @@ struct UnrollLoop<0>
     template <class T1, class T2>
     static void add(T1, T2) {}
     template <class T1, class T2>
+    static void addScalar(T1, T2) {}
+    template <class T1, class T2>
     static void sub(T1, T2) {}
     template <class T1, class T2>
+    static void subScalar(T1, T2) {}
+    template <class T1, class T2>
     static void mul(T1, T2) {}
     template <class T1, class T2>
     static void mulScalar(T1, T2) {}
@@ -574,7 +583,7 @@ struct UnrollLoop<0>
     template <class T1, class T2>
     static bool notEqual(T1, T2) { return false; }
     template <class T1, class T2>
-    static bool less(T1, T2) { return false; }
+    static bool lexicographicLessThan(T1, T2) { return false; }
     template <class T1, class T2>
     static void min(T1, T2) {}
     template <class T1, class T2>
@@ -757,6 +766,22 @@ class TinyVectorBase
 
         /** Component-wise scalar multiply-assignment
         */
+    DERIVED & operator+=(double r)
+    {
+        Loop::addScalar(data_, r);
+        return static_cast<DERIVED &>(*this);
+    }
+
+        /** Component-wise scalar divide-assignment
+        */
+    DERIVED & operator-=(double r)
+    {
+        Loop::subScalar(data_, r);
+        return static_cast<DERIVED &>(*this);
+    }
+
+        /** Component-wise scalar multiply-assignment
+        */
     DERIVED & operator*=(double r)
     {
         Loop::mulScalar(data_, r);
@@ -771,15 +796,16 @@ class TinyVectorBase
         return static_cast<DERIVED &>(*this);
     }
 
-        /** Calculate magnitude.
-        */
+        /** Calculate magnitude (i.e. 2-norm / Euclidean norm / length).
+         * \see squaredMagnitude()
+         */
     NormType magnitude() const
     {
          return sqrt(static_cast<typename
               SquareRootTraits<SquaredNormType>::SquareRootArgument>(squaredMagnitude()));
     }
 
-        /** Calculate squared magnitude.
+        /** Calculate squared magnitude (i.e. sum of squared elements).
         */
     SquaredNormType squaredMagnitude() const
     {
@@ -799,14 +825,14 @@ class TinyVectorBase
     {
         return Loop::maximum(data_);
     }
-    
+
         /** Check that all elements of this vector are non-zero (or 'true' if T is bool).
         */
     bool all() const
     {
         return Loop::all(data_, VALUETYPE());
     }
-    
+
         /** Check that at least one element of this vector is non-zero (or 'true' if T is bool).
         */
     bool any() const
@@ -844,7 +870,15 @@ class TinyVectorBase
         /** Get const random access iterator past-the-end of vector.
         */
     const_iterator end() const { return data_ + SIZE; }
-    
+
+        /** Get const random access iterator to begin of vector.
+        */
+    const_iterator cbegin() const { return data_; }
+
+        /** Get const random access iterator past-the-end of vector.
+        */
+    const_iterator cend() const { return data_ + SIZE; }
+
         /** Get a view to the subarray with length <tt>(TO-FROM)</tt> starting at <tt>FROM</tt>.
             The bounds must fullfill <tt>0 <= FROM < TO <= SIZE</tt>, but this is only
             checked when <tt>VIGRA_CHECK_BOUNDS</tt> is \#define'd.
@@ -860,6 +894,20 @@ class TinyVectorBase
         return TinyVectorView<VALUETYPE, TO-FROM>(data_+FROM);
     }
 
+    TinyVector<VALUETYPE, SIZE-1>
+    dropIndex(int m) const
+    {
+#ifdef VIGRA_CHECK_BOUNDS
+        vigra_precondition(0 <= m && m < SIZE, "Dimension out of bounds");
+#endif
+        TinyVector<VALUETYPE, SIZE-1> res(SkipInitialization);
+        for(int k=0; k<m; ++k)
+            res[k] = data_[k];
+        for(int k=m; k<SIZE-1; ++k)
+            res[k] = data_[k+1];
+        return res;
+    }
+
         /** Size of TinyVector vector always equals the template parameter SIZE.
         */
     size_type size() const { return SIZE; }
@@ -867,7 +915,29 @@ class TinyVectorBase
     pointer data() { return data_; }
 
     const_pointer data() const { return data_; }
-    
+
+    reference front()
+    {
+        return data_[0];
+    }
+
+    const_reference front() const
+    {
+        return data_[0];
+    }
+
+    reference back()
+    {
+        return data_[SIZE-1];
+    }
+
+    const_reference back() const
+    {
+        return data_[SIZE-1];
+    }
+
+        /** \brief Factory function for a unit vector for dimension \a k.
+        */
     static TinyVector<VALUETYPE, SIZE> unitVector(int k)
     {
         VIGRA_ASSERT_INSIDE(k);
@@ -876,11 +946,34 @@ class TinyVectorBase
         return ret;
     }
 
+        /** \brief Factory function for a linear sequence.
+
+            The result will be initialized as <tt>res[k] = start + k*step</tt>.
+        */
+    static TinyVector<VALUETYPE, SIZE> linearSequence(VALUETYPE start=VALUETYPE(), VALUETYPE step=VALUETYPE(1))
+    {
+        TinyVector<VALUETYPE, SIZE> ret(SkipInitialization);
+        for(int k=0; k<SIZE; ++k, start+=step)
+            ret[k] = start;
+        return ret;
+    }
+
   protected:
-  
+
     DATA data_;
 };
 
+#ifndef DOXYGEN
+
+template <int SIZE, int DESIRED_SIZE>
+struct TinyVector_constructor_has_wrong_number_of_arguments
+: staticAssert::AssertBool<SIZE == DESIRED_SIZE>
+{};
+
+#endif /* DOXYGEN */
+
+enum ReverseCopyTag { ReverseCopy };
+
 /** \brief Class for fixed size vectors.
     \ingroup RangesAndPoints
 
@@ -930,11 +1023,9 @@ class TinyVector
     typedef typename BaseType::scalar_multiplier scalar_multiplier;
     typedef typename BaseType::SquaredNormType SquaredNormType;
     typedef typename BaseType::NormType NormType;
-    
-    enum ReverseCopyTag { ReverseCopy };
 
         /** Construction with constant value.
-        
+
             Initializes all vector elements with the given value.
         */
     explicit TinyVector(value_type const & initial)
@@ -944,7 +1035,7 @@ class TinyVector
     }
 
         /** Construction from lemon::Invalid.
-        
+
             Initializes all vector elements with -1.
         */
     TinyVector(lemon::Invalid const &)
@@ -954,7 +1045,7 @@ class TinyVector
     }
 
         /** Construction with Diff2D.
-        
+
             Use only when <tt>SIZE == 2</tt>.
         */
     explicit TinyVector(Diff2D const & initial)
@@ -970,6 +1061,7 @@ class TinyVector
     TinyVector(value_type const & i1, value_type const & i2)
     : BaseType()
     {
+        VIGRA_STATIC_ASSERT((TinyVector_constructor_has_wrong_number_of_arguments<SIZE, 2>));
         BaseType::data_[0] = i1;
         BaseType::data_[1] = i2;
     }
@@ -980,6 +1072,7 @@ class TinyVector
     TinyVector(value_type const & i1, value_type const & i2, value_type const & i3)
     : BaseType()
     {
+        VIGRA_STATIC_ASSERT((TinyVector_constructor_has_wrong_number_of_arguments<SIZE, 3>));
         BaseType::data_[0] = i1;
         BaseType::data_[1] = i2;
         BaseType::data_[2] = i3;
@@ -992,6 +1085,7 @@ class TinyVector
                value_type const & i3, value_type const & i4)
     : BaseType()
     {
+        VIGRA_STATIC_ASSERT((TinyVector_constructor_has_wrong_number_of_arguments<SIZE, 4>));
         BaseType::data_[0] = i1;
         BaseType::data_[1] = i2;
         BaseType::data_[2] = i3;
@@ -1006,13 +1100,14 @@ class TinyVector
                value_type const & i5)
     : BaseType()
     {
+        VIGRA_STATIC_ASSERT((TinyVector_constructor_has_wrong_number_of_arguments<SIZE, 5>));
         BaseType::data_[0] = i1;
         BaseType::data_[1] = i2;
         BaseType::data_[2] = i3;
         BaseType::data_[3] = i4;
         BaseType::data_[4] = i5;
     }
-    
+
        /** Default constructor (initializes all elements with zero).
         */
     TinyVector()
@@ -1049,7 +1144,7 @@ class TinyVector
     }
 
         /** Constructor by reverse copy from C array.
-            
+
             Usage:
             \code
             TinyVector<int, 3> v(1,2,3);
@@ -1089,7 +1184,7 @@ class TinyVector
     }
 
         /** Assignment from Diff2D.
-        
+
             Use only when <tt>SIZE == 2</tt>.
         */
     TinyVector & operator=(Diff2D const & r)
@@ -1108,7 +1203,7 @@ class TinyVector
     }
 
         /** Copy from a TinyVector with a different number of elements.
-        
+
             Only the first <tt>min(SIZE, USIZE)</tt> elements are copied.
         */
     template <class U, int USIZE, class DATA, class DERIVED>
@@ -1117,7 +1212,7 @@ class TinyVector
         static const int minSize = USIZE < SIZE
                                         ? USIZE
                                         : SIZE;
-        
+
         typedef typename detail::LoopType<minSize>::type MinLoop;
         MinLoop::assignCast(BaseType::data_, r.begin());
         return *this;
@@ -1267,16 +1362,65 @@ operator!=(TinyVectorBase<V1, SIZE, D1, D2> const & l,
 template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4>
 inline bool
 operator<(TinyVectorBase<V1, SIZE, D1, D2> const & l,
-          TinyVectorBase<V2, SIZE, D3, D4> const & r)
+                      TinyVectorBase<V2, SIZE, D3, D4> const & r)
 {
     typedef typename detail::LoopType<SIZE>::type ltype;
-    return ltype::less(l.begin(), r.begin());
+    return ltype::lexicographicLessThan(l.begin(), r.begin());
+}
+
+
+    /// pointwise less-than
+template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4>
+inline bool
+allLess(TinyVectorBase<V1, SIZE, D1, D2> const & l,
+        TinyVectorBase<V2, SIZE, D3, D4> const & r)
+{
+    for(int k=0; k < SIZE; ++k)
+        if (l[k] >= r[k])
+            return false;
+    return true;
+}
+
+    /// pointwise greater-than
+template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4>
+inline bool
+allGreater(TinyVectorBase<V1, SIZE, D1, D2> const & l,
+           TinyVectorBase<V2, SIZE, D3, D4> const & r)
+{
+    for(int k=0; k < SIZE; ++k)
+        if(l[k] <= r[k])
+            return false;
+    return true;
+}
+
+    /// pointwise less-equal
+template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4>
+inline bool
+allLessEqual(TinyVectorBase<V1, SIZE, D1, D2> const & l,
+             TinyVectorBase<V2, SIZE, D3, D4> const & r)
+{
+    for(int k=0; k < SIZE; ++k)
+        if (l[k] > r[k])
+            return false;
+    return true;
+}
+
+    /// pointwise greater-equal
+template <class V1, int SIZE, class D1, class D2, class V2, class D3, class D4>
+inline bool
+allGreaterEqual(TinyVectorBase<V1, SIZE, D1, D2> const & l,
+                TinyVectorBase<V2, SIZE, D3, D4> const & r)
+{
+    for(int k=0; k < SIZE; ++k)
+        if (l[k] < r[k])
+            return false;
+    return true;
 }
 
 template <class V, int SIZE, class D1, class D2, class D3, class D4>
-bool 
+bool
 closeAtTolerance(TinyVectorBase<V, SIZE, D1, D2> const & l,
-                 TinyVectorBase<V, SIZE, D3, D4> const & r, 
+                 TinyVectorBase<V, SIZE, D3, D4> const & r,
                  V epsilon = NumericTraits<V>::epsilon())
 {
     typedef typename detail::LoopType<SIZE>::type ltype;
@@ -1284,9 +1428,9 @@ closeAtTolerance(TinyVectorBase<V, SIZE, D1, D2> const & l,
 }
 
 template <class V, int SIZE>
-bool 
+bool
 closeAtTolerance(TinyVector<V, SIZE> const & l,
-                 TinyVector<V, SIZE> const & r, 
+                 TinyVector<V, SIZE> const & r,
                  V epsilon = NumericTraits<V>::epsilon())
 {
     typedef typename detail::LoopType<SIZE>::type ltype;
@@ -1707,6 +1851,42 @@ operator%(TinyVectorBase<V1, SIZE, D1, D2> const & l,
     return typename PromoteTraits<TinyVector<V1, SIZE>, TinyVector<V2 , SIZE> >::Promote(l) %= r;
 }
 
+    /// component-wise left scalar addition
+template <class V, int SIZE, class D1, class D2>
+inline
+typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
+operator+(double v, TinyVectorBase<V, SIZE, D1, D2> const & r)
+{
+    return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(r) += v;
+}
+
+    /// component-wise right scalar addition
+template <class V, int SIZE, class D1, class D2>
+inline
+typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
+operator+(TinyVectorBase<V, SIZE, D1, D2> const & l, double v)
+{
+    return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(l) += v;
+}
+
+    /// component-wise left scalar subtraction
+template <class V, int SIZE, class D1, class D2>
+inline
+typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
+operator-(double v, TinyVectorBase<V, SIZE, D1, D2> const & r)
+{
+    return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(v) -= r;
+}
+
+    /// component-wise right scalar subtraction
+template <class V, int SIZE, class D1, class D2>
+inline
+typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
+operator-(TinyVectorBase<V, SIZE, D1, D2> const & l, double v)
+{
+    return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(l) -= v;
+}
+
     /// component-wise left scalar multiplication
 template <class V, int SIZE, class D1, class D2>
 inline
@@ -1725,7 +1905,16 @@ operator*(TinyVectorBase<V, SIZE, D1, D2> const & l, double v)
     return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(l) *= v;
 }
 
-    /// component-wise scalar division
+    /// component-wise left scalar division
+template <class V, int SIZE, class D1, class D2>
+inline
+typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
+operator/(double v, TinyVectorBase<V, SIZE, D1, D2> const & r)
+{
+    return typename NumericTraits<TinyVector<V, SIZE> >::RealPromote(v) /= r;
+}
+
+    /// component-wise right scalar division
 template <class V, int SIZE, class D1, class D2>
 inline
 typename NumericTraits<TinyVector<V, SIZE> >::RealPromote
@@ -1811,6 +2000,19 @@ round(TinyVectorBase<V, SIZE, D1, D2> const & v)
     return res;
 }
 
+    /** Apply roundi() function to each vector component, i.e. return an integer vector.
+    */
+template <class V, int SIZE, class D1, class D2>
+inline
+TinyVector<std::ptrdiff_t, SIZE>
+roundi(TinyVectorBase<V, SIZE, D1, D2> const & v)
+{
+    TinyVector<V, SIZE> res(detail::dontInit());
+    for(int k=0; k<SIZE; ++k)
+        res[k] = roundi(v[k]);
+    return res;
+}
+
     /** Apply sqrt() function to each vector component.
     */
 template <class V, int SIZE, class D1, class D2>
@@ -2036,9 +2238,138 @@ inline
 TinyVector<V, SIZE>
 reverse(TinyVector<V, SIZE> const & t)
 {
-    return TinyVector<V, SIZE>(t.begin(), TinyVector<V, SIZE>::ReverseCopy);
+    return TinyVector<V, SIZE>(t.begin(), ReverseCopy);
+}
+
+    /** \brief transposed copy
+
+        Elements are arranged such that <tt>res[k] = t[permutation[k]]</tt>.
+    */
+template <class V, int SIZE, class T>
+inline
+TinyVector<V, SIZE>
+transpose(TinyVector<V, SIZE> const & t, TinyVector<T, SIZE> const & permutation)
+{
+    TinyVector<V, SIZE> res(SkipInitialization);
+    for(int k=0; k<SIZE; ++k)
+    {
+        VIGRA_ASSERT_INSIDE(permutation[k]);
+        res[k] = t[permutation[k]];
+    }
+    return res;
+}
+
+    /** \brief Clip negative values.
+
+        All elements smaller than 0 are set to zero.
+    */
+template<class V,int SIZE>
+inline
+TinyVector<V, SIZE> clipLower(TinyVector<V, SIZE> const & t){
+    return clipLower(t, V(0));
+}
+
+    /** \brief Clip values below a threshold.
+
+        All elements smaller than \a val are set to \a val.
+    */
+template<class V,int SIZE>
+inline
+TinyVector<V, SIZE> clipLower(TinyVector<V, SIZE> const & t,const V val){
+    TinyVector<V, SIZE> res(SkipInitialization);
+    for(int k=0; k<SIZE; ++k){
+        res[k]=t[k]< val ? val :  t[k];
+    }
+    return res;
+}
+
+    /** \brief Clip values above a threshold.
+
+        All elements bigger than \a val are set to \a val.
+    */
+template<class V,int SIZE>
+inline
+TinyVector<V, SIZE> clipUpper(TinyVector<V, SIZE> const & t,const V val){
+    TinyVector<V, SIZE> res(SkipInitialization);
+    for(int k=0; k<SIZE; ++k){
+        res[k]=t[k]> val ? val :  t[k];
+    }
+    return res;
+}
+
+    /** \brief Clip values to an interval.
+
+        All elements less than \a valLower are set to \a valLower, all elements
+        bigger than \a valUpper are set to \a valUpper.
+    */
+template<class V,int SIZE>
+inline
+TinyVector<V, SIZE> clip(TinyVector<V, SIZE> const & t,const V valLower, const V valUpper){
+    TinyVector<V, SIZE> res(SkipInitialization);
+    for(int k=0; k<SIZE; ++k){
+        res[k] =  (t[k] < valLower)
+                       ? valLower
+                       : (t[k] > valUpper)
+                             ? valUpper
+                             : t[k];
+    }
+    return res;
+}
+
+    /** \brief Clip values to a vector of intervals.
+
+        All elements less than \a valLower are set to \a valLower, all elements
+        bigger than \a valUpper are set to \a valUpper.
+    */
+template<class V,int SIZE>
+inline
+TinyVector<V, SIZE> clip(TinyVector<V, SIZE> const & t,
+                         TinyVector<V, SIZE> const & valLower,
+                         TinyVector<V, SIZE> const & valUpper)
+{
+    TinyVector<V, SIZE> res(SkipInitialization);
+    for(int k=0; k<SIZE; ++k){
+        res[k] =  (t[k] < valLower[k])
+                       ? valLower[k]
+                       : (t[k] > valUpper[k])
+                             ? valUpper[k]
+                             : t[k];
+    }
+    return res;
+}
+
+template<class V,int SIZE>
+inline
+bool isZero(TinyVector<V, SIZE> const & t){
+    for(int k=0; k<SIZE; ++k){
+        if(t[k]!=static_cast<V>(0))
+            return false;
+    }
+    return true;
+}
+
+template<class V,int SIZE>
+inline typename NumericTraits<V>::RealPromote
+mean(TinyVector<V, SIZE> const & t){
+    const V sumVal = sum(t);
+    return static_cast< typename NumericTraits<V>::RealPromote>(sumVal)/SIZE;
+}
+
+
+template<class V,int SIZE>
+inline typename NumericTraits<V>::RealPromote
+sizeDividedSquaredNorm(TinyVector<V, SIZE> const & t){
+    return squaredNorm(t)/SIZE;
+}
+
+template<class V,int SIZE>
+inline typename NumericTraits<V>::RealPromote
+sizeDividedNorm(TinyVector<V, SIZE> const & t){
+    return norm(t)/SIZE;
 }
 
+
+
 //@}
 
 // mask cl.exe shortcomings [end]
diff --git a/include/vigra/transform_iterator.hxx b/include/vigra/transform_iterator.hxx
new file mode 100644
index 0000000..a22bc39
--- /dev/null
+++ b/include/vigra/transform_iterator.hxx
@@ -0,0 +1,192 @@
+
+
+
+namespace vigra{
+
+
+
+
+    template<class T>
+    class TransformIterValProxy{
+    public:
+        typedef const T & reference;
+        typedef const T * pointer;
+        typedef T value_type;
+
+        reference getRef(const T & functionReturn){
+            t_ = functionReturn;
+            return t_;
+        }
+        pointer getPr(const T & functionReturn){
+            t_ = functionReturn;
+            return &t_;
+        }
+    private:
+        T t_;
+    };
+
+
+    template<class T>
+    class TransformIterValProxy<const T &>{
+        typedef const T & reference;
+        typedef const T * pointer;
+        typedef T value_type;
+
+        reference getRef(const T & functionReturn){
+            t_ = functionReturn;
+            return t_;
+        }
+        pointer getPr(const T & functionReturn){
+            t_ = functionReturn;
+            return &t_;
+        }
+    private:
+        T t_;
+    };
+
+    template<class T>
+    class TransformIterValProxy<T &>{
+        typedef T & reference;
+        typedef T * pointer;
+        typedef T value_type;
+
+        reference getRef(const T & functionReturn){
+            t_ = functionReturn;
+            return t_;
+        }
+        pointer getPr(const T & functionReturn){
+            t_ = functionReturn;
+            return &t_;
+        }
+    private:
+        T t_;
+    };
+
+
+    template <
+        class UnaryFunction, 
+        class Iterator
+    >
+    class TransformIterator{
+
+    public:
+        
+        typedef typename UnaryFunction::result_type function_result_type;
+        typedef TransformIterValProxy<function_result_type> RetHelper;
+
+        typedef typename RetHelper::value_type  value_type;
+        typedef typename RetHelper::reference   reference;
+        typedef typename RetHelper::pointer     pointer;
+
+        typedef typename std::iterator_traits<Iterator>::difference_type    difference_type;
+        typedef typename std::iterator_traits<Iterator>::iterator_category iterator_category;
+
+        TransformIterator(const Iterator & iter = Iterator(), const UnaryFunction & f = UnaryFunction())
+        :   iter_(iter),
+            f_(f){
+        }
+
+        reference  operator * () const{
+            return retHelper_.getRef(f_(*iter_)); 
+        } 
+
+        reference  operator[](const difference_type i) const{
+            return retHelper_.getRef(f_(iter_[i])); 
+        }
+
+        pointer  operator -> () const{
+            return retHelper_.getRef(f_(*iter_)); 
+        }
+
+
+        #define TRANSFORMITERATOR_CP_OP_GEN(OP)\
+        bool operator OP (const TransformIterator & rhs)const{\
+            return iter_ OP rhs.iter_;\
+        }
+
+        TRANSFORMITERATOR_CP_OP_GEN(==);
+        TRANSFORMITERATOR_CP_OP_GEN(!=);
+        TRANSFORMITERATOR_CP_OP_GEN(<);
+        TRANSFORMITERATOR_CP_OP_GEN(<=);
+        TRANSFORMITERATOR_CP_OP_GEN(>);
+        TRANSFORMITERATOR_CP_OP_GEN(>=);
+
+        #undef TRANSFORMITERATOR_CP_OP_GEN
+
+        TransformIterator & operator ++ (){
+            ++iter_;
+            return *this;
+        }
+        TransformIterator & operator -- (){
+            --iter_;
+            return *this;
+        }
+        TransformIterator operator ++ (int) const{
+            TransformIterator res(*this);
+            ++res.iter_;
+            return res;
+        }
+        TransformIterator operator -- (int)const{
+            TransformIterator res(*this);
+            --res.iter_;
+            return res;
+        }
+        TransformIterator & operator+=( const difference_type i ){
+            iter_ += i;
+            return *this;
+        } 
+        TransformIterator & operator-=( const difference_type i ){
+            iter_ -= i;
+            return *this;
+        }
+        TransformIterator operator+( const difference_type i )const{
+            TransformIterator res(*this);
+            res += i;
+            return res;
+        } 
+        TransformIterator operator-( const difference_type i )const{
+            TransformIterator res(*this);
+            res -= i;
+            return res;
+        } 
+
+        difference_type operator - (const TransformIterator rhs) const{
+            return iter_ - rhs.iter_;
+        }
+
+    protected:
+        const Iterator & baseIterator()const{
+            return iter_;
+        }
+        const UnaryFunction & unaryFunction()const{
+            return f_;
+        }
+    private:
+        Iterator iter_;
+        UnaryFunction f_;
+        mutable RetHelper retHelper_;
+    };
+
+
+    template <
+        class UnaryFunction, 
+        class Iterator
+    >
+    class EndAwareTransformIterator
+    : public TransformIterator<UnaryFunction, Iterator>
+    {
+    public:
+        EndAwareTransformIterator(const Iterator & iter = Iterator(), const UnaryFunction & f = UnaryFunction())
+        :   TransformIterator<UnaryFunction, Iterator>(iter,f){
+        }
+
+        EndAwareTransformIterator getEndIterator()const{
+            return EndAwareTransformIterator(this->baseIterator().getEndIterator(),
+                                             this->unaryFunction());
+        }
+    private:    
+
+    };
+
+
+}
diff --git a/include/vigra/transformimage.hxx b/include/vigra/transformimage.hxx
index f584b94..bed3039 100644
--- a/include/vigra/transformimage.hxx
+++ b/include/vigra/transformimage.hxx
@@ -95,7 +95,7 @@ transformLineIf(SrcIterator s,
 
 /** \brief Apply unary point transformation to each pixel.
 
-    After the introduction of arithmetic and algebraic \ref MultiMathModule "array experessions",
+    After the introduction of arithmetic and algebraic \ref MultiMathModule "array expressions",
     this function is rarely needed. Moreover, \ref transformMultiArray() provides the 
     same functionality for arbitrary dimensional arrays.
 
@@ -242,7 +242,7 @@ transformImage(MultiArrayView<2, T1, S1> const & src,
 /** \brief Apply unary point transformation to each pixel within the ROI
     (i.e., where the mask is non-zero).
 
-    After the introduction of arithmetic and algebraic \ref MultiMathModule "array experessions",
+    After the introduction of arithmetic and algebraic \ref MultiMathModule "array expressions",
     this function is rarely needed. Moreover, \ref combineTwoMultiArrays() provides the 
     same functionality for arbitrary dimensional arrays.
 
diff --git a/include/vigra/tv_filter.hxx b/include/vigra/tv_filter.hxx
index 17b4462..cc3448b 100644
--- a/include/vigra/tv_filter.hxx
+++ b/include/vigra/tv_filter.hxx
@@ -30,7 +30,7 @@
 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
-/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
 
@@ -57,7 +57,7 @@
 #define setZeroY(A) A.subarray(Shape2(0,height-1),Shape2(width,height))*=0;
 
 namespace vigra{
-  
+
 
 
 /** \addtogroup NonLinearDiffusion
@@ -74,67 +74,67 @@ namespace vigra{
 /** \brief Performs standard Total Variation Regularization
 
 The algorithm minimizes
-    
+
 \f[
        \min_u \int_\Omega \frac{1}{2} (u-f)^2\;dx + \alpha TV(u)\qquad\qquad (1)
 \f]
 where <em>\f$ f=f(x)\f$</em> are the two dimensional noisy data,
 <em> \f$ u=u(x)\f$</em> are the smoothed data,<em>\f$ \alpha \ge 0 \f$</em>
 is the filter parameter and <em>\f$ TV(u)\f$ </em> is the total variation semi-norm.
-        
+
 <b> Declarations:</b>
-   
+
 \code
 namespace vigra {
       template <class stride1,class stride2>
-      void totalVariationFilter(MultiArrayView<2,double,stride1> data, 
+      void totalVariationFilter(MultiArrayView<2,double,stride1> data,
                                 MultiArrayView<2,double,stride2> out,
-                                double alpha, 
-                                int steps, 
+                                double alpha,
+                                int steps,
                                 double eps=0);
       void totalVariationFilter(MultiArrayView<2,double,stride1> data,
                                 MultiArrayView<2,double,stride2> weight,
                                 MultiArrayView<2,double,stride3> out,
-                                double alpha, 
-                                int steps, 
+                                double alpha,
+                                int steps,
                                 double eps=0);
 }
 \endcode
-            
+
 \ref totalVariationFilter() implements a primal-dual algorithm to solve (1).
-     
+
 Input:
-     <table>     
+     <table>
      <tr><td><em>data</em>:  </td><td> input data to be smoothed. </td></tr>
      <tr><td><em>alpha</em>: </td><td> smoothing parameter.</td></tr>
      <tr><td><em>steps</em>: </td><td> maximal number of iteration steps. </td></tr>
      <tr><td><em>eps</em>:   </td><td> The algorithm stops, if the primal-dual gap is below the threshold <em>eps</em>.
      </table>
-     
+
      Output:
-     
+
      <em>out</em> contains the filtered data.
-    
+
      In addition, a point-wise weight (\f$ \ge 0 \f$) for the data term can be provided (overloaded function).
-    
+
     <b> Usage:</b>
-    
+
     <b>\#include</b> \<vigra/tv_filter.hxx\>
-    
+
     \code
     MultiArray<2,double> data(Shape2(width,height));  // to be initialized
     MultiArray<2,double> out(Shape2(width,height));
     MultiArray<2,double> weight(Shape2(width,height))); //optional argument in overloaded function, to be initialized if used
     int steps;        // to be initialized
     double alpha,eps; // to be initialized
-    
+
     totalVariationFilter(data,out,alpha,steps,eps);
     \endcode
     or
     \code
     totalVariationFilter(data,weight,out,alpha,steps,eps);
     \endcode
-  
+
  */
 doxygen_overloaded_function(template <...> void totalVariationFilter)
 
@@ -143,7 +143,7 @@ void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayView<2
 
   using namespace multi_math;
   int width=data.shape(0),height=data.shape(1);
-  
+
   MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shape()),vy(data.shape()),u_bar(data.shape());
   Kernel1D<double> Lx,LTx;
   Lx.initExplicitly(-1,0)=1,-1;                       // = Right sided finite differences for d/dx and d/dy
@@ -153,17 +153,17 @@ void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayView<2
 
   out=data;
   u_bar=data;
-  
+
   double tau=1.0 / std::max(alpha,1.) / std::sqrt(8.0) * 0.06;
   double sigma=1.0 / std::sqrt(8.0) / 0.06;
-    
+
   for (int i=0;i<steps;i++){
-  
+
     separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
     vx+=(sigma*temp1);
     separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroY(temp1);
     vy+=(sigma*temp1);
-    
+
     //project to constraint set
     for (int y=0;y<data.shape(1);y++){
       for (int x=0;x<data.shape(0);x++){
@@ -174,19 +174,19 @@ void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayView<2
         }
       }
     }
-    
+
     separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx));
     separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx));
     u_bar=out;
     out-=tau*(out-data+alpha*(temp1+temp2));
     u_bar=2*out-u_bar;   //cf. Chambolle/Pock and Popov's algorithm
-    
-    
+
+
     //stopping criterion
     if (eps>0){
       separableConvolveX(srcImageRange(out),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
       separableConvolveY(srcImageRange(out),destImage(temp2),kernel1d(Lx));setZeroY(temp2);
-      
+
       double f_primal=0,f_dual=0;
       for (int y=0;y<data.shape(1);y++){
         for (int x=0;x<data.shape(0);x++){
@@ -213,26 +213,26 @@ void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayView<2
 
   using namespace multi_math;
   int width=data.shape(0),height=data.shape(1);
-  
+
   MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shape()),vy(data.shape()),u_bar(data.shape());
-  Kernel1D<double> Lx,LTx; 
+  Kernel1D<double> Lx,LTx;
   Lx.initExplicitly(-1,0)=1,-1;                       // = Right sided finite differences for d/dx and d/dy
   Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT);   //   with hom. Neumann boundary conditions
   LTx.initExplicitly(0,1)=-1,1;                     //  = Left sided finite differences for -d/dx  and -d/dy
   LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD);  //   with hom. Dirichlet b. c.
-  
+
   out=data;
   u_bar=data;
-  
+
   double tau=1.0 / std::max(alpha,1.) / std::sqrt(8.0) * 0.06;
   double sigma=1.0 / std::sqrt(8.0) / 0.06;
-  
+
   for (int i=0;i<steps;i++){
     separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
     vx+=(sigma*temp1);
     separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroY(temp1);
     vy+=(sigma*temp1);
-    
+
     //project to constraint set
     for (int y=0;y<data.shape(1);y++){
       for (int x=0;x<data.shape(0);x++){
@@ -243,19 +243,19 @@ void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayView<2
         }
       }
     }
-    
+
     separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx));
     separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx));
     u_bar=out;
     out-=tau*(weight*(out-data)+alpha*(temp1+temp2));
     u_bar=2*out-u_bar;
-    
-    
+
+
     //stopping criterion
     if (eps>0){
       separableConvolveX(srcImageRange(out),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
       separableConvolveY(srcImageRange(out),destImage(temp2),kernel1d(Lx));setZeroY(temp2);
-      
+
       double f_primal=0,f_dual=0;
       for (int y=0;y<data.shape(1);y++){
         for (int x=0;x<data.shape(0);x++){
@@ -290,7 +290,7 @@ void totalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayView<2
 
 This routine provides a two-dimensional normalized vector field \f$ v \f$, which is normal to edges in the given data,
 found as the eigenvector of the structure tensor belonging to the largest eigenvalue.
-\f$ v \f$ is encoded by a scalar field \f$ \varphi \f$ of angles, i.e. 
+\f$ v \f$ is encoded by a scalar field \f$ \varphi \f$ of angles, i.e.
 \f$ v(x)=(\cos(\varphi(x)),\sin(\varphi(x)))^\top \f$.
 
 In addition, two scalar fields \f$ \alpha \f$ and  \f$ \beta \f$ are generated from
@@ -309,12 +309,12 @@ scalar parameters \f$ \alpha_{par}\f$ and \f$ \beta_{par}\f$, such that
 namespace vigra {
 void getAnisotropy(MultiArrayView<2,double,stride1> data,
                    MultiArrayView<2,double,stride2> phi,
-                   MultiArrayView<2,double,stride3> alpha, 
-                   MultiArrayView<2,double,stride4> beta, 
-                   double alpha_par, 
-                   double beta_par, 
-                   double sigma_par, 
-                   double rho_par, 
+                   MultiArrayView<2,double,stride3> alpha,
+                   MultiArrayView<2,double,stride4> beta,
+                   double alpha_par,
+                   double beta_par,
+                   double sigma_par,
+                   double rho_par,
                    double K_par);
 }
 \endcode
@@ -332,32 +332,32 @@ Input:
 <tr><td> <em>rho_par</em>:</td><td> non-negative parameter for presmoothing the structure tensor.</td></tr>
 <tr><td><em>K_par</em>:</td><td> positive edge sensitivity parameter.</td></tr>
  </table>
- 
+
 (see \ref anisotropicTotalVariationFilter() and \ref secondOrderTotalVariationFilter() for usage in an application).
 */
 doxygen_overloaded_function(template <...> void getAnisotropy)
 
 template <class stride1,class stride2,class stride3,class stride4>
 void getAnisotropy(MultiArrayView<2,double,stride1> data,MultiArrayView<2,double,stride2> phi,
-                    MultiArrayView<2,double,stride3> alpha, MultiArrayView<2,double,stride4> beta, 
+                    MultiArrayView<2,double,stride3> alpha, MultiArrayView<2,double,stride4> beta,
                     double alpha_par, double beta_par, double sigma_par, double rho_par, double K_par){
-  
+
   using namespace multi_math;
   int width=data.shape(0),height=data.shape(1);
-  
+
   MultiArray<2,double> smooth(data.shape()),tmp(data.shape());
   vigra::Kernel1D<double> gauss;
 
-  
+
   gauss.initGaussian(sigma_par);
   separableConvolveX(srcImageRange(data), destImage(tmp), kernel1d(gauss));
   separableConvolveY(srcImageRange(tmp), destImage(smooth), kernel1d(gauss));
-  
+
   MultiArray<2,double> stxx(data.shape()),stxy(data.shape()),styy(data.shape());
-  
+
   // calculate Structure Tensor at inner scale = sigma and outer scale = rho
   vigra::structureTensor(srcImageRange(smooth),destImage(stxx), destImage(stxy), destImage(styy),1.,1.);
-  
+
   gauss.initGaussian(rho_par);
   separableConvolveX(srcImageRange(stxx), destImage(tmp), kernel1d(gauss));
   separableConvolveY(srcImageRange(tmp), destImage(stxx), kernel1d(gauss));
@@ -365,20 +365,20 @@ void getAnisotropy(MultiArrayView<2,double,stride1> data,MultiArrayView<2,double
   separableConvolveY(srcImageRange(tmp), destImage(stxy), kernel1d(gauss));
   separableConvolveX(srcImageRange(styy), destImage(tmp), kernel1d(gauss));
   separableConvolveY(srcImageRange(tmp), destImage(styy), kernel1d(gauss));
-  
+
   MultiArray<2,double> matrix(Shape2(2,2)),ev(Shape2(2,2)),ew(Shape2(2,1));
-  
+
    for (int y=0;y<data.shape(1);y++){
     for (int x=0;x<data.shape(0);x++){
-      
+
       matrix(0,0)=stxx(x,y);
       matrix(1,1)=styy(x,y);
       matrix(0,1)=stxy(x,y);
       matrix(1,0)=stxy(x,y);
-      vigra::linalg::detail::symmetricEigensystem2x2(matrix,ew,ev);
-      
+      vigra::symmetricEigensystemNoniterative(matrix,ew,ev);
+
       phi(x,y)=std::atan2(ev(1,0),ev(0,0));
-      double coherence=ew(0,0)-ew(1,0); 
+      double coherence=ew(0,0)-ew(1,0);
       double c=std::min(K_par*coherence,1.);
       alpha(x,y)=alpha_par*c+(1-c)*beta_par;
       beta(x,y)=beta_par;
@@ -415,7 +415,7 @@ namespace vigra {
   void anisotropicTotalVariationFilter(MultiArrayView<2,double,stride1> data,
                                        MultiArrayView<2,double,stride2> weight,
                                        MultiArrayView<2,double,stride3> phi,
-                                       MultiArrayView<2,double,stride4> alpha, 
+                                       MultiArrayView<2,double,stride4> alpha,
                                        MultiArrayView<2,double,stride5> beta,
                                        MultiArrayView<2,double,stride6> out,
                                        int steps);
@@ -444,13 +444,13 @@ in an outer loop:
 
 <b>\#include</b> \<vigra/tv_filter.hxx\>
 
-\code 
+\code
 MultiArray<2,double> data(Shape2(width,height)); //to be initialized
 MultiArray<2,double> out (Shape2(width,height));
 MultiArray<2,double> weight(Shape2(width,height));  //to be initialized
 MultiArray<2,double> phi  (Shape2(width,height));
 MultiArray<2,double> alpha(Shape2(width,height));
-MultiArray<2,double> beta (Shape2(width,height)); 
+MultiArray<2,double> beta (Shape2(width,height));
 double alpha0,beta0,sigma,rho,K;  //to be initialized
 int outer_steps,inner_steps;//to be initialized
 
@@ -467,43 +467,43 @@ for (int i=0;i<outer_steps;i++){
 doxygen_overloaded_function(template <...>  void anisotropicTotalVariationFilter)
 
 template <class stride1,class stride2,class stride3,class stride4,class stride5,class stride6>
-void anisotropicTotalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayView<2,double,stride2> weight, 
+void anisotropicTotalVariationFilter(MultiArrayView<2,double,stride1> data,MultiArrayView<2,double,stride2> weight,
                     MultiArrayView<2,double,stride3> phi,MultiArrayView<2,double,stride4> alpha,
                     MultiArrayView<2,double,stride5> beta,MultiArrayView<2,double,stride6> out,
                     int steps){
-  
+
   using namespace multi_math;
   int width=data.shape(0),height=data.shape(1);
-  
+
   MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shape()),vy(data.shape()),u_bar(data.shape());
   MultiArray<2,double> rx(data.shape()),ry(data.shape());
-  
+
   Kernel1D<double> Lx,LTx;
   Lx.initExplicitly(-1,0)=1,-1;                       // = Right sided finite differences for d/dx and d/dy
   Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT);   //   with hom. Neumann boundary conditions
   LTx.initExplicitly(0,1)=-1,1;                     //  = Left sided finite differences for -d/dx  and -d/dy
   LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD);  //   with hom. Dirichlet b. c.
-  
+
   u_bar=out;
-  
+
   double m=0;
   for (int y=0;y<data.shape(1);y++){
     for (int x=0;x<data.shape(0);x++){
       m=std::max(m,alpha(x,y));
       m=std::max(m,beta (x,y));
     }
-  }  
+  }
   m=std::max(m,1.);
-  double tau=.9/m/std::sqrt(8.)*0.06;  
+  double tau=.9/m/std::sqrt(8.)*0.06;
   double sigma=.9/m/std::sqrt(8.)/0.06;
-  
-    
+
+
   for (int i=0;i<steps;i++){
     separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
     vx+=(sigma*temp1);
     separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroY(temp1);
     vy+=(sigma*temp1);
-    
+
     //project to constraint set
     for (int y=0;y<data.shape(1);y++){
       for (int x=0;x<data.shape(0);x++){
@@ -514,12 +514,12 @@ void anisotropicTotalVariationFilter(MultiArrayView<2,double,stride1> data,Multi
         skp1=vx(x,y)*e1+vy(x,y)*e2;
         skp2=vx(x,y)*(-e2)+vy(x,y)*e1;
         vigra::detail::projectEllipse2D (skp1,skp2,alpha(x,y),beta(x,y),0.001,100);
-        
+
         vx(x,y)=skp1*e1-skp2*e2;
         vy(x,y)=skp1*e2+skp2*e1;
       }
     }
-    
+
     separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx));
     separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx));
     u_bar=out;
@@ -542,7 +542,7 @@ The algorithm minimizes
 \min_u \int_\Omega \frac{1}{2} (u-f)^2 + \sqrt{\nabla u^\top A \nabla u}  + \gamma |Hu|_F\;dx \qquad\qquad (3)
 \f]
 where <em> \f$ f=f(x)\f$ </em> are the noisy data, <em> \f$ u=u(x)\f$ </em> are the smoothed data,<em>\f$ \nabla u \f$ </em>
-is the image gradient in the sense of Total Variation, <em>\f$ A \f$ </em> is a locally varying 
+is the image gradient in the sense of Total Variation, <em>\f$ A \f$ </em> is a locally varying
 symmetric, positive-definite  2x2 matrix and <em>\f$ |Hu|_F \f$</em> is the Frobenius norm of the Hessian of \f$ u \f$.
 
 Matrix <em>\f$ A \f$ </em> is described by providing  for each data point a normalized eigenvector (via angle \f$ \phi \f$)
@@ -556,7 +556,7 @@ and two eigenvalues \f$ \alpha>0 \f$ and \f$ \beta>0 \f$.
 \code
 namespace vigra {
   template <class stride1,class stride2,...,class stride9>
-  void secondOrderTotalVariationFilter(MultiArrayView<2,double,stride1> data, 
+  void secondOrderTotalVariationFilter(MultiArrayView<2,double,stride1> data,
                                        MultiArrayView<2,double,stride2> weight,
                                        MultiArrayView<2,double,stride3> phi,
                                        MultiArrayView<2,double,stride4> alpha,
@@ -579,7 +579,7 @@ Input:
 <tr><td><em>weight</em> : </td><td> point-wise weight (\f$ \ge 0\f$ ) for the data term.</td></tr>
 <tr><td><em>phi</em>,<em>alpha</em>,<em>beta</em>: </td><td> describe matrix \f$ A\f$, see above.</td></tr>
 <tr><td><em> xedges </em> and <em> yedges </em>: </td><td> binary arrays indicating the
-presence of horizontal (between (x,y) and (x+1,y)) and vertical edges (between (x,y) and (x,y+1)). 
+presence of horizontal (between (x,y) and (x+1,y)) and vertical edges (between (x,y) and (x,y+1)).
 These data are considered in the calculation of \f$ Hu\f$, such that
 finite differences across edges are artificially set to zero to avoid second order smoothing over edges.</td></tr>
 </table>
@@ -591,13 +591,13 @@ in an outer loop:
 
 <b>\#include</b> \<vigra/tv_filter.hxx\>
 
-\code 
+\code
 MultiArray<2,double> data(Shape2(width,height)); //to be initialized
 MultiArray<2,double> out(Shape2(width,height));
 MultiArray<2,double> weight(Shape2(width,height))); //to be initialized
 MultiArray<2,double> phi(Shape2(width,height);
 MultiArray<2,double> alpha(Shape2(width,height);
-MultiArray<2,double> beta(Shape2(width,height)); 
+MultiArray<2,double> beta(Shape2(width,height));
 MultiArray<2,double> gamma(Shape2(width,height));  //to be initialized
 MultiArray<2,double> xedges(Shape2(width,height));  //to be initialized
 MultiArray<2,double> yedges(Shape2(width,height));  //to be initialized
@@ -609,7 +609,7 @@ int outer_steps,inner_steps;//to be initialized
 out=data; // data serves as initial value
 
 for (int i=0;i<outer_steps;i++){
-  
+
   getAnisotropy(out,phi,alpha,beta,alpha0,beta0,sigma,rho,K);  // sets phi, alpha, beta
   secondOrderTotalVariationFilter(data,weight,phi,alpha,beta,gamma,xedges,yedges,out,inner_steps);
 }
@@ -621,30 +621,30 @@ for (int i=0;i<outer_steps;i++){
 doxygen_overloaded_function(template <...> void secondOrderTotalVariationFilter)
 
 template <class stride1,class stride2,class stride3,class stride4,class stride5,class stride6,class stride7,class stride8,class stride9>
-void secondOrderTotalVariationFilter(MultiArrayView<2,double,stride1> data, 
+void secondOrderTotalVariationFilter(MultiArrayView<2,double,stride1> data,
                             MultiArrayView<2,double,stride2> weight,MultiArrayView<2,double,stride3> phi,
                             MultiArrayView<2,double,stride4> alpha,MultiArrayView<2,double,stride5> beta,
                             MultiArrayView<2,double,stride6> gamma,
                             MultiArrayView<2,double,stride7> xedges,MultiArrayView<2,double,stride8> yedges,
-		            MultiArrayView<2,double,stride9> out,
+                    MultiArrayView<2,double,stride9> out,
                             int steps){
-  
+
   using namespace multi_math;
   int width=data.shape(0),height=data.shape(1);
-  
+
   MultiArray<2,double> temp1(data.shape()),temp2(data.shape()),vx(data.shape()),vy(data.shape()),u_bar(data.shape());
   MultiArray<2,double> rx(data.shape()),ry(data.shape());
   MultiArray<2,double> wx(data.shape()),wy(data.shape()),wz(data.shape());
-  
-  
+
+
   Kernel1D<double> Lx,LTx;
   Lx.initExplicitly(-1,0)=1,-1;                       // = Right sided finite differences for d/dx and d/dy
   Lx.setBorderTreatment(BORDER_TREATMENT_REFLECT);   //   with hom. Neumann boundary conditions
   LTx.initExplicitly(0,1)=-1,1;                     //  = Left sided finite differences for -d/dx  and -d/dy
   LTx.setBorderTreatment(BORDER_TREATMENT_ZEROPAD);  //   with hom. Dirichlet b. c.
-  
+
   u_bar=out;
-  
+
   double m=0;
   for (int y=0;y<data.shape(1);y++){
     for (int x=0;x<data.shape(0);x++){
@@ -652,54 +652,54 @@ void secondOrderTotalVariationFilter(MultiArrayView<2,double,stride1> data,
       m=std::max(m,beta (x,y));
       m=std::max(m,gamma(x,y));
      }
-  }  
+  }
   m=std::max(m,1.);
-  double tau=.1/m;//std::sqrt(8)*0.06;  
+  double tau=.1/m;//std::sqrt(8)*0.06;
   double sigma=.1;//m;/std::sqrt(8)/0.06;
-  
+
   //std::cout<<"tau= "<<tau<<std::endl;
-  
+
   for (int i=0;i<steps;i++){
-    
+
     separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
     vx+=(sigma*temp1);
     separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroY(temp1);
     vy+=(sigma*temp1);
-    
-    
+
+
     // update wx
     separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
     temp1*=xedges;
     separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx));
     wx-=sigma*temp2;//(-Lx'*(xedges.*(Lx*u)));
-    
+
     //update wy
     separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroY(temp1);
     temp1*=yedges;
     separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx));
     wy-=sigma*temp2;//(-Ly'*(yedges.*(Ly*u)));
-    
-    
+
+
     //update wz
     #if (VIGRA_MIXED_2ND_DERIVATIVES)
     separableConvolveY(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroY(temp1);
     temp1*=yedges;
     separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx));
     wz-=sigma*temp2;//-Lx'*(yedges.*(Ly*u))
-    
+
     separableConvolveX(srcImageRange(u_bar),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
     temp1*=xedges;
     separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx));
     wz-=sigma*temp2;//-Ly'*(xedges.*(Lx*u)));
-    
+
     #endif
-    
-    
+
+
     //project to constraint sets
     for (int y=0;y<data.shape(1);y++){
       for (int x=0;x<data.shape(0);x++){
         double e1,e2,skp1,skp2;
-        
+
         //project v
         e1=std::cos(phi(x,y));
         e2=std::sin(phi(x,y));
@@ -708,56 +708,56 @@ void secondOrderTotalVariationFilter(MultiArrayView<2,double,stride1> data,
         vigra::detail::projectEllipse2D (skp1,skp2,alpha(x,y),beta(x,y),0.001,100);
         vx(x,y)=skp1*e1-skp2*e2;
         vy(x,y)=skp1*e2+skp2*e1;
-        
+
         //project w
         double l=sqrt(wx(x,y)*wx(x,y)+wy(x,y)*wy(x,y)+wz(x,y)*wz(x,y));
         if (l>gamma(x,y)){
           wx(x,y)=gamma(x,y)*wx(x,y)/l;
-          wy(x,y)=gamma(x,y)*wy(x,y)/l;  
+          wy(x,y)=gamma(x,y)*wy(x,y)/l;
           #if (VIGRA_MIXED_2ND_DERIVATIVES)
           wz(x,y)=gamma(x,y)*wz(x,y)/l;
           #endif
         }
       }
     }
-    
+
     separableConvolveX(srcImageRange(vx),destImage(temp1),kernel1d(LTx));
     separableConvolveY(srcImageRange(vy),destImage(temp2),kernel1d(LTx));
-    
+
     u_bar=out;
     out-=tau*(weight*(out-data)+temp1+temp2);
-    
-    
+
+
     // update wx
     separableConvolveX(srcImageRange(wx),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
     temp1*=xedges;
     separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx));
     out+=tau*temp2; // (-1)^2
-    
-    
+
+
     //update wy
     separableConvolveY(srcImageRange(wy),destImage(temp1),kernel1d(Lx));setZeroY(temp1);
     temp1*=yedges;
     separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx));
-    out+=tau*temp2; 
-    
+    out+=tau*temp2;
+
     //update wz
     #if (VIGRA_MIXED_2ND_DERIVATIVES)
-    
+
     separableConvolveY(srcImageRange(wz),destImage(temp1),kernel1d(Lx));setZeroY(temp1);
     temp1*=yedges;
     separableConvolveX(srcImageRange(temp1),destImage(temp2),kernel1d(LTx));
     out+=tau*temp2;
-    
+
     separableConvolveX(srcImageRange(wz),destImage(temp1),kernel1d(Lx));setZeroX(temp1);
     temp1*=xedges;
     separableConvolveY(srcImageRange(temp1),destImage(temp2),kernel1d(LTx));
     out+=tau*temp2;
-    
+
     #endif
-    
+
     u_bar=2*out-u_bar;   //cf. Chambolle/Pock and Popov's algorithm
-    
+
   }
 }
 
diff --git a/include/vigra/union_find.hxx b/include/vigra/union_find.hxx
index 7721f58..9f4120c 100644
--- a/include/vigra/union_find.hxx
+++ b/include/vigra/union_find.hxx
@@ -37,88 +37,269 @@
 #ifndef VIGRA_UNION_FIND_HXX
 #define VIGRA_UNION_FIND_HXX
 
+/*std*/
+#include <map>
+
+/*vigra*/
 #include "config.hxx"
 #include "error.hxx"
 #include "array_vector.hxx"
+#include "iteratoradapter.hxx"
 
 namespace vigra {
 
 namespace detail {
 
+template <class T, class IsSigned = VigraFalseType>
+struct UnionFindAccessorImpl
+{
+    static const T max_label = NumericTraits<T>::maxConst >> 1;
+    static const T anchor_bit = ~max_label;
+    
+    static T max()
+    {
+        return max_label;
+    }
+    
+    static T deletedAnchor()
+    {
+        return NumericTraits<T>::maxConst;
+    }
+    
+    static bool isAnchor(T const & t)
+    {
+        return (t & anchor_bit) != 0;
+    }
+    
+    static bool isValidAnchor(T const & t)
+    {
+        return isAnchor(t) && t != deletedAnchor();
+    }
+    
+    static bool notAnchor(T const & t)
+    {
+        return (t & anchor_bit) == 0;
+    }
+    
+    static T toAnchor(T const & t)
+    {
+        return t | anchor_bit;
+    }
+    
+    static T fromAnchor(T const & t)
+    {
+        return t & max_label;
+    }
+};
+
+template <class T>
+struct UnionFindAccessorImpl<T, VigraTrueType>
+{
+    static T max()
+    {
+        return NumericTraits<T>::max();
+    }
+    
+    static T deletedAnchor()
+    {
+        return NumericTraits<T>::min();
+    }
+    
+    static bool isAnchor(T const & t)
+    {
+        return t < 0;
+    }
+    
+    static bool isValidAnchor(T const & t)
+    {
+        return isAnchor(t) && t != deletedAnchor();
+    }
+    
+    static bool notAnchor(T const & t)
+    {
+        return t >= 0;
+    }
+    
+    static T toAnchor(T const & t)
+    {
+        return -t - 1;
+    }
+    
+    static T fromAnchor(T const & t)
+    {
+        return -(t + 1);
+    }
+};
+
+template <class Array, class LabelAccessor>
+class UnionFindIteratorPolicy
+{
+  public:
+    typedef UnionFindIteratorPolicy                BaseType;
+    typedef typename Array::difference_type        value_type;
+    typedef typename Array::difference_type        difference_type;
+    typedef value_type const &                     reference;
+    typedef value_type const &                     index_reference;
+    typedef value_type const *                     pointer;
+    typedef typename std::forward_iterator_tag     iterator_category;
+
+    Array const & array_;
+    value_type index_;
+    
+    UnionFindIteratorPolicy(Array const & array, value_type index=0)
+    : array_(array)
+    , index_(index)
+    {}
+    
+    static void initialize(BaseType & d) 
+    {
+        advanceToAnchor(d);
+    }
+
+    static reference dereference(BaseType const & d)
+    { 
+        return d.index_;
+    }
+
+    static bool equal(BaseType const & d1, BaseType const & d2)
+    {
+        return d1.index_ == d2.index_;
+    }
+
+    static bool less(BaseType const & d1, BaseType const & d2)
+    {
+        return d1.index_ < d2.index_;
+    }
+
+    static void increment(BaseType & d)
+    {
+        ++d.index_; 
+        advanceToAnchor(d);
+    }
+
+    static void advanceToAnchor(BaseType & d)
+    {
+        while(d.index_ < (value_type)d.array_.size()-1 && 
+              !LabelAccessor::isValidAnchor(d.array_[d.index_]))
+        {
+            ++d.index_;
+        }
+    }
+};
+
+} // namespace detail
+
 template <class T>
 class UnionFindArray
 {
-    typedef typename ArrayVector<T>::difference_type IndexType;
+    typedef ArrayVector<T>                                             LabelArray;
+    typedef typename LabelArray::difference_type                       IndexType;
+    typedef detail::UnionFindAccessorImpl<T, 
+                          typename NumericTraits<T>::isSigned>         LabelAccessor;
+    typedef detail::UnionFindIteratorPolicy<LabelArray, LabelAccessor> IteratorPolicy;
+    typedef IteratorAdaptor<IteratorPolicy>                            iterator;
+    typedef iterator                                                   const_iterator;
+
     mutable ArrayVector<T> labels_;
     
   public:
     UnionFindArray(T next_free_label = 1)
     {
-        for(T k=0; k <= next_free_label; ++k)
-            labels_.push_back(k);
+        vigra_precondition(next_free_label <= LabelAccessor::max(),
+           "UnionFindArray(): Need more labels than can be represented"
+           "in the destination type.");
+        
+        for(T k=0; k < next_free_label; ++k)
+            labels_.push_back(LabelAccessor::toAnchor(k));
+        labels_.push_back(LabelAccessor::toAnchor(next_free_label));
+    } 
+    
+    const_iterator begin(unsigned int start_at=0) const
+    {
+        return const_iterator(IteratorPolicy(labels_, start_at));
+    }
+    
+    const_iterator end() const
+    {
+        return const_iterator(IteratorPolicy(labels_, labels_.size()-1));
     }
     
-    T nextFreeLabel() const
+    T nextFreeIndex() const
     {
-        return labels_.back();
+        return T(labels_.size() - 1);
     }
     
-    T find(T label) const
+    T findIndex(T index) const
     {
-        T root = label;
-        while(root != labels_[(IndexType)root])
-            root = labels_[(IndexType)root];
+        IndexType root = index;
+        while(LabelAccessor::notAnchor(labels_[root]))
+            root = (IndexType)labels_[root];
         // path compression
-        while(label != root)
+        while((IndexType)index != root)
         {
-            T next = labels_[(IndexType)label];
-            labels_[(IndexType)label] = root;
-            label = next;
+            T next = labels_[(IndexType)index];
+            labels_[(IndexType)index] = root;
+            index = next;
         }
-        return root;
+        return (T)root;
     } 
     
+    T findLabel(T index) const
+    {
+        return LabelAccessor::fromAnchor(labels_[findIndex(index)]);
+    }
+    
+    void deleteIndex(T index)
+    {
+        labels_[findIndex(index)] = LabelAccessor::deletedAnchor();
+    }
+    
+        // this function does not yet check for deletedIndex()
     T makeUnion(T l1, T l2)
     {
-        l1 = find(l1);
-        l2 = find(l2);
-        if(l1 <= l2)
+        IndexType i1 = findIndex(l1);
+        IndexType i2 = findIndex(l2);
+        if(i1 == i2)
+        {
+            return i1;
+        }
+        else if(i1 < i2)
         {
-            labels_[(IndexType)l2] = l1;
-            return l1;
+            labels_[i2] = i1;
+            return (T)i1;
         }
         else
         {
-            labels_[(IndexType)l1] = l2;
-            return l2;
+            labels_[i1] = i2;
+            return (T)i2;
         }
     }
     
-    T finalizeLabel(T label)
+    T finalizeIndex(T index)
     {
-        if(label == (T)labels_.size()-1)
+        if(index == (T)labels_.size()-1)
         {
             // indeed a new region
-            vigra_invariant(label < NumericTraits<T>::max(),
+            vigra_invariant(index < LabelAccessor::max(),
                     "connected components: Need more labels than can be represented in the destination type.");
             // create new back entry
-            labels_.push_back((T)labels_.size());
+            labels_.push_back(LabelAccessor::toAnchor((T)labels_.size()));
         }
         else
         {
-            // no new label => reset the back entry of the label array
-            labels_.back() = (T)labels_.size()-1;
+            // no new index => reset the back entry of the index array
+            labels_.back() = LabelAccessor::toAnchor((T)labels_.size()-1);
         }
-        return label;
+        return index;
     }
     
-    T makeNewLabel() 
+    T makeNewIndex() 
     {
-        T label = labels_.back();
-        vigra_invariant(label < NumericTraits<T>::max(),
+        T index = LabelAccessor::fromAnchor(labels_.back());
+        vigra_invariant(index < LabelAccessor::max(),
           "connected components: Need more labels than can be represented in the destination type.");
-        labels_.push_back((T)labels_.size());
-        return label;
+        labels_.push_back(LabelAccessor::toAnchor((T)labels_.size()));
+        return index;
     }
     
     unsigned int makeContiguous()
@@ -127,26 +308,19 @@ class UnionFindArray
         unsigned int count = 0; 
         for(IndexType i=0; i<(IndexType)(labels_.size()-1); ++i)
         {
-            if(labels_[i] == i)
+            if(LabelAccessor::isValidAnchor(labels_[i]))
             {
-                    labels_[i] = (T)count++;
+                    labels_[i] = LabelAccessor::toAnchor((T)count++);
             }
             else
             {
-                    labels_[i] = labels_[(IndexType)labels_[i]]; 
+                    labels_[i] = findIndex(i);  // path compression
             }
         }
         return count-1;   
     }
-    
-    T operator[](T label) const
-    {
-        return labels_[(IndexType)label];
-    }
 };
 
-} // namespace detail
-
 } // namespace vigra
 
 #endif // VIGRA_UNION_FIND_HXX
diff --git a/include/vigra/unittest.hxx b/include/vigra/unittest.hxx
index b9fecf5..b3180ed 100755
--- a/include/vigra/unittest.hxx
+++ b/include/vigra/unittest.hxx
@@ -110,13 +110,20 @@
 #define VIGRA_ASSERT(predicate) \
     vigra::detail::should_impl((predicate), #predicate, __FILE__, __LINE__)
 
+#define VIGRA_ASSERT_NOT(predicate) \
+    vigra::detail::should_impl(!(predicate), "!(" #predicate ")", __FILE__, __LINE__)
+
 #define should VIGRA_ASSERT
 
+#define shouldNot VIGRA_ASSERT_NOT
+
 #define VIGRA_ASSERT_MESSAGE(predicate, message) \
     vigra::detail::should_impl((predicate), message, __FILE__, __LINE__)
 
 #define shouldMsg VIGRA_ASSERT_MESSAGE
 
+#define shouldMessage VIGRA_ASSERT_MESSAGE
+
 #define shouldEqual(left, right) \
     vigra::detail::equal_impl(left, right, #left " == " #right, __FILE__, __LINE__)
 
@@ -233,8 +240,6 @@ int catch_signals( Generator function_object, detail::errstream & err, int timeo
 
 #elif defined(__unix)
 
-extern "C" {
-
 inline jmp_buf & unit_test_jump_buffer()
 {
     static jmp_buf unit_test_jump_buffer_;
@@ -246,8 +251,6 @@ static void unit_test_signal_handler(int sig)
     longjmp(unit_test_jump_buffer(), sig);
 }
 
-} // extern "C"
-
 template< class Generator >  // Generator is function object returning int
 int catch_signals( Generator function_object, detail::errstream & err, int timeout)
 {
@@ -463,6 +466,12 @@ should_impl(bool predicate, const char * message, const char * file, int line)
     } 
 }
 
+inline void
+should_impl(bool predicate, std::string const & message, const char * file, int line)
+{
+    should_impl(predicate, message.c_str(), file, line);
+}
+
 template <class Iter1, class Iter2>
 void 
 sequence_equal_impl(Iter1 i1, Iter1 end1, Iter2 i2, const char * file, int line)
diff --git a/include/vigra/unsupervised_decomposition.hxx b/include/vigra/unsupervised_decomposition.hxx
index 78a2849..bb66e13 100644
--- a/include/vigra/unsupervised_decomposition.hxx
+++ b/include/vigra/unsupervised_decomposition.hxx
@@ -54,71 +54,71 @@ namespace vigra
 
 /*****************************************************************/
 /*                                                               */
-/*              principle component analysis (PCA)               */
+/*              principal component analysis (PCA)               */
 /*                                                               */
 /*****************************************************************/
 
-   /** \brief Decompose a matrix according to the PCA algorithm. 
+   /** \brief Decompose a matrix according to the PCA algorithm.
 
-        This function implements the PCA algorithm (principle component analysis).
+        This function implements the PCA algorithm (principal component analysis).
 
         \arg features must be a matrix with shape <tt>(numFeatures * numSamples)</tt>, which is
-        decomposed into the matrices 
+        decomposed into the matrices
         \arg fz with shape <tt>(numFeatures * numComponents)</tt> and
         \arg zv with shape <tt>(numComponents * numSamples)</tt>
-        
+
         such that
         \f[
             \mathrm{features} \approx \mathrm{fz} * \mathrm{zv}
         \f]
         (this formula requires that the features have been centered around the mean by
         <tt>\ref linalg::prepareRows (features, features, ZeroMean)</tt>).
-       
-        The shape parameter <tt>numComponents</tt> determines the complexity of 
+
+        The shape parameter <tt>numComponents</tt> determines the complexity of
         the decomposition model and therefore the approximation quality (if
-        <tt>numComponents == numFeatures</tt>, the representation becomes exact). 
+        <tt>numComponents == numFeatures</tt>, the representation becomes exact).
         Intuitively, <tt>fz</tt> is a projection matrix from the reduced space
         into the original space, and <tt>zv</tt> is  the reduced representation
         of the data, using just <tt>numComponents</tt> features.
 
         <b>Declaration:</b>
-        
+
         <b>\#include</b> \<vigra/unsupervised_decomposition.hxx\>
 
         \code
         namespace vigra {
-        
+
             template <class U, class C1, class C2, class C3>
             void
-            principleComponents(MultiArrayView<2, U, C1> const & features,
-                                MultiArrayView<2, U, C2> fz, 
+            principalComponents(MultiArrayView<2, U, C1> const & features,
+                                MultiArrayView<2, U, C2> fz,
                                 MultiArrayView<2, U, C3> zv);
         }
         \endcode
-        
+
         <b>Usage:</b>
         \code
         Matrix<double> data(numFeatures, numSamples);
         ... // fill the input matrix
-        
+
         int numComponents = 3;
         Matrix<double> fz(numFeatures, numComponents),
                        zv(numComponents, numSamples);
-                       
+
         // center the data
         prepareRows(data, data, ZeroMean);
-        
+
         // compute the reduced representation
-        principleComponents(data, fz, zv);
-        
+        principalComponents(data, fz, zv);
+
         Matrix<double> model = fz*zv;
         double meanSquaredError = squaredNorm(data - model) / numSamples;
         \endcode
    */
 template <class T, class C1, class C2, class C3>
 void
-principleComponents(MultiArrayView<2, T, C1> const & features,
-                    MultiArrayView<2, T, C2> fz, 
+principalComponents(MultiArrayView<2, T, C1> const & features,
+                    MultiArrayView<2, T, C2> fz,
                     MultiArrayView<2, T, C3> zv)
 {
     using namespace linalg; // activate matrix multiplication and arithmetic functions
@@ -127,17 +127,17 @@ principleComponents(MultiArrayView<2, T, C1> const & features,
     int numSamples = columnCount(features);
     int numComponents = columnCount(fz);
     vigra_precondition(numSamples >= numFeatures,
-      "principleComponents(): The number of samples has to be larger than the number of features.");
+      "principalComponents(): The number of samples has to be larger than the number of features.");
     vigra_precondition(numFeatures >= numComponents && numComponents >= 1,
-      "principleComponents(): The number of features has to be larger or equal to the number of components in which the feature matrix is decomposed.");
+      "principalComponents(): The number of features has to be larger or equal to the number of components in which the feature matrix is decomposed.");
     vigra_precondition(rowCount(fz) == numFeatures,
-      "principleComponents(): The output matrix fz has to be of dimension numFeatures*numComponents.");
+      "principalComponents(): The output matrix fz has to be of dimension numFeatures*numComponents.");
     vigra_precondition(columnCount(zv) == numSamples && rowCount(zv) == numComponents,
-      "principleComponents(): The output matrix zv has to be of dimension numComponents*numSamples.");
+      "principalComponents(): The output matrix zv has to be of dimension numComponents*numSamples.");
 
     Matrix<T> U(numSamples, numFeatures), S(numFeatures, 1), V(numFeatures, numFeatures);
     singularValueDecomposition(features.transpose(), U, S, V);
-    
+
     for(int k=0; k<numComponents; ++k)
     {
         rowVector(zv, k) = columnVector(U, k).transpose() * S(k, 0);
@@ -153,7 +153,7 @@ principleComponents(MultiArrayView<2, T, C1> const & features,
 /*                                                               */
 /*****************************************************************/
 
-   /** \brief Option object for the \ref pLSA algorithm. 
+   /** \brief Option object for the \ref pLSA algorithm.
    */
 class PLSAOptions
 {
@@ -189,12 +189,12 @@ class PLSAOptions
         min_rel_gain = g;
         return *this;
     }
-    
+
         /** Normalize the entries of the zv result array.
-        
+
             If true, the columns of zv sum to one. Otherwise, they have the same
             column sum as the original feature matrix.
-            
+
             default: true
         */
     PLSAOptions & normalizedComponentWeights(bool v = true)
@@ -208,9 +208,9 @@ class PLSAOptions
     bool normalized_component_weights;
 };
 
-   /** \brief Decompose a matrix according to the pLSA algorithm. 
+   /** \brief Decompose a matrix according to the pLSA algorithm.
 
-        This function implements the pLSA algorithm (probabilistic latent semantic analysis) 
+        This function implements the pLSA algorithm (probabilistic latent semantic analysis)
         proposed in
 
         T. Hofmann: <a href="http://www.cs.brown.edu/people/th/papers/Hofmann-UAI99.pdf">
@@ -218,28 +218,28 @@ class PLSAOptions
         in: UAI'99, Proc. 15th Conf. on Uncertainty in Artificial Intelligence,
         pp. 289-296, Morgan Kaufmann, 1999
 
-        \arg features must be a matrix with shape <tt>(numFeatures * numSamples)</tt> and 
-        non-negative entries, which is decomposed into the matrices 
+        \arg features must be a matrix with shape <tt>(numFeatures * numSamples)</tt> and
+        non-negative entries, which is decomposed into the matrices
         \arg fz with shape <tt>(numFeatures * numComponents)</tt> and
         \arg zv with shape <tt>(numComponents * numSamples)</tt>
-        
+
         such that
         \f[
             \mathrm{features} \approx \mathrm{fz} * \mathrm{zv}
         \f]
-        (this formula applies when pLSA is called with 
+        (this formula applies when pLSA is called with
         <tt>PLSAOptions.normalizedComponentWeights(false)</tt>. Otherwise, you must
         normalize the features by calling <tt>\ref linalg::prepareColumns (features, features, UnitSum)</tt>
         to make the formula hold).
-       
-        The shape parameter <tt>numComponents</tt> determines the complexity of 
-        the decomposition model and therefore the approximation quality. 
-        Intuitively, features are a set of words, and the samples a set of 
-        documents. The entries of the <tt>features</tt> matrix denote the relative 
-        frequency of the words in each document. The components represents a 
-        (presumably small) set of topics. The matrix <tt>fz</tt> encodes the 
-        relative frequency of words in the different topics, and the matrix  
-        <tt>zv</tt> encodes to what extend each topic explains the content of each 
+
+        The shape parameter <tt>numComponents</tt> determines the complexity of
+        the decomposition model and therefore the approximation quality.
+        Intuitively, features are a set of words, and the samples a set of
+        documents. The entries of the <tt>features</tt> matrix denote the relative
+        frequency of the words in each document. The components represents a
+        (presumably small) set of topics. The matrix <tt>fz</tt> encodes the
+        relative frequency of words in the different topics, and the matrix
+        <tt>zv</tt> encodes to what extend each topic explains the content of each
         document.
 
         The option object determines the iteration termination conditions and the output
@@ -247,40 +247,40 @@ class PLSAOptions
         which is used to create the initial solution.
 
         <b>Declarations:</b>
-        
+
         <b>\#include</b> \<vigra/unsupervised_decomposition.hxx\>
 
         \code
         namespace vigra {
-        
+
             template <class U, class C1, class C2, class C3, class Random>
             void
             pLSA(MultiArrayView<2, U, C1> const & features,
-                 MultiArrayView<2, U, C2> & fz, 
+                 MultiArrayView<2, U, C2> & fz,
                  MultiArrayView<2, U, C3> & zv,
                  Random const& random,
                  PLSAOptions const & options = PLSAOptions());
-                 
+
             template <class U, class C1, class C2, class C3>
             void
-            pLSA(MultiArrayView<2, U, C1> const & features, 
-                 MultiArrayView<2, U, C2> & fz, 
+            pLSA(MultiArrayView<2, U, C1> const & features,
+                 MultiArrayView<2, U, C2> & fz,
                  MultiArrayView<2, U, C3> & zv,
                  PLSAOptions const & options = PLSAOptions());
         }
         \endcode
-        
+
         <b>Usage:</b>
         \code
         Matrix<double> words(numWords, numDocuments);
         ... // fill the input matrix
-        
+
         int numTopics = 3;
         Matrix<double> fz(numWords, numTopics),
                        zv(numTopics, numDocuments);
-                       
+
         pLSA(words, fz, zv, PLSAOptions().normalizedComponentWeights(false));
-        
+
         Matrix<double> model = fz*zv;
         double meanSquaredError = (words - model).squaredNorm() / numDocuments;
         \endcode
@@ -291,7 +291,7 @@ doxygen_overloaded_function(template <...> void pLSA)
 template <class U, class C1, class C2, class C3, class Random>
 void
 pLSA(MultiArrayView<2, U, C1> const & features,
-     MultiArrayView<2, U, C2> fz, 
+     MultiArrayView<2, U, C2> fz,
      MultiArrayView<2, U, C3> zv,
      Random const& random,
      PLSAOptions const & options = PLSAOptions())
@@ -326,11 +326,11 @@ pLSA(MultiArrayView<2, U, C1> const & features,
     Matrix<U> columnSums(1, numSamples);
     features.sum(columnSums);
     Matrix<U> expandedSums = ones<U>(numFeatures, 1) * columnSums;
-    
+
     while(iteration < options.max_iterations && (lastChange > options.min_rel_gain))
     {
         Matrix<U> fzv = fz*zv;
-        
+
         //if(iteration%25 == 0)
         //{
             //std::cout << "iteration: " << iteration << std::endl;
@@ -350,12 +350,12 @@ pLSA(MultiArrayView<2, U, C1> const & features,
         //std::cout << "error: " << err << std::endl;
         lastChange = abs((err-err_old) / (U)(err + eps));
         //std::cout << "lastChange: " << lastChange << std::endl;
-         
+
         iteration += 1;
     }
     //std::cout << "Terminated after " << iteration << " iterations." << std::endl;
     //std::cout << "Last relative change was " << lastChange << "." << std::endl;
-    
+
     if(!options.normalized_component_weights)
     {
         // undo the normalization
@@ -366,8 +366,8 @@ pLSA(MultiArrayView<2, U, C1> const & features,
 
 template <class U, class C1, class C2, class C3>
 inline void
-pLSA(MultiArrayView<2, U, C1> const & features, 
-     MultiArrayView<2, U, C2> & fz, 
+pLSA(MultiArrayView<2, U, C1> const & features,
+     MultiArrayView<2, U, C2> & fz,
      MultiArrayView<2, U, C3> & zv,
      PLSAOptions const & options = PLSAOptions())
 {
diff --git a/include/vigra/utilities.hxx b/include/vigra/utilities.hxx
index f482302..bc66b72 100644
--- a/include/vigra/utilities.hxx
+++ b/include/vigra/utilities.hxx
@@ -47,6 +47,8 @@
 #include <sstream>
 #include <cctype>
 
+/*! \file */
+
 namespace vigra {
 
 /** Convert a value to a string. Available for integral and floating point types
@@ -81,11 +83,11 @@ VIGRA_AS_STRING(void *)
 #undef VIGRA_AS_STRING
 
 template <class T>
-std::string & operator<<(std::string & s, T const & t)
+std::string operator<<(std::string const & s, T const & t)
 {
     std::stringstream ss;
-    ss << t; 
-    return s += ss.str();
+    ss << t;
+    return s + ss.str();
 }
 
     /** Convert string to lower case.
@@ -107,7 +109,7 @@ inline std::string tolower(const char * s)
 inline std::string normalizeString(std::string const & s)
 {
     std::string res;
-    
+
     for(unsigned int k=0; k<s.size(); ++k)
     {
         if(std::isspace(s[k]))
@@ -122,8 +124,88 @@ inline std::string normalizeString(const char * s)
     return normalizeString(std::string(s));
 }
 
+namespace detail {
+
+template <class T>
+struct FinallyImpl
+{
+    T & destructor_;
+
+    FinallyImpl(T & destructor)
+    : destructor_(destructor)
+    {}
+
+    ~FinallyImpl()
+    {
+        destructor_();
+    }
+};
+
+} // namespace detail
+
 } // namespace vigra
 
+#define VIGRA_TOKEN_PASTE_IMPL(x, y) x##y
+#define VIGRA_TOKEN_PASTE(x, y) VIGRA_TOKEN_PASTE_IMPL(x, y)
+
+#define VIGRA_FINALLY_IMPL(destructor, counter) \
+    auto VIGRA_TOKEN_PASTE(_vigra_finally_impl_, counter) = [&]() { destructor; }; \
+    ::vigra::detail::FinallyImpl<decltype(VIGRA_TOKEN_PASTE(_vigra_finally_impl_, counter))> \
+        VIGRA_TOKEN_PASTE(_vigra_finally_, counter)(VIGRA_TOKEN_PASTE(_vigra_finally_impl_, counter))
+
+    /** Emulate the 'finally' keyword as known from Python and other languages.
+
+        This macro improves upon the famous
+        <a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">Resource Acquisition Is Initialization</a> idiom, where a resource (e.g. heap memory or a mutex) is automatically free'ed when program execution leaves the current scope. Normally, this is implemented by calling a suitable function in the destructor of a dedicated helper class (e.g. <tt>std::unique_ptr</tt> or <tt>std::lock_guard<std::mutex></tt>).
+
+        Traditionally, a separate helper class has to be implemented for each kind of resource to be handled. In contrast, the macro <tt>VIGRA_FINALLY</tt> creates such a class on the fly by means of an embedded lambda expression.
+
+        <b>Usage:</b>
+
+        <b>\#include</b> \<vigra/utilities.hxx\><br/>
+
+        \code
+        std::mutex my_mutex;
+        ...
+        {
+            // the following two lines are equivalent to
+            //     std::unique_ptr<std::string> my_string = new std::string("foo");
+            std::string * my_string = new std::string("foo");
+            VIGRA_FINALLY(delete my_string);
+
+            // the following two lines are equivalent to
+            //     std::lock_guard<std::mutex> lock(my_mutex);
+            my_mutex.lock();
+            VIGRA_FINALLY(my_mutex.unlock());
+
+            ...
+        }
+        // the string has been deallocated and the mutex is unlocked
+        \endcode
+
+        You can pass any code to this macro. Multiple statements must be enclosed in braces as usual. Arbitrary many calls to <tt>VIGRA_FINALLY</tt> can be placed in the same scope. Their actions will be executed in the reversed order of declaration:
+
+        \code
+        int i = 0;
+        ...
+        {
+            VIGRA_FINALLY({           // execute multiple statements
+                i = i*i;
+                ++i;
+            });
+
+            VIGRA_FINALLY( i += 2 );  // this executes first
+
+            assert(i == 0);           // as yet, nothing happend
+        }
+        assert(i == 5);               // 'finally' code was executed in reversed order at end-of-scope
+        \endcode
+
+        This idea was popularized by Marko Tintor in "<a href="http://blog.memsql.com/c-error-handling-with-auto/">The Auto Macro: A Clean Approach to C++ Error Handling</a>".
+    */
+#define VIGRA_FINALLY(destructor) \
+    VIGRA_FINALLY_IMPL(destructor, __COUNTER__)
+
 namespace std {
 
 template <class T1, class T2>
@@ -141,6 +223,8 @@ ostream & operator<<(ostream & s, std::pair<T1, T2> const & p)
     <UL style="list-style-image:url(documents/bullet.gif)">
     <LI> \ref vigra::ArrayVector
          <BR>   <em>replacement for std::vector (always uses consecutive memory)</em>
+    <LI> \ref vigra::Any
+         <BR>   <em>typesafe storage of arbitrary values</em>
     <LI> \ref vigra::BucketQueue and \ref vigra::MappedBucketQueue
          <BR>   <em>efficient priority queues for integer priorities</em>
     <LI> \ref RangesAndPoints
@@ -157,6 +241,8 @@ ostream & operator<<(ostream & s, std::pair<T1, T2> const & p)
          <BR>   <em>M_PI, M_SQRT2</em>
     <LI> \ref TimingMacros
          <BR>   <em>Macros for taking execution speed measurements</em>
+    <LI> \ref VIGRA_FINALLY
+         <BR>   <em>Emulation of the 'finally' keyword from Python</em>
     </UL>
 */
 
diff --git a/include/vigra/vector_distance.hxx b/include/vigra/vector_distance.hxx
new file mode 100644
index 0000000..f477043
--- /dev/null
+++ b/include/vigra/vector_distance.hxx
@@ -0,0 +1,534 @@
+/************************************************************************/
+/*                                                                      */
+/*    Copyright 2003-2015 by Philipp Schubert and Ullrich Koethe        */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_VECTOR_DISTANCE_HXX
+#define VIGRA_VECTOR_DISTANCE_HXX
+
+#include <vector>
+#include <set>
+#include <functional>
+#include "array_vector.hxx"
+#include "multi_array.hxx"
+#include "accessor.hxx"
+#include "numerictraits.hxx"
+#include "navigator.hxx"
+#include "metaprogramming.hxx"
+#include "multi_pointoperators.hxx"
+#include "functorexpression.hxx"
+#include "multi_distance.hxx"
+
+#undef VECTORIAL_DIST_DEBUG
+
+namespace vigra
+{
+
+namespace detail
+{
+
+template <class Vector, class Value>
+struct VectorialDistParabolaStackEntry
+{
+    double left, center, right;
+    Value apex_height;
+    Vector point;
+
+    VectorialDistParabolaStackEntry(const Vector& vec, Value prev, double l, double c, double r)
+    : left(l), center(c), right(r), apex_height(prev), point(vec)
+    {}
+};
+
+#ifdef VECTORIAL_DIST_DEBUG
+template <class Vector, class Value>
+std::ostream& operator<<(std::ostream&o, const VectorialDistParabolaStackEntry<Vector, Value>& e) {
+    o << "l=" << e.left << ", c=" << e.center << ", r=" << e.right << ", pV=" << e.apex_height << ", pVec=" << e.point;
+    return o;
+}
+#endif
+
+/********************************************************/
+/*                                                      */
+/*               vectorialDistParabola                  */
+/*                                                      */
+/********************************************************/
+
+template <class VEC, class ARRAY>
+inline double
+partialSquaredMagnitude(const VEC& vec, MultiArrayIndex dim, ARRAY const & pixel_pitch)
+{
+    //computes the squared magnitude of vec
+    //considering only the first dim dimensions
+    double sqMag = 0.0;
+    for(MultiArrayIndex i=0; i<=dim; ++i)
+    {
+        sqMag += sq(pixel_pitch[i]*vec[i]);
+    }
+    return sqMag;
+}
+
+template <class SrcIterator,
+          class Array>
+void
+vectorialDistParabola(MultiArrayIndex dimension,
+                      SrcIterator is, SrcIterator iend,
+                      Array const & pixel_pitch )
+{
+    typedef typename SrcIterator::value_type SrcType;
+    typedef VectorialDistParabolaStackEntry<SrcType, double> Influence;
+
+    double sigma = pixel_pitch[dimension],
+           sigma2 = sq(sigma);
+    double w = iend - is; //width of the scanline
+
+    SrcIterator id = is;
+
+    std::vector<Influence> _stack; //stack of influence parabolas
+    double apex_height = partialSquaredMagnitude(*is, dimension, pixel_pitch);
+    _stack.push_back(Influence(*is, apex_height, 0.0, 0.0, w));
+    ++is;
+    double current = 1.0;
+    while(current < w)
+    {
+        apex_height = partialSquaredMagnitude(*is, dimension, pixel_pitch);
+        Influence & s = _stack.back();
+        double diff = current - s.center;
+        double intersection = current + (apex_height - s.apex_height - sq(sigma*diff)) / (2.0*sigma2 * diff);
+
+        if( intersection < s.left) // previous point has no influence
+        {
+            _stack.pop_back();
+            if(_stack.empty())
+                _stack.push_back(Influence(*is, apex_height, 0.0, current, w));
+            else
+                continue; // try new top of stack without advancing current
+        }
+        else if(intersection < s.right)
+        {
+            s.right = intersection;
+            _stack.push_back(Influence(*is, apex_height, intersection, current, w));
+        }
+        ++is;
+        ++current;
+    }
+
+    // Now we have the stack indicating which rows are influenced by (and therefore
+    // closest to) which row. We can go through the stack and calculate the
+    // distance squared for each element of the column.
+    typename std::vector<Influence>::iterator it = _stack.begin();
+    for(current = 0.0; current < w; ++current, ++id)
+    {
+        while( current >= it->right)
+            ++it;
+
+        *id = it->point;
+        (*id)[dimension] = it->center - current;
+    }
+}
+
+template <class DestIterator,
+          class LabelIterator,
+          class Array1, class Array2>
+void
+boundaryVectorDistParabola(MultiArrayIndex dimension,
+                           DestIterator is, DestIterator iend,
+                           LabelIterator ilabels,
+                           Array1 const & pixel_pitch,
+                           Array2 const & dmax,
+                           bool array_border_is_active=false)
+{
+    double w = iend - is;
+    if(w <= 0)
+        return;
+
+    typedef typename LabelIterator::value_type LabelType;
+    typedef typename DestIterator::value_type DestType;
+    typedef VectorialDistParabolaStackEntry<DestType, double> Influence;
+    typedef std::vector<Influence> Stack;
+
+    DestIterator id = is;
+    DestType border_point = array_border_is_active
+                                ? DestType(0)
+                                : dmax;
+    double apex_height = partialSquaredMagnitude(border_point, dimension, pixel_pitch);
+    Stack _stack(1, Influence(border_point, apex_height, 0.0, -1.0, w));
+    LabelType current_label = *ilabels;
+    for(double begin = 0.0, current = 0.0; current <= w; ++ilabels, ++is, ++current)
+    {
+        DestType point = (current < w)
+                             ? (current_label == *ilabels)
+                                 ? *is
+                                 : DestType(0)
+                             : border_point;
+        apex_height = partialSquaredMagnitude(point, dimension, pixel_pitch);
+        while(true)
+        {
+            Influence & s = _stack.back();
+            double diff = (current - s.center)*pixel_pitch[dimension];
+            double intersection = current + (apex_height - s.apex_height - sq(diff)) / (2.0 * diff);
+
+            if(intersection < s.left) // previous parabola has no influence
+            {
+                _stack.pop_back();
+                if(_stack.empty())
+                    intersection = begin; // new parabola is valid for entire present segment
+                else
+                    continue;  // try new top of stack without advancing to next pixel
+            }
+            else if(intersection < s.right)
+            {
+                s.right = intersection;
+            }
+            if(intersection < w)
+                _stack.push_back(Influence(point, apex_height, intersection, current, w));
+            if(current < w && current_label == *ilabels)
+                break; // finished present pixel, advance to next one
+
+            // label changed => finalize the current segment
+            typename Stack::iterator it = _stack.begin();
+            for(double c = begin; c < current; ++c, ++id)
+            {
+                while(c >= it->right)
+                    ++it;
+                *id = it->point;
+                (*id)[dimension] = it->center - c;
+            }
+            if(current == w)
+                break;  // stop when this was the last segment
+
+            // initialize the new segment
+            begin = current;
+            current_label = *ilabels;
+            point = *is;
+            apex_height = partialSquaredMagnitude(point, dimension, pixel_pitch);
+            Stack(1, Influence(DestType(0), 0.0, begin-1.0, begin-1.0, w)).swap(_stack);
+            // don't advance to next pixel here, because the present pixel must also
+            // be analysed in the context of the new segment
+        }
+    }
+}
+
+template <unsigned int N, class T1, class S1,
+                          class T2, class S2,
+          class Array>
+void
+interpixelBoundaryVectorDistance(MultiArrayView<N, T1, S1> const & labels,
+                                 MultiArrayView<N, T2, S2> dest,
+                                 Array const & pixelPitch)
+{
+    typedef typename MultiArrayShape<N>::type  Shape;
+    typedef GridGraph<N>                       Graph;
+    typedef typename Graph::Node               Node;
+    typedef typename Graph::NodeIt             graph_scanner;
+    typedef typename Graph::OutArcIt           neighbor_iterator;
+
+    Graph g(labels.shape());
+    for (graph_scanner node(g); node != lemon_graph::INVALID; ++node)
+    {
+        T1 label = labels[*node];
+        double min_dist = NumericTraits<double>::max();
+        Node point    = *node,
+             boundary = point + Node(dest[point]),
+             min_pos  = lemon::INVALID;
+        T2 min_diff;
+
+        //go to adjacent neighbour with same label as origin pixel with smallest distance
+        if(labels.isInside(boundary))
+        {
+            for (neighbor_iterator arc(g, boundary); arc != lemon_graph::INVALID; ++arc)
+            {
+                if(label == labels[g.target(*arc)])
+                {
+                    double dist = squaredNorm(pixelPitch*(g.target(*arc) - point));
+                    if (dist < min_dist)
+                    {
+                        min_dist = dist;
+                        min_pos = g.target(*arc);
+                    }
+                }
+            }
+            if(min_pos == lemon::INVALID)
+                continue;
+            min_dist = NumericTraits<double>::max();
+        }
+        else
+        {
+            min_pos = clip(boundary, Shape(0), labels.shape()-Shape(1));
+            min_diff = 0.5*(boundary + min_pos) - point;
+            min_dist = squaredNorm(pixelPitch*min_diff);
+        }
+
+        //from this pixel look for the vector which points to the nearest interpixel between two label
+        for (neighbor_iterator arc(g, min_pos); arc != lemon_graph::INVALID; ++arc)
+        {
+            if(label != labels[g.target(*arc)])
+            {
+                T2 diff = 0.5*(g.target(*arc) + min_pos) - point;
+                double dist = squaredNorm(pixelPitch*diff);
+                if (dist < min_dist)
+                {
+                    min_dist = dist;
+                    min_diff = diff;
+                }
+            }
+        }
+        dest[point] = min_diff;
+    }
+}
+
+} // namespace detail
+
+/** \addtogroup MultiArrayDistanceTransform
+*/
+//@{
+
+template<bool PRED>
+struct Error_output_pixel_type_must_be_TinyVector_of_appropriate_length
+: vigra::staticAssert::AssertBool<PRED> {};
+
+/********************************************************/
+/*                                                      */
+/*               separableVectorDistance                */
+/*                                                      */
+/********************************************************/
+
+    /** \brief Compute the vector distance transform of a N-dimensional binary array.
+
+        <b> Declarations:</b>
+
+        \code
+        namespace vigra {
+            template <unsigned int N, class T1, class S1,
+                      class T2, class S2, class Array>
+            void
+            separableVectorDistance(MultiArrayView<N, T1, S1> const & source,
+                                    MultiArrayView<N, T2, S2> dest,
+                                    bool background,
+                                    Array const & pixelPitch=TinyVector<double, N>(1));
+        }
+        \endcode
+
+        This function works like \ref separableMultiDistance() (see there for details),
+        but returns in each pixel the <i>vector</i> to the nearest background pixel
+        rather than the scalar distance. This enables much more powerful applications.
+
+        <b> Usage:</b>
+
+        <b>\#include</b> \<vigra/vector_distance.hxx\><br/>
+        Namespace: vigra
+
+        \code
+        Shape3 shape(width, height, depth);
+        MultiArray<3, unsigned char> source(shape);
+        MultiArray<3, Shape3> dest(shape);
+        ...
+
+        // For each background pixel, find the vector to the nearest foreground pixel.
+        separableVectorDistance(source, dest, true);
+        \endcode
+
+        \see vigra::separableMultiDistance(), vigra::boundaryVectorDistance()
+    */
+doxygen_overloaded_function(template <...> void separableVectorDistance)
+
+template <unsigned int N, class T1, class S1,
+          class T2, class S2, class Array>
+void
+separableVectorDistance(MultiArrayView<N, T1, S1> const & source,
+                        MultiArrayView<N, T2, S2> dest,
+                        bool background,
+                        Array const & pixelPitch)
+{
+    using namespace vigra::functor;
+    typedef typename MultiArrayView<N, T2, S2>::traverser Traverser;
+    typedef MultiArrayNavigator<Traverser, N> Navigator;
+
+    VIGRA_STATIC_ASSERT((Error_output_pixel_type_must_be_TinyVector_of_appropriate_length<N == T2::static_size>));
+    vigra_precondition(source.shape() == dest.shape(),
+        "separableVectorDistance(): shape mismatch between input and output.");
+    vigra_precondition(pixelPitch.size() == N,
+        "separableVectorDistance(): pixelPitch has wrong length.");
+
+    T2 maxDist(2*sum(source.shape()*pixelPitch)), rzero;
+    if(background == true)
+        transformMultiArray( source, dest,
+                                ifThenElse( Arg1() == Param(0), Param(maxDist), Param(rzero) ));
+    else
+        transformMultiArray( source, dest,
+                                ifThenElse( Arg1() != Param(0), Param(maxDist), Param(rzero) ));
+
+    for(int d = 0; d < N; ++d )
+    {
+        Navigator nav( dest.traverser_begin(), dest.shape(), d);
+        for( ; nav.hasMore(); nav++ )
+        {
+             detail::vectorialDistParabola(d, nav.begin(), nav.end(), pixelPitch);
+        }
+    }
+}
+
+template <unsigned int N, class T1, class S1,
+          class T2, class S2>
+inline void
+separableVectorDistance(MultiArrayView<N, T1, S1> const & source,
+                        MultiArrayView<N, T2, S2> dest,
+                        bool background=true)
+{
+    TinyVector<double, N> pixelPitch(1.0);
+    separableVectorDistance(source, dest, background, pixelPitch);
+}
+
+
+    /** \brief Compute the vector distance transform to the implicit boundaries of a
+               multi-dimensional label array.
+
+        <b> Declarations:</b>
+
+        \code
+        namespace vigra {
+            template <unsigned int N, class T1, class S1,
+                                      class T2, class S2,
+                      class Array>
+            void
+            boundaryVectorDistance(MultiArrayView<N, T1, S1> const & labels,
+                                   MultiArrayView<N, T2, S2> dest,
+                                   bool array_border_is_active=false,
+                                   BoundaryDistanceTag boundary=OuterBoundary,
+                                   Array const & pixelPitch=TinyVector<double, N>(1));
+        }
+        \endcode
+
+        This function works like \ref boundaryMultiDistance() (see there for details),
+        but returns in each pixel the <i>vector</i> to the nearest boundary pixel
+        rather than the scalar distance. This enables much more powerful applications.
+        Additionally, it support a <tt>pixelPitch</tt> parameter which allows to adjust
+        the distance calculations for anisotropic grid resolution.
+
+        <b> Usage:</b>
+
+        <b>\#include</b> \<vigra/vector_distance.hxx\><br/>
+        Namespace: vigra
+
+        \code
+        Shape3 shape(width, height, depth);
+        MultiArray<3, UInt32> labels(shape);
+        MultiArray<3, Shape3> dest(shape);
+        ...
+
+        // For each region, find the vectors to the nearest boundary pixel, including the
+        // outer border of the array.
+        boundaryVectorDistance(labels, dest, true);
+        \endcode
+
+        \see vigra::boundaryMultiDistance(), vigra::separableVectorDistance()
+    */
+doxygen_overloaded_function(template <...> void boundaryVectorDistance)
+
+template <unsigned int N, class T1, class S1,
+                          class T2, class S2,
+          class Array>
+void
+boundaryVectorDistance(MultiArrayView<N, T1, S1> const & labels,
+                       MultiArrayView<N, T2, S2> dest,
+                       bool array_border_is_active,
+                       BoundaryDistanceTag boundary,
+                       Array const & pixelPitch)
+{
+    VIGRA_STATIC_ASSERT((Error_output_pixel_type_must_be_TinyVector_of_appropriate_length<N == T2::static_size>));
+    vigra_precondition(labels.shape() == dest.shape(),
+        "boundaryVectorDistance(): shape mismatch between input and output.");
+    vigra_precondition(pixelPitch.size() == N,
+        "boundaryVectorDistance(): pixelPitch has wrong length.");
+
+    using namespace vigra::functor;
+
+    if(boundary == InnerBoundary)
+    {
+        MultiArray<N, unsigned char> boundaries(labels.shape());
+
+        markRegionBoundaries(labels, boundaries, IndirectNeighborhood);
+        if(array_border_is_active)
+            initMultiArrayBorder(boundaries, 1, 1);
+        separableVectorDistance(boundaries, dest, true, pixelPitch);
+    }
+    else
+    {
+        if(boundary == InterpixelBoundary)
+        {
+            vigra_precondition(!NumericTraits<T2>::isIntegral::value,
+                "boundaryVectorDistance(..., InterpixelBoundary): output pixel type must be float or double.");
+        }
+
+        typedef typename MultiArrayView<N, T1, S1>::const_traverser LabelIterator;
+        typedef typename MultiArrayView<N, T2, S2>::traverser DestIterator;
+        typedef MultiArrayNavigator<LabelIterator, N> LabelNavigator;
+        typedef MultiArrayNavigator<DestIterator, N> DNavigator;
+
+        T2 maxDist(2*sum(labels.shape()*pixelPitch));
+        dest = maxDist;
+        for( int d = 0; d < N; ++d )
+        {
+            LabelNavigator lnav( labels.traverser_begin(), labels.shape(), d );
+            DNavigator dnav( dest.traverser_begin(), dest.shape(), d );
+
+            for( ; dnav.hasMore(); dnav++, lnav++ )
+            {
+                detail::boundaryVectorDistParabola(d, dnav.begin(), dnav.end(), lnav.begin(),
+                                                   pixelPitch, maxDist, array_border_is_active);
+            }
+        }
+
+        if(boundary == InterpixelBoundary)
+        {
+           detail::interpixelBoundaryVectorDistance(labels, dest, pixelPitch);
+        }
+    }
+}
+
+template <unsigned int N, class T1, class S1,
+                          class T2, class S2>
+void
+boundaryVectorDistance(MultiArrayView<N, T1, S1> const & labels,
+                       MultiArrayView<N, T2, S2> dest,
+                       bool array_border_is_active=false,
+                       BoundaryDistanceTag boundary=OuterBoundary)
+{
+    TinyVector<double, N> pixelPitch(1.0);
+    boundaryVectorDistance(labels, dest, array_border_is_active, boundary, pixelPitch);
+}
+
+//@}
+
+} //-- namespace vigra
+
+#endif        //-- VIGRA_VECTOR_DISTANCE_HXX
diff --git a/include/vigra/visit_border.hxx b/include/vigra/visit_border.hxx
new file mode 100644
index 0000000..cfde0d9
--- /dev/null
+++ b/include/vigra/visit_border.hxx
@@ -0,0 +1,179 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_VISIT_BORDER_HXX
+#define VIGRA_VISIT_BORDER_HXX
+
+#include "multi_array.hxx"
+
+namespace vigra
+{
+
+namespace visit_border_detail
+{
+
+template <unsigned int K>
+struct visit_border_impl
+{
+    template <unsigned int N, class Data, class S1,
+                              class Label, class S2,
+              class Shape, class Visitor>
+    static void exec(const MultiArrayView<N, Data, S1>& u_data, MultiArrayView<N, Label, S2> u_labels,
+                     const MultiArrayView<N, Data, S1>& v_data, MultiArrayView<N, Label, S2> v_labels,
+                     const Shape& block_difference, NeighborhoodType neighborhood, Visitor visitor)
+    {
+        static const unsigned int D = K - 1;
+        typedef visit_border_impl<D> next;
+        
+        if(block_difference[D] == -1)
+        {
+            MultiArrayIndex last = v_data.shape(D) - 1;
+            next::exec(u_data.bindAt(D, 0), u_labels.bindAt(D, 0),
+                       v_data.bindAt(D, last), v_labels.bindAt(D, last),
+                       block_difference, neighborhood, visitor);
+        }
+        else if(block_difference[D] == 1)
+        {
+            MultiArrayIndex last = u_data.shape(D) - 1;
+            next::exec(u_data.bindAt(D, last), u_labels.bindAt(D, last),
+                       v_data.bindAt(D, 0), v_labels.bindAt(D, 0),
+                       block_difference, neighborhood, visitor);
+        }
+        else if(block_difference[D] == 0)
+        {
+            next::exec(u_data, u_labels, v_data, v_labels, block_difference, neighborhood, visitor);
+        }
+        else
+        {
+            vigra_precondition(false, "invalid block difference");
+        }
+    }
+};
+
+template <>
+struct visit_border_impl<0>
+{
+    template <class Data, class S1,
+              class Label, class S2,
+              class Shape, class Visitor>
+    static void exec(const MultiArrayView<0, Data, S1>& u_data, MultiArrayView<0, Label, S2> u_labels,
+                     const MultiArrayView<0, Data, S1>& v_data, MultiArrayView<0, Label, S2> v_labels,
+                     const Shape& block_difference, NeighborhoodType neighborhood, Visitor visitor)
+    {
+        visitor(u_data(0), u_labels(0), v_data(0), v_labels(0), block_difference);
+    }
+    template <unsigned int N, class Data, class S1,
+                              class Label, class S2,
+              class Shape, class Visitor>
+    static void exec(const MultiArrayView<N, Data, S1>& u_data, MultiArrayView<N, Label, S2> u_labels,
+                     const MultiArrayView<N, Data, S1>& v_data, MultiArrayView<N, Label, S2> v_labels,
+                     const Shape& block_difference, NeighborhoodType neighborhood, Visitor visitor)
+    {
+        if(neighborhood == DirectNeighborhood)
+        {
+            typedef typename MultiArrayView<N, Data, S1>::const_iterator DataIterator;
+            typedef typename MultiArrayView<N, Label, S2>::iterator LabelsIterator;
+
+            DataIterator u_data_it = u_data.begin();
+            LabelsIterator u_labels_it = u_labels.begin();
+
+            DataIterator v_data_it = v_data.begin();
+            LabelsIterator v_labels_it = v_labels.begin();
+
+            for( ; u_data_it != u_data.end(); ++u_data_it, ++u_labels_it, ++v_data_it, ++v_labels_it)
+            {
+                visitor(*u_data_it, *u_labels_it, *v_data_it, *v_labels_it, block_difference);
+            }
+        } 
+        else if(neighborhood == IndirectNeighborhood)
+        {
+            typedef GridGraph<N, undirected_tag> Graph;
+            typedef typename Graph::NodeIt GraphScanner;
+            typedef typename Graph::OutArcIt NeighborIterator;
+            
+            static const int global_dim_number = Shape::static_size;
+            TinyVector<unsigned int, N> dim_mapping; // mapping of every local dimension to their actual global dimension indices
+            int local_dims_pos = 0;
+            int global_dims_pos = 0;
+            for( ; global_dims_pos != global_dim_number; ++global_dims_pos)
+            {
+                if(block_difference[global_dims_pos] == 0)
+                {
+                    vigra_assert(local_dims_pos != N, "");
+                    dim_mapping[local_dims_pos] = global_dims_pos;
+                    ++local_dims_pos;
+                }
+            }
+            vigra_assert(local_dims_pos == N, "");
+
+            Graph graph(u_data.shape(), neighborhood);
+            Shape pixel_difference = block_difference;
+            for(GraphScanner node(graph); node != lemon::INVALID; ++node)
+            {
+                // compare neighbors that have have equal coordinates in all unbound dimensions
+                // their pixel-level difference is exactly block_difference
+                visitor(u_data[*node], u_labels[*node], v_data[*node], v_labels[*node], block_difference);
+                // now let unbound dimensions vary
+                for(NeighborIterator arc(graph, *node); arc != lemon::INVALID; ++arc)
+                {
+                    for(int i = 0; i != N; ++i)
+                        pixel_difference[dim_mapping[i]] = graph.target(*arc)[i] - (*node)[i];
+                    visitor(u_data[*node], u_labels[*node], v_data[graph.target(*arc)], v_labels[graph.target(*arc)], pixel_difference);
+                }
+            }
+        }
+    }
+};
+
+} // namespace visit_border_detail
+
+template <unsigned int N, class Data, class S1,
+                          class Label, class S2,
+          class Shape, class Visitor>
+inline void 
+visitBorder(const MultiArrayView<N, Data, S1>& u_data, MultiArrayView<N, Label, S2> u_labels,
+            const MultiArrayView<N, Data, S1>& v_data, MultiArrayView<N, Label, S2> v_labels,
+            const Shape& difference, NeighborhoodType neighborhood, Visitor visitor)
+{
+    vigra_precondition(u_data.shape() == u_labels.shape() && v_data.shape() == v_labels.shape(),
+                       "differing block shapes");
+    visit_border_detail::visit_border_impl<N>::exec(u_data, u_labels,
+                                                    v_data, v_labels,
+                                                    difference, neighborhood, visitor);
+}
+
+} // namespace vigra
+
+#endif // VIGRA_VISIT_BORDER_HXX
diff --git a/include/vigra/watersheds.hxx b/include/vigra/watersheds.hxx
index 288ccfb..0e185e0 100644
--- a/include/vigra/watersheds.hxx
+++ b/include/vigra/watersheds.hxx
@@ -69,7 +69,7 @@ unsigned int watershedLabeling(SrcIterator upperlefts,
     DestIterator xd(yd);
 
     // temporary image to store region labels
-    detail::UnionFindArray<LabelType> labels;
+    UnionFindArray<LabelType> labels;
 
     // initialize the neighborhood circulators
     NeighborOffsetCirculator<Neighborhood> ncstart(Neighborhood::CausalFirst);
@@ -92,7 +92,7 @@ unsigned int watershedLabeling(SrcIterator upperlefts,
     // tree is distinguished by pointing to itself (it contains its
     // own scan order address). This condition is enforced whenever a
     // new region is found or two regions are merged
-    da.set(labels.finalizeLabel(labels.nextFreeLabel()), xd);
+    da.set(labels.finalizeIndex(labels.nextFreeIndex()), xd);
 
     ++xs.x;
     ++xd.x;
@@ -105,7 +105,7 @@ unsigned int watershedLabeling(SrcIterator upperlefts,
         }
         else
         {
-            da.set(labels.finalizeLabel(labels.nextFreeLabel()), xd);
+            da.set(labels.finalizeIndex(labels.nextFreeIndex()), xd);
         }
     }
 
@@ -124,15 +124,15 @@ unsigned int watershedLabeling(SrcIterator upperlefts,
             NeighborOffsetCirculator<Neighborhood> nce(x == 0
                                                          ? ncendBorder
                                                          : ncend);
-            LabelType currentLabel = labels.nextFreeLabel();
+            LabelType currentIndex = labels.nextFreeIndex();
             for(; nc != nce; ++nc)
             {
                 if((sa(xs) & nc.directionBit()) || (sa(xs, *nc) & nc.oppositeDirectionBit()))
                 {
-                    currentLabel = labels.makeUnion(da(xd,*nc), currentLabel);
+                    currentIndex = labels.makeUnion(da(xd,*nc), currentIndex);
                 }
             }
-            da.set(labels.finalizeLabel(currentLabel), xd);
+            da.set(labels.finalizeIndex(currentIndex), xd);
         }
     }
 
@@ -146,7 +146,7 @@ unsigned int watershedLabeling(SrcIterator upperlefts,
         DestIterator xd(yd);
         for(x = 0; x != w; ++x, ++xd.x)
         {
-            da.set(labels[da(xd)], xd);
+            da.set(labels.findLabel(da(xd)), xd);
         }
     }
     return count;
diff --git a/include/vigra/watersheds3d.hxx b/include/vigra/watersheds3d.hxx
index 0ef3258..6e93dba 100644
--- a/include/vigra/watersheds3d.hxx
+++ b/include/vigra/watersheds3d.hxx
@@ -141,7 +141,7 @@ unsigned int watershedLabeling3D( SrcIterator s_Iter, SrcShape srcShape, SrcAcce
     DestIterator zd = d_Iter;
         
     // temporary image to store region labels
-    detail::UnionFindArray<LabelType> labels;
+    UnionFindArray<LabelType> labels;
     
     // initialize the neighborhood traversers
     NeighborOffsetCirculator<Neighborhood3D> nc(Neighborhood3D::CausalFirst);
@@ -172,7 +172,7 @@ unsigned int watershedLabeling3D( SrcIterator s_Iter, SrcShape srcShape, SrcAcce
 
             for(x = 0; x != w; ++x, ++xs.dim0(), ++xd.dim0())
             {
-                LabelType currentLabel = labels.nextFreeLabel(); // default: new region    
+                LabelType currentIndex = labels.nextFreeIndex(); // default: new region    
 
                 //check whether there is a special border treatment to be used or not
                 AtVolumeBorder atBorder = isAtVolumeBorderCausal(x,y,z,w,h,d);
@@ -189,7 +189,7 @@ unsigned int watershedLabeling3D( SrcIterator s_Iter, SrcShape srcShape, SrcAcce
                         // = Direction of voxel           towards us?
                         if((sa(xs) & nc.directionBit()) || (sa(xs,*nc) & nc.oppositeDirectionBit()))
                         {
-                            currentLabel = labels.makeUnion(da(xd,*nc), currentLabel);
+                            currentIndex = labels.makeUnion(da(xd,*nc), currentIndex);
                         }
                         ++nc;
                     }while(nc!=nce);
@@ -201,16 +201,21 @@ unsigned int watershedLabeling3D( SrcIterator s_Iter, SrcShape srcShape, SrcAcce
                     int j=0;
                     while(nc.direction() != Neighborhood3D::Error)
                     {
+                        int dummy = x+(*nc)[0];  // prevents an apparently incorrect optimization in gcc 4.8
+                        if (dummy<0)
+                        {  
+                            std::cerr << "internal error " << dummy << std::endl;
+                        }
                         //   Direction of NTraversr       Neighbor's direction bit is pointing
                         // = Direction of voxel           towards us?
                         if((sa(xs) & nc.directionBit()) || (sa(xs,*nc) & nc.oppositeDirectionBit()))
                         {
-                            currentLabel = labels.makeUnion(da(xd,*nc), currentLabel);
+                            currentIndex = labels.makeUnion(da(xd,*nc), currentIndex);
                         }
                         nc.turnTo(Neighborhood3D::nearBorderDirectionsCausal(atBorder,++j));
                     }
                 }
-                da.set(labels.finalizeLabel(currentLabel), xd);
+                da.set(labels.finalizeIndex(currentIndex), xd);
             }
         }
     }
@@ -230,7 +235,7 @@ unsigned int watershedLabeling3D( SrcIterator s_Iter, SrcShape srcShape, SrcAcce
 
             for(x = 0; x != w; ++x, ++xd.dim0())
             {
-                da.set(labels[da(xd)], xd);
+                da.set(labels.findLabel(da(xd)), xd);
             }
         }
     }
diff --git a/include/vigra/windows.h b/include/vigra/windows.h
index 5bfa061..7326cc6 100644
--- a/include/vigra/windows.h
+++ b/include/vigra/windows.h
@@ -54,6 +54,12 @@
 # ifdef DIFFERENCE
 #  undef DIFFERENCE
 # endif
+# ifdef IN
+#  undef IN
+# endif
+# ifdef OUT
+#  undef OUT
+# endif
 #endif
 
 #endif /* VIGRA_WINDOWS_H */
diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt
index cb78217..36f1c5e 100644
--- a/src/examples/CMakeLists.txt
+++ b/src/examples/CMakeLists.txt
@@ -13,6 +13,7 @@ SET(TARGETS
     watershed
     weightedWatersheds
     voronoi
+    nnlsq
     total_variation)
 
 ADD_CUSTOM_TARGET(examples)
diff --git a/src/examples/nnlsq.cxx b/src/examples/nnlsq.cxx
new file mode 100644
index 0000000..7907c87
--- /dev/null
+++ b/src/examples/nnlsq.cxx
@@ -0,0 +1,55 @@
+#include <iostream>
+#include <vigra/matrix.hxx>
+#include <vigra/regression.hxx>
+#include <vigra/quadprog.hxx>
+
+double A_data[] = {
+     1, -3,  2,
+    -3, 10, -5,
+     2, -5,  6
+};
+
+double b_data[] = {
+     27, 
+    -78, 
+     64
+};
+
+int main()
+{
+    using namespace vigra;
+    using namespace vigra::linalg;
+    
+    Matrix<double> A(Shape2(3,3), A_data);
+    Matrix<double> b(Shape2(3,1), b_data);
+    Matrix<double> x(Shape2(3,1));
+    
+     // minimize (A*x-b)^2  s.t. x>=0 using least angle regression (LARS algorithm)
+    nonnegativeLeastSquares(A, b, x);
+
+    std::cout << "solution LARS: ";
+    for(int k=0; k<3; ++k)
+        std::cout << x(k,0) << ", ";
+    std::cout << "\n";
+    
+    // expected output:
+    // solution LARS: 18.4493, 0, 4.50725,
+    
+    Matrix<double> eye(identityMatrix<double>(3)),
+                   zeros(Shape2(3,1)),
+                   empty,
+                   U =  transpose(A)*A,
+                   v = -transpose(A)*b;
+    x = 0;
+    
+     // minimize (A*x-b)^2  s.t. x>=0 using the Goldfarb-Idnani algorithm
+    quadraticProgramming(U, v, empty, empty, eye, zeros, x);
+    
+    std::cout << "solution Goldfarb-Idnani: ";
+    for(int k=0; k<3; ++k)
+        std::cout << x(k,0) << ", ";
+    std::cout << "\n";
+    
+    // expected output:
+    // solution Goldfarb-Idnani: 18.4493, 0, 4.50725,
+}
diff --git a/src/impex/CMakeLists.txt b/src/impex/CMakeLists.txt
index 80aa035..da9a76c 100644
--- a/src/impex/CMakeLists.txt
+++ b/src/impex/CMakeLists.txt
@@ -1,13 +1,18 @@
-IF(JPEG_FOUND)
-  ADD_DEFINITIONS(-DHasJPEG)
-  INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR})
-ENDIF(JPEG_FOUND)
+IF(ZLIB_FOUND)
+  ADD_DEFINITIONS(-DHasZLIB)
+  INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
+ENDIF(ZLIB_FOUND)
 
 IF(PNG_FOUND)
   ADD_DEFINITIONS(-DHasPNG)
   INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR})
 ENDIF(PNG_FOUND)
 
+IF(JPEG_FOUND)
+  ADD_DEFINITIONS(-DHasJPEG)
+  INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR})
+ENDIF(JPEG_FOUND)
+
 IF(TIFF_FOUND)
   ADD_DEFINITIONS(-DHasTIFF)
   INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR})
@@ -33,10 +38,14 @@ ELSEIF(CMAKE_COMPILER_IS_GNUCXX)
     ENDIF()
 ENDIF ()
 
+
+
+
 ADD_LIBRARY(vigraimpex ${LIBTYPE}
     bmp.cxx
     byteorder.cxx
     codecmanager.cxx
+    compression.cxx
     exr.cxx
     gif.cxx
     hdr.cxx
@@ -45,6 +54,7 @@ ADD_LIBRARY(vigraimpex ${LIBTYPE}
     iccjpeg.c
     imageinfo.cxx
     jpeg.cxx
+    lz4.c
     png.cxx
     pnm.cxx
     rgbe.c
@@ -54,7 +64,7 @@ ADD_LIBRARY(vigraimpex ${LIBTYPE}
     viff.cxx
     void_vector.cxx)
 
-set(SOVERSION 5)  # increment this after changing the vigraimpex library
+set(SOVERSION 6)  # increment this after changing the vigraimpex library
 IF(MACOSX)
     SET_TARGET_PROPERTIES(vigraimpex PROPERTIES VERSION ${SOVERSION}.${vigra_version} 
                          SOVERSION ${SOVERSION} INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}")
@@ -82,6 +92,11 @@ IF(HDF5_FOUND)
   TARGET_LINK_LIBRARIES(vigraimpex ${HDF5_LIBRARIES})
 ENDIF(HDF5_FOUND)
 
+IF(ZLIB_FOUND)
+  TARGET_LINK_LIBRARIES(vigraimpex ${ZLIB_LIBRARIES})
+ENDIF(ZLIB_FOUND)
+
+
 INSTALL(TARGETS vigraimpex
         EXPORT vigra-targets
         RUNTIME DESTINATION bin 
diff --git a/src/impex/bmp.cxx b/src/impex/bmp.cxx
index c1458d5..7fce8aa 100644
--- a/src/impex/bmp.cxx
+++ b/src/impex/bmp.cxx
@@ -792,7 +792,7 @@ void BmpDecoderImpl::read_rgb_data ()
 
 void BmpDecoder::init( const std::string & filename )
 {
-    pimpl = new BmpDecoderImpl( filename.c_str() );
+    pimpl = new BmpDecoderImpl( filename );
 }
 
 BmpDecoder::~BmpDecoder()
diff --git a/src/impex/compression.cxx b/src/impex/compression.cxx
new file mode 100644
index 0000000..8a7ebf1
--- /dev/null
+++ b/src/impex/compression.cxx
@@ -0,0 +1,204 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2013-2014 by Ullrich Koethe                  */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#include <algorithm>
+#include "vigra/compression.hxx"
+#include "lz4.h"
+
+#ifdef HasZLIB
+#include <zlib.h>
+#endif
+
+namespace vigra {
+
+std::size_t compressImpl(char const * source, std::size_t srcSize, 
+                         ArrayVector<char> & buffer,
+                         CompressionMethod method)
+{
+    switch(method)
+    {
+      case NO_COMPRESSION:
+      {
+        ArrayVector<char>(source, source+srcSize).swap(buffer);
+        return srcSize;
+      }
+      case ZLIB:
+      case ZLIB_NONE:
+      case ZLIB_FAST:
+      case ZLIB_BEST:
+      {
+    #ifdef HasZLIB
+        uLong destSize = ::compressBound(srcSize);
+        buffer.resize(destSize);
+        int res = ::compress2((Bytef *)buffer.data(), &destSize, (Bytef *)source, srcSize, method);
+        vigra_postcondition(res == Z_OK, "compress(): zlib compression failed.");                    
+        return destSize;
+    #else
+        vigra_precondition(false, "compress(): VIGRA was compiled without ZLIB compression.");
+        return 0;
+    #endif
+      }
+      case DEFAULT_COMPRESSION:
+      case LZ4:
+      {
+        std::size_t destSize = ::LZ4_compressBound(srcSize);
+        buffer.resize(destSize);
+        destSize = ::LZ4_compress(source, buffer.data(), srcSize);
+        vigra_postcondition(destSize > 0, "compress(): lz4 compression failed.");
+        return destSize;
+      }
+
+#if 0  // currently unsupported
+      case SNAPPY:
+      {
+    #ifdef HasSNAPPY
+        std::size_t destSize = snappy::MaxCompressedLength(srcSize);
+        buffer.resize(destSize);
+        snappy::RawCompress(source, srcSize, buffer.data(), &destSize);
+        return destSize;
+    #else
+        vigra_precondition(false, "compress(): VIGRA was compiled without SNAPPY compression.");
+        return 0;
+    #endif
+      }
+      case LZO:
+      {
+    #ifdef HasLZO
+        static const int workmemSize = 
+                  (LZO1X_1_MEM_COMPRESS + sizeof(lzo_align_t) - 1) / sizeof(lzo_align_t);
+        ArrayVector<lzo_align_t> wrkmem(workmemSize);
+        
+        lzo_uint destSize = srcSize + srcSize / 16 + 64 + 3;
+        buffer.resize(destSize);
+        int res = ::lzo1x_1_compress((const lzo_bytep)source, srcSize, 
+                                     (lzo_bytep)buffer.data(), &destSize, 
+                                     wrkmem.data());
+        return destSize;
+    #else
+        vigra_precondition(false, "compress(): VIGRA was compiled without LZO compression.");
+        return 0;
+    #endif
+      }
+#endif
+      default:
+        vigra_precondition(false, "compress(): Unknown compression method.");
+    }
+    return 0;
+}
+
+void compress(char const * source, std::size_t size, ArrayVector<char> & dest, CompressionMethod method)
+{
+    ArrayVector<char> buffer;
+    std::size_t destSize = compressImpl(source, size, buffer, method);
+    dest.resize(destSize);
+    std::copy(buffer.data(), buffer.data() + destSize, dest.begin());
+}
+
+void compress(char const * source, std::size_t size, std::vector<char> & dest, CompressionMethod method)
+{
+    ArrayVector<char> buffer;
+    std::size_t destSize = compressImpl(source, size, buffer, method);
+    dest.insert(dest.begin(), buffer.data(), buffer.data() + destSize);
+}
+
+void uncompress(char const * source, std::size_t srcSize, 
+                char * dest, std::size_t destSize, CompressionMethod method)
+{
+    switch(method)
+    {
+      case NO_COMPRESSION:
+      {
+        std::copy(source, source+srcSize, dest);
+        break;
+      }
+      case ZLIB:
+      case ZLIB_NONE:
+      case ZLIB_FAST:
+      case ZLIB_BEST:
+      {
+    #ifdef HasZLIB
+        uLong destLen = destSize;
+        int res = ::uncompress((Bytef *)dest, &destLen, (Bytef *)source, srcSize);
+        vigra_postcondition(res == Z_OK, "uncompress(): zlib decompression failed.");
+    #else
+        vigra_precondition(false, "uncompress(): VIGRA was compiled without ZLIB compression.");
+    #endif
+        break;
+      }
+      case DEFAULT_COMPRESSION:
+      case LZ4:
+      {
+        int sourceLen = ::LZ4_decompress_fast(source, dest, destSize);
+        vigra_postcondition(sourceLen == srcSize, "uncompress(): lz4 decompression failed.");
+        break;
+      }
+      
+#if 0 // currently unsupported
+      case SNAPPY:
+      {
+    #ifdef HasSNAPPY
+        snappy::RawUncompress(source, srcSize, dest);
+    #else
+        vigra_precondition(false, "compress(): VIGRA was compiled without SNAPPY compression.");
+    #endif
+        break;
+      }
+      case LZO:
+      {
+    #ifdef HasLZO
+        lzo_uint destLen = destSize;
+        int res = ::lzo1x_decompress((const lzo_bytep)source, srcSize,
+                                     (lzo_bytep)dest, &destLen, NULL);
+        vigra_postcondition(res == LZO_E_OK, "uncompress(): lzo decompression failed.");
+    #else
+        vigra_precondition(false, "compress(): VIGRA was compiled without LZO compression.");
+    #endif
+        break;
+      }
+#endif
+      default:
+        vigra_precondition(false, "uncompress(): Unknown compression method.");
+    }
+}
+
+/** Uncompress a data buffer when the uncompressed size is unknown.
+
+    The destination array will be resized as required.
+*/
+void uncompress(char const * source, std::size_t size, ArrayVector<char> & dest, CompressionMethod method);
+void uncompress(char const * source, std::size_t size, std::vector<char> & dest, CompressionMethod method);
+
+
+} // namespace vigra
diff --git a/src/impex/gif.cxx b/src/impex/gif.cxx
index ea0d70a..88f19c1 100644
--- a/src/impex/gif.cxx
+++ b/src/impex/gif.cxx
@@ -482,12 +482,12 @@ namespace {
             in_code,
             old_code;
 
-        register int
+        int
             bits,
             code,
             count;
 
-        register unsigned long
+        unsigned long
         datum;
 
         void_vector<Int16> prefix(MaxStackSize);
@@ -496,8 +496,8 @@ namespace {
         void_vector<UInt8> packet(256);
         void_vector<UInt16> indices(header.width*header.height);
 
-        register UInt8 *c;
-        register UInt16 *p = indices.begin();
+        UInt8 *c;
+        UInt16 *p = indices.begin();
 
         UInt8
         data_size,
@@ -624,7 +624,7 @@ namespace {
 
             int pass, x, y;
 
-            register UInt16 *q;
+            UInt16 *q;
 
             static int
               interlace_rate[4] = { 8, 8, 4, 2 },
@@ -891,9 +891,9 @@ namespace {
         long
           datum;
 
-        register int k;
+        int k;
 
-        register UInt8 *p;
+        UInt8 *p;
 
         void_vector<Int16> hash_code(MaxHashTable);
         void_vector<Int16> hash_prefix(MaxHashTable);
diff --git a/src/impex/hdf5impex.cxx b/src/impex/hdf5impex.cxx
index af0107c..45b8c29 100644
--- a/src/impex/hdf5impex.cxx
+++ b/src/impex/hdf5impex.cxx
@@ -45,12 +45,12 @@ namespace vigra {
 
 HDF5ImportInfo::HDF5ImportInfo(const char* filePath, const char* pathInFile)
 {
-    m_file_handle = HDF5Handle(H5Fopen(filePath, H5F_ACC_RDONLY, H5P_DEFAULT),
-                               &H5Fclose, "HDF5ImportInfo(): Unable to open file.");
+    m_file_handle = HDF5HandleShared(H5Fopen(filePath, H5F_ACC_RDONLY, H5P_DEFAULT),
+                                     &H5Fclose, "HDF5ImportInfo(): Unable to open file.");
 
 
-    m_dataset_handle = HDF5Handle(H5Dopen(m_file_handle, pathInFile, H5P_DEFAULT),
-                                  &H5Dclose, "HDF5ImportInfo(): Unable to open dataset.");
+    m_dataset_handle = HDF5HandleShared(H5Dopen(m_file_handle, pathInFile, H5P_DEFAULT),
+                                        &H5Dclose, "HDF5ImportInfo(): Unable to open dataset.");
 
 
     //DataSet dset = m_file.openDataSet(datasetname);
@@ -194,9 +194,8 @@ void HDF5_ls_insert(void* operator_data, const std::string & x)
 {
     static_cast<HDF5File::ls_closure*>(operator_data)->insert(x);
 }
-// callback function for ls(), called via HDF5File::H5Literate()
-// see http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
-// for as to why.
+
+// callback function for ls(), called via HDF5File::ls_H5Literate()
 extern "C"
 herr_t HDF5_ls_inserter_callback(hid_t loc_id, const char* name,
                                  const H5L_info_t*, void* operator_data)
@@ -214,6 +213,15 @@ herr_t HDF5_ls_inserter_callback(hid_t loc_id, const char* name,
     return 0;
 }
 
+// callback function for listAttributes(), called via HDF5File::ls_H5Literate()
+extern "C"
+herr_t HDF5_listAttributes_inserter_callback(hid_t loc_id, const char* name,
+                                             const H5A_info_t*, void* operator_data)
+{
+    HDF5_ls_insert(operator_data, name);
+    return 0;
+}
+
 } // namespace vigra
 
 #endif // HasHDF5
diff --git a/src/impex/imageinfo.cxx b/src/impex/imageinfo.cxx
index a48f295..2420347 100644
--- a/src/impex/imageinfo.cxx
+++ b/src/impex/imageinfo.cxx
@@ -117,7 +117,7 @@ std::string trimString(const std::string &s)
 
 
 // find filenames matching the pattern "<path>/base[0-9]+ext"
-#ifdef _WIN32
+#ifdef _MSC_VER
 void splitPathFromFilename(const std::string &pathAndName,
                            std::string &path, std::string &name)
 {
@@ -203,7 +203,7 @@ VIGRA_EXPORT void findImageSequence(const std::string &name_base,
     numbers.swap(result);
 }
 
-#else // _WIN32
+#else // not _MSC_VER
 
 void splitPathFromFilename(const std::string &pathAndName,
                            std::string &path, std::string &name)
@@ -266,7 +266,7 @@ void findImageSequence(const std::string &name_base,
     numbers.swap(result);
 }
 
-#endif // _WIN32
+#endif // _MSC_VER
 
 // build a string from a sequence.
 #if defined(_MSC_VER) && (_MSC_VER < 1300)
diff --git a/src/impex/lz4.c b/src/impex/lz4.c
new file mode 100644
index 0000000..f521b0f
--- /dev/null
+++ b/src/impex/lz4.c
@@ -0,0 +1,865 @@
+/*
+   LZ4 - Fast LZ compression algorithm
+   Copyright (C) 2011-2013, Yann Collet.
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - LZ4 source repository : http://code.google.com/p/lz4/
+   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+
+//**************************************
+// Tuning parameters
+//**************************************
+// MEMORY_USAGE :
+// Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+// Increasing memory usage improves compression ratio
+// Reduced memory usage can improve speed, due to cache effect
+// Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
+#define MEMORY_USAGE 14
+
+// HEAPMODE :
+// Select how default compression functions will allocate memory for their hash table,
+// in memory stack (0:default, fastest), or in memory heap (1:requires memory allocation (malloc)).
+#define HEAPMODE 0
+
+
+//**************************************
+// CPU Feature Detection
+//**************************************
+// 32 or 64 bits ?
+#if (defined(__x86_64__) || defined(_M_X64) || defined(_WIN64) \
+  || defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) \
+  || defined(__64BIT__) || defined(_LP64) || defined(__LP64__) \
+  || defined(__ia64) || defined(__itanium__) || defined(_M_IA64) )   // Detects 64 bits mode
+#  define LZ4_ARCH64 1
+#else
+#  define LZ4_ARCH64 0
+#endif
+
+// Little Endian or Big Endian ?
+// Overwrite the #define below if you know your architecture endianess
+#if defined (__GLIBC__)
+#  include <endian.h>
+#  if (__BYTE_ORDER == __BIG_ENDIAN)
+#     define LZ4_BIG_ENDIAN 1
+#  endif
+#elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN))
+#  define LZ4_BIG_ENDIAN 1
+#elif defined(__sparc) || defined(__sparc__) \
+   || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \
+   || defined(__hpux)  || defined(__hppa) \
+   || defined(_MIPSEB) || defined(__s390__)
+#  define LZ4_BIG_ENDIAN 1
+#else
+// Little Endian assumed. PDP Endian and other very rare endian format are unsupported.
+#endif
+
+// Unaligned memory access is automatically enabled for "common" CPU, such as x86.
+// For others CPU, such as ARM, the compiler may be more cautious, inserting unnecessary extra code to ensure aligned access property
+// If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance
+#if defined(__ARM_FEATURE_UNALIGNED)
+#  define LZ4_FORCE_UNALIGNED_ACCESS 1
+#endif
+
+// Define this parameter if your target system or compiler does not support hardware bit count
+#if defined(_MSC_VER) && defined(_WIN32_WCE)            // Visual Studio for Windows CE does not support Hardware bit count
+#  define LZ4_FORCE_SW_BITCOUNT
+#endif
+
+// BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE :
+// This option may provide a small boost to performance for some big endian cpu, although probably modest.
+// You may set this option to 1 if data will remain within closed environment.
+// This option is useless on Little_Endian CPU (such as x86)
+//#define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1
+
+
+//**************************************
+// Compiler Options
+//**************************************
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)   // C99
+/* "restrict" is a known keyword */
+#else
+#  define restrict // Disable restrict
+#endif
+
+#ifdef _MSC_VER    // Visual Studio
+#  define FORCE_INLINE static __forceinline
+#  include <intrin.h>                    // For Visual 2005
+#  if LZ4_ARCH64   // 64-bits
+#    pragma intrinsic(_BitScanForward64) // For Visual 2005
+#    pragma intrinsic(_BitScanReverse64) // For Visual 2005
+#  else            // 32-bits
+#    pragma intrinsic(_BitScanForward)   // For Visual 2005
+#    pragma intrinsic(_BitScanReverse)   // For Visual 2005
+#  endif
+#  pragma warning(disable : 4127)        // disable: C4127: conditional expression is constant
+#else
+#  ifdef __GNUC__
+#    define FORCE_INLINE static inline __attribute__((always_inline))
+#  else
+#    define FORCE_INLINE static inline
+#  endif
+#endif
+
+#ifdef _MSC_VER
+#  define lz4_bswap16(x) _byteswap_ushort(x)
+#else
+#  define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8)))
+#endif
+
+#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
+#  define expect(expr,value)    (__builtin_expect ((expr),(value)) )
+#else
+#  define expect(expr,value)    (expr)
+#endif
+
+#define likely(expr)     expect((expr) != 0, 1)
+#define unlikely(expr)   expect((expr) != 0, 0)
+
+
+//**************************************
+// Memory routines
+//**************************************
+#include <stdlib.h>   // malloc, calloc, free
+#define ALLOCATOR(n,s) calloc(n,s)
+#define FREEMEM        free
+#include <string.h>   // memset, memcpy
+#define MEM_INIT       memset
+
+
+//**************************************
+// Includes
+//**************************************
+#include "lz4.h"
+
+
+//**************************************
+// Basic Types
+//**************************************
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   // C99
+# include <stdint.h>
+  typedef  uint8_t BYTE;
+  typedef uint16_t U16;
+  typedef uint32_t U32;
+  typedef  int32_t S32;
+  typedef uint64_t U64;
+#else
+  typedef unsigned char       BYTE;
+  typedef unsigned short      U16;
+  typedef unsigned int        U32;
+  typedef   signed int        S32;
+  typedef unsigned long long  U64;
+#endif
+
+#if defined(__GNUC__)  && !defined(LZ4_FORCE_UNALIGNED_ACCESS)
+#  define _PACKED __attribute__ ((packed))
+#else
+#  define _PACKED
+#endif
+
+#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__)
+#  if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#    pragma pack(1)
+#  else
+#    pragma pack(push, 1)
+#  endif
+#endif
+
+typedef struct { U16 v; }  _PACKED U16_S;
+typedef struct { U32 v; }  _PACKED U32_S;
+typedef struct { U64 v; }  _PACKED U64_S;
+typedef struct {size_t v;} _PACKED size_t_S;
+
+#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__)
+#  if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#    pragma pack(0)
+#  else
+#    pragma pack(pop)
+#  endif
+#endif
+
+#define A16(x)   (((U16_S *)(x))->v)
+#define A32(x)   (((U32_S *)(x))->v)
+#define A64(x)   (((U64_S *)(x))->v)
+#define AARCH(x) (((size_t_S *)(x))->v)
+
+
+//**************************************
+// Constants
+//**************************************
+#define LZ4_HASHLOG   (MEMORY_USAGE-2)
+#define HASHTABLESIZE (1 << MEMORY_USAGE)
+#define HASHNBCELLS4  (1 << LZ4_HASHLOG)
+
+#define MINMATCH 4
+
+#define COPYLENGTH 8
+#define LASTLITERALS 5
+#define MFLIMIT (COPYLENGTH+MINMATCH)
+const int LZ4_minLength = (MFLIMIT+1);
+
+#define LZ4_64KLIMIT ((1<<16) + (MFLIMIT-1))
+#define SKIPSTRENGTH 6     // Increasing this value will make the compression run slower on incompressible data
+
+#define MAXD_LOG 16
+#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
+
+#define ML_BITS  4
+#define ML_MASK  ((1U<<ML_BITS)-1)
+#define RUN_BITS (8-ML_BITS)
+#define RUN_MASK ((1U<<RUN_BITS)-1)
+
+#define KB *(1U<<10)
+#define MB *(1U<<20)
+#define GB *(1U<<30)
+
+
+//**************************************
+// Structures and local types
+//**************************************
+
+typedef struct {
+    U32 hashTable[HASHNBCELLS4];
+    const BYTE* bufferStart;
+    const BYTE* base;
+    const BYTE* nextBlock;
+} LZ4_Data_Structure;
+
+typedef enum { notLimited = 0, limited = 1 } limitedOutput_directive;
+typedef enum { byPtr, byU32, byU16 } tableType_t;
+
+typedef enum { noPrefix = 0, withPrefix = 1 } prefix64k_directive;
+
+typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
+typedef enum { full = 0, partial = 1 } earlyEnd_directive;
+
+
+//**************************************
+// Architecture-specific macros
+//**************************************
+#define STEPSIZE                  sizeof(size_t)
+#define LZ4_COPYSTEP(d,s)         { AARCH(d) = AARCH(s); d+=STEPSIZE; s+=STEPSIZE; }
+#define LZ4_COPY8(d,s)            { LZ4_COPYSTEP(d,s); if (STEPSIZE<8) LZ4_COPYSTEP(d,s); }
+#define LZ4_SECURECOPY(d,s,e)     { if ((STEPSIZE==4)||(d<e)) LZ4_WILDCOPY(d,s,e); }
+
+#if LZ4_ARCH64   // 64-bit
+#  define HTYPE                   U32
+#  define INITBASE(base)          const BYTE* const base = ip
+#else            // 32-bit
+#  define HTYPE                   const BYTE*
+#  define INITBASE(base)          const int base = 0
+#endif
+
+#if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE))
+#  define LZ4_READ_LITTLEENDIAN_16(d,s,p) { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; }
+#  define LZ4_WRITE_LITTLEENDIAN_16(p,i)  { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p+=2; }
+#else      // Little Endian
+#  define LZ4_READ_LITTLEENDIAN_16(d,s,p) { d = (s) - A16(p); }
+#  define LZ4_WRITE_LITTLEENDIAN_16(p,v)  { A16(p) = v; p+=2; }
+#endif
+
+
+//**************************************
+// Macros
+//**************************************
+#define LZ4_WILDCOPY(d,s,e)     { do { LZ4_COPY8(d,s) } while (d<e); }           // at the end, d>=e;
+
+
+//****************************
+// Private functions
+//****************************
+#if LZ4_ARCH64
+
+FORCE_INLINE int LZ4_NbCommonBytes (register U64 val)
+{
+# if defined(LZ4_BIG_ENDIAN)
+#   if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+    unsigned long r = 0;
+    _BitScanReverse64( &r, val );
+    return (int)(r>>3);
+#   elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT)
+    return (__builtin_clzll(val) >> 3);
+#   else
+    int r;
+    if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
+    if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+    r += (!val);
+    return r;
+#   endif
+# else
+#   if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+    unsigned long r = 0;
+    _BitScanForward64( &r, val );
+    return (int)(r>>3);
+#   elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT)
+    return (__builtin_ctzll(val) >> 3);
+#   else
+    static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
+    return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+#   endif
+# endif
+}
+
+#else
+
+FORCE_INLINE int LZ4_NbCommonBytes (register U32 val)
+{
+# if defined(LZ4_BIG_ENDIAN)
+#   if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+    unsigned long r = 0;
+    _BitScanReverse( &r, val );
+    return (int)(r>>3);
+#   elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT)
+    return (__builtin_clz(val) >> 3);
+#   else
+    int r;
+    if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+    r += (!val);
+    return r;
+#   endif
+# else
+#   if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+    unsigned long r;
+    _BitScanForward( &r, val );
+    return (int)(r>>3);
+#   elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT)
+    return (__builtin_ctz(val) >> 3);
+#   else
+    static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
+    return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+#   endif
+# endif
+}
+
+#endif
+
+
+//****************************
+// Compression functions
+//****************************
+FORCE_INLINE int LZ4_hashSequence(U32 sequence, tableType_t tableType)
+{
+    if (tableType == byU16)
+        return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
+    else
+        return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
+}
+
+FORCE_INLINE int LZ4_hashPosition(const BYTE* p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); }
+
+FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+    switch (tableType)
+    {
+    case byPtr: { const BYTE** hashTable = (const BYTE**) tableBase; hashTable[h] = p; break; }
+    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); break; }
+    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); break; }
+    }
+}
+
+FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+    U32 h = LZ4_hashPosition(p, tableType);
+    LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
+}
+
+FORCE_INLINE const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+    if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
+    if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
+    { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; }   // default, to ensure a return
+}
+
+FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+    U32 h = LZ4_hashPosition(p, tableType);
+    return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
+}
+
+
+FORCE_INLINE int LZ4_compress_generic(
+                 void* ctx,
+                 const char* source,
+                 char* dest,
+                 int inputSize,
+                 int maxOutputSize,
+
+                 limitedOutput_directive limitedOutput,
+                 tableType_t tableType,
+                 prefix64k_directive prefix)
+{
+    const BYTE* ip = (const BYTE*) source;
+    const BYTE* const base = (prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->base : (const BYTE*) source;
+    const BYTE* const lowLimit = ((prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->bufferStart : (const BYTE*)source);
+    const BYTE* anchor = (const BYTE*) source;
+    const BYTE* const iend = ip + inputSize;
+    const BYTE* const mflimit = iend - MFLIMIT;
+    const BYTE* const matchlimit = iend - LASTLITERALS;
+
+    BYTE* op = (BYTE*) dest;
+    BYTE* const oend = op + maxOutputSize;
+
+    int length;
+    const int skipStrength = SKIPSTRENGTH;
+    U32 forwardH;
+
+    // Init conditions
+    if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0;                                // Unsupported input size, too large (or negative)
+    if ((prefix==withPrefix) && (ip != ((LZ4_Data_Structure*)ctx)->nextBlock)) return 0;   // must continue from end of previous block
+    if (prefix==withPrefix) ((LZ4_Data_Structure*)ctx)->nextBlock=iend;                    // do it now, due to potential early exit
+    if ((tableType == byU16) && (inputSize>=LZ4_64KLIMIT)) return 0;                       // Size too large (not within 64K limit)
+    if (inputSize<LZ4_minLength) goto _last_literals;                                      // Input too small, no compression (all literals)
+
+    // First Byte
+    LZ4_putPosition(ip, ctx, tableType, base);
+    ip++; forwardH = LZ4_hashPosition(ip, tableType);
+
+    // Main Loop
+    for ( ; ; )
+    {
+        int findMatchAttempts = (1U << skipStrength) + 3;
+        const BYTE* forwardIp = ip;
+        const BYTE* ref;
+        BYTE* token;
+
+        // Find a match
+        do {
+            U32 h = forwardH;
+            int step = findMatchAttempts++ >> skipStrength;
+            ip = forwardIp;
+            forwardIp = ip + step;
+
+            if unlikely(forwardIp > mflimit) { goto _last_literals; }
+
+            forwardH = LZ4_hashPosition(forwardIp, tableType);
+            ref = LZ4_getPositionOnHash(h, ctx, tableType, base);
+            LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+        } while ((ref + MAX_DISTANCE < ip) || (A32(ref) != A32(ip)));
+
+        // Catch up
+        while ((ip>anchor) && (ref > lowLimit) && unlikely(ip[-1]==ref[-1])) { ip--; ref--; }
+
+        // Encode Literal length
+        length = (int)(ip - anchor);
+        token = op++;
+        if ((limitedOutput) && unlikely(op + length + (2 + 1 + LASTLITERALS) + (length/255) > oend)) return 0;   // Check output limit
+        if (length>=(int)RUN_MASK)
+        {
+            int len = length-RUN_MASK;
+            *token=(RUN_MASK<<ML_BITS);
+            for(; len >= 255 ; len-=255) *op++ = 255;
+            *op++ = (BYTE)len;
+        }
+        else *token = (BYTE)(length<<ML_BITS);
+
+        // Copy Literals
+        { BYTE* end=(op)+(length); LZ4_WILDCOPY(op,anchor,end); op=end; }
+
+_next_match:
+        // Encode Offset
+        LZ4_WRITE_LITTLEENDIAN_16(op,(U16)(ip-ref));
+
+        // Start Counting
+        ip+=MINMATCH; ref+=MINMATCH;    // MinMatch already verified
+        anchor = ip;
+        while likely(ip<matchlimit-(STEPSIZE-1))
+        {
+            size_t diff = AARCH(ref) ^ AARCH(ip);
+            if (!diff) { ip+=STEPSIZE; ref+=STEPSIZE; continue; }
+            ip += LZ4_NbCommonBytes(diff);
+            goto _endCount;
+        }
+        if (LZ4_ARCH64) if ((ip<(matchlimit-3)) && (A32(ref) == A32(ip))) { ip+=4; ref+=4; }
+        if ((ip<(matchlimit-1)) && (A16(ref) == A16(ip))) { ip+=2; ref+=2; }
+        if ((ip<matchlimit) && (*ref == *ip)) ip++;
+_endCount:
+
+        // Encode MatchLength
+        length = (int)(ip - anchor);
+        if ((limitedOutput) && unlikely(op + (1 + LASTLITERALS) + (length>>8) > oend)) return 0;    // Check output limit
+        if (length>=(int)ML_MASK)
+        {
+            *token += ML_MASK;
+            length -= ML_MASK;
+            for (; length > 509 ; length-=510) { *op++ = 255; *op++ = 255; }
+            if (length >= 255) { length-=255; *op++ = 255; }
+            *op++ = (BYTE)length;
+        }
+        else *token += (BYTE)(length);
+
+        // Test end of chunk
+        if (ip > mflimit) { anchor = ip;  break; }
+
+        // Fill table
+        LZ4_putPosition(ip-2, ctx, tableType, base);
+
+        // Test next position
+        ref = LZ4_getPosition(ip, ctx, tableType, base);
+        LZ4_putPosition(ip, ctx, tableType, base);
+        if ((ref + MAX_DISTANCE >= ip) && (A32(ref) == A32(ip))) { token = op++; *token=0; goto _next_match; }
+
+        // Prepare next loop
+        anchor = ip++;
+        forwardH = LZ4_hashPosition(ip, tableType);
+    }
+
+_last_literals:
+    // Encode Last Literals
+    {
+        int lastRun = (int)(iend - anchor);
+        if ((limitedOutput) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0;   // Check output limit
+        if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun >= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; }
+        else *op++ = (BYTE)(lastRun<<ML_BITS);
+        memcpy(op, anchor, iend - anchor);
+        op += iend-anchor;
+    }
+
+    // End
+    return (int) (((char*)op)-dest);
+}
+
+
+int LZ4_compress(const char* source, char* dest, int inputSize)
+{
+#if (HEAPMODE)
+    void* ctx = ALLOCATOR(HASHNBCELLS4, 4);   // Aligned on 4-bytes boundaries
+#else
+    U32 ctx[1U<<(MEMORY_USAGE-2)] = {0};      // Ensure data is aligned on 4-bytes boundaries
+#endif
+    int result;
+
+    if (inputSize < (int)LZ4_64KLIMIT)
+        result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, byU16, noPrefix);
+    else
+        result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix);
+
+#if (HEAPMODE)
+    FREEMEM(ctx);
+#endif
+    return result;
+}
+
+int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+#if (HEAPMODE)
+    void* ctx = ALLOCATOR(HASHNBCELLS4, 4);   // Aligned on 4-bytes boundaries
+#else
+    U32 ctx[1U<<(MEMORY_USAGE-2)] = {0};      // Ensure data is aligned on 4-bytes boundaries
+#endif
+    int result;
+
+    if (inputSize < (int)LZ4_64KLIMIT)
+        result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limited, byU16, noPrefix);
+    else
+        result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix);
+
+#if (HEAPMODE)
+    FREEMEM(ctx);
+#endif
+    return result;
+}
+
+
+//*****************************
+// Using an external allocation
+//*****************************
+
+int LZ4_sizeofState() { return 1 << MEMORY_USAGE; }
+
+
+int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize)
+{
+    if (((size_t)(state)&3) != 0) return 0;   // Error : state is not aligned on 4-bytes boundary
+    MEM_INIT(state, 0, LZ4_sizeofState());
+
+    if (inputSize < (int)LZ4_64KLIMIT)
+        return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noPrefix);
+    else
+        return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix);
+}
+
+
+int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+    if (((size_t)(state)&3) != 0) return 0;   // Error : state is not aligned on 4-bytes boundary
+    MEM_INIT(state, 0, LZ4_sizeofState());
+
+    if (inputSize < (int)LZ4_64KLIMIT)
+        return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limited, byU16, noPrefix);
+    else
+        return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix);
+}
+
+
+//****************************
+// Stream functions
+//****************************
+
+int LZ4_sizeofStreamState()
+{
+    return sizeof(LZ4_Data_Structure);
+}
+
+FORCE_INLINE void LZ4_init(LZ4_Data_Structure* lz4ds, const BYTE* base)
+{
+    MEM_INIT(lz4ds->hashTable, 0, sizeof(lz4ds->hashTable));
+    lz4ds->bufferStart = base;
+    lz4ds->base = base;
+    lz4ds->nextBlock = base;
+}
+
+int LZ4_resetStreamState(void* state, const char* inputBuffer)
+{
+    if ((((size_t)state) & 3) != 0) return 1;   // Error : pointer is not aligned on 4-bytes boundary
+    LZ4_init((LZ4_Data_Structure*)state, (const BYTE*)inputBuffer);
+    return 0;
+}
+
+void* LZ4_create (const char* inputBuffer)
+{
+    void* lz4ds = ALLOCATOR(1, sizeof(LZ4_Data_Structure));
+    LZ4_init ((LZ4_Data_Structure*)lz4ds, (const BYTE*)inputBuffer);
+    return lz4ds;
+}
+
+
+int LZ4_free (void* LZ4_Data)
+{
+    FREEMEM(LZ4_Data);
+    return (0);
+}
+
+
+char* LZ4_slideInputBuffer (void* LZ4_Data)
+{
+    LZ4_Data_Structure* lz4ds = (LZ4_Data_Structure*)LZ4_Data;
+    size_t delta = lz4ds->nextBlock - (lz4ds->bufferStart + 64 KB);
+
+    if ( (lz4ds->base - delta > lz4ds->base)                          // underflow control
+       || ((size_t)(lz4ds->nextBlock - lz4ds->base) > 0xE0000000) )   // close to 32-bits limit
+    {
+        size_t deltaLimit = (lz4ds->nextBlock - 64 KB) - lz4ds->base;
+        int nH;
+
+        for (nH=0; nH < HASHNBCELLS4; nH++)
+        {
+            if ((size_t)(lz4ds->hashTable[nH]) < deltaLimit) lz4ds->hashTable[nH] = 0;
+            else lz4ds->hashTable[nH] -= (U32)deltaLimit;
+        }
+        memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB);
+        lz4ds->base = lz4ds->bufferStart;
+        lz4ds->nextBlock = lz4ds->base + 64 KB;
+    }
+    else
+    {
+        memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB);
+        lz4ds->nextBlock -= delta;
+        lz4ds->base -= delta;
+    }
+
+    return (char*)(lz4ds->nextBlock);
+}
+
+
+int LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize)
+{
+    return LZ4_compress_generic(LZ4_Data, source, dest, inputSize, 0, notLimited, byU32, withPrefix);
+}
+
+
+int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+    return LZ4_compress_generic(LZ4_Data, source, dest, inputSize, maxOutputSize, limited, byU32, withPrefix);
+}
+
+
+//****************************
+// Decompression functions
+//****************************
+
+// This generic decompression function cover all use cases.
+// It shall be instanciated several times, using different sets of directives
+// Note that it is essential this generic function is really inlined,
+// in order to remove useless branches during compilation optimisation.
+FORCE_INLINE int LZ4_decompress_generic(
+                 const char* source,
+                 char* dest,
+                 int inputSize,          //
+                 int outputSize,         // If endOnInput==endOnInputSize, this value is the max size of Output Buffer.
+
+                 int endOnInput,         // endOnOutputSize, endOnInputSize
+                 int prefix64k,          // noPrefix, withPrefix
+                 int partialDecoding,    // full, partial
+                 int targetOutputSize    // only used if partialDecoding==partial
+                 )
+{
+    // Local Variables
+    const BYTE* restrict ip = (const BYTE*) source;
+    const BYTE* ref;
+    const BYTE* const iend = ip + inputSize;
+
+    BYTE* op = (BYTE*) dest;
+    BYTE* const oend = op + outputSize;
+    BYTE* cpy;
+    BYTE* oexit = op + targetOutputSize;
+
+    const size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0};   // static reduces speed for LZ4_decompress_safe() on GCC64
+    static const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
+
+
+    // Special cases
+    if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT;                        // targetOutputSize too high => decode everything
+    if ((endOnInput) && unlikely(outputSize==0)) return ((inputSize==1) && (*ip==0)) ? 0 : -1;   // Empty output buffer
+    if ((!endOnInput) && unlikely(outputSize==0)) return (*ip==0?1:-1);
+
+
+    // Main Loop
+    while (1)
+    {
+        unsigned token;
+        size_t length;
+
+        // get runlength
+        token = *ip++;
+        if ((length=(token>>ML_BITS)) == RUN_MASK)
+        {
+            unsigned s=255;
+            while (((endOnInput)?ip<iend:1) && (s==255))
+            {
+                s = *ip++;
+                length += s;
+            }
+        }
+
+        // copy literals
+        cpy = op+length;
+        if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
+            || ((!endOnInput) && (cpy>oend-COPYLENGTH)))
+        {
+            if (partialDecoding)
+            {
+                if (cpy > oend) goto _output_error;                           // Error : write attempt beyond end of output buffer
+                if ((endOnInput) && (ip+length > iend)) goto _output_error;   // Error : read attempt beyond end of input buffer
+            }
+            else
+            {
+                if ((!endOnInput) && (cpy != oend)) goto _output_error;       // Error : block decoding must stop exactly there
+                if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error;   // Error : input must be consumed
+            }
+            memcpy(op, ip, length);
+            ip += length;
+            op += length;
+            break;                                       // Necessarily EOF, due to parsing restrictions
+        }
+        LZ4_WILDCOPY(op, ip, cpy); ip -= (op-cpy); op = cpy;
+
+        // get offset
+        LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2;
+        if ((prefix64k==noPrefix) && unlikely(ref < (BYTE* const)dest)) goto _output_error;   // Error : offset outside destination buffer
+
+        // get matchlength
+        if ((length=(token&ML_MASK)) == ML_MASK)
+        {
+            while ((!endOnInput) || (ip<iend-(LASTLITERALS+1)))   // Ensure enough bytes remain for LASTLITERALS + token
+            {
+                unsigned s = *ip++;
+                length += s;
+                if (s==255) continue;
+                break;
+            }
+        }
+
+        // copy repeated sequence
+        if unlikely((op-ref)<(int)STEPSIZE)
+        {
+            const size_t dec64 = dec64table[(sizeof(void*)==4) ? 0 : op-ref];
+            op[0] = ref[0];
+            op[1] = ref[1];
+            op[2] = ref[2];
+            op[3] = ref[3];
+            op += 4, ref += 4; ref -= dec32table[op-ref];
+            A32(op) = A32(ref);
+            op += STEPSIZE-4; ref -= dec64;
+        } else { LZ4_COPYSTEP(op,ref); }
+        cpy = op + length - (STEPSIZE-4);
+
+        if unlikely(cpy>oend-COPYLENGTH-(STEPSIZE-4))
+        {
+            if (cpy > oend-LASTLITERALS) goto _output_error;    // Error : last 5 bytes must be literals
+            LZ4_SECURECOPY(op, ref, (oend-COPYLENGTH));
+            while(op<cpy) *op++=*ref++;
+            op=cpy;
+            continue;
+        }
+        LZ4_WILDCOPY(op, ref, cpy);
+        op=cpy;   // correction
+    }
+
+    // end of decoding
+    if (endOnInput)
+       return (int) (((char*)op)-dest);     // Nb of output bytes decoded
+    else
+       return (int) (((char*)ip)-source);   // Nb of input bytes read
+
+    // Overflow error detected
+_output_error:
+    return (int) (-(((char*)ip)-source))-1;
+}
+
+
+int LZ4_decompress_safe(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+    return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, noPrefix, full, 0);
+}
+
+int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+    return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, withPrefix, full, 0);
+}
+
+int LZ4_decompress_safe_partial(const char* source, char* dest, int inputSize, int targetOutputSize, int maxOutputSize)
+{
+    return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, noPrefix, partial, targetOutputSize);
+}
+
+int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int outputSize)
+{
+    return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, withPrefix, full, 0);
+}
+
+int LZ4_decompress_fast(const char* source, char* dest, int outputSize)
+{
+#ifdef _MSC_VER   // This version is faster with Visual
+    return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, noPrefix, full, 0);
+#else
+    return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, withPrefix, full, 0);
+#endif
+}
+
diff --git a/src/impex/lz4.h b/src/impex/lz4.h
new file mode 100644
index 0000000..af05dbc
--- /dev/null
+++ b/src/impex/lz4.h
@@ -0,0 +1,249 @@
+/*
+   LZ4 - Fast LZ compression algorithm
+   Header File
+   Copyright (C) 2011-2013, Yann Collet.
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
+   - LZ4 source repository : http://code.google.com/p/lz4/
+*/
+#pragma once
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+//**************************************
+// Compiler Options
+//**************************************
+#if defined(_MSC_VER) && !defined(__cplusplus)   // Visual Studio
+#  define inline __inline           // Visual C is not C99, but supports some kind of inline
+#endif
+
+
+//****************************
+// Simple Functions
+//****************************
+
+int LZ4_compress        (const char* source, char* dest, int inputSize);
+int LZ4_decompress_safe (const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/*
+LZ4_compress() :
+    Compresses 'inputSize' bytes from 'source' into 'dest'.
+    Destination buffer must be already allocated,
+    and must be sized to handle worst cases situations (input data not compressible)
+    Worst case size evaluation is provided by function LZ4_compressBound()
+    inputSize : Max supported value is LZ4_MAX_INPUT_VALUE
+    return : the number of bytes written in buffer dest
+             or 0 if the compression fails
+
+LZ4_decompress_safe() :
+    maxOutputSize : is the size of the destination buffer (which must be already allocated)
+    return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)
+             If the source stream is detected malformed, the function will stop decoding and return a negative result.
+             This function is protected against buffer overflow exploits (never writes outside of output buffer, and never reads outside of input buffer). Therefore, it is protected against malicious data packets
+*/
+
+
+//****************************
+// Advanced Functions
+//****************************
+#define LZ4_MAX_INPUT_SIZE        0x7E000000   // 2 113 929 216 bytes
+#define LZ4_COMPRESSBOUND(isize)  ((unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
+static inline int LZ4_compressBound(int isize)  { return LZ4_COMPRESSBOUND(isize); }
+
+/*
+LZ4_compressBound() :
+    Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible)
+    primarily useful for memory allocation of output buffer.
+    inline function is recommended for the general case,
+    macro is also provided when result needs to be evaluated at compilation (such as stack memory allocation).
+
+    isize  : is the input size. Max supported value is LZ4_MAX_INPUT_SIZE
+    return : maximum output size in a "worst case" scenario
+             or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
+*/
+
+
+int LZ4_compress_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/*
+LZ4_compress_limitedOutput() :
+    Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'.
+    If it cannot achieve it, compression will stop, and result of the function will be zero.
+    This function never writes outside of provided output buffer.
+
+    inputSize  : Max supported value is LZ4_MAX_INPUT_VALUE
+    maxOutputSize : is the size of the destination buffer (which must be already allocated)
+    return : the number of bytes written in buffer 'dest'
+             or 0 if the compression fails
+*/
+
+
+int LZ4_decompress_fast (const char* source, char* dest, int outputSize);
+
+/*
+LZ4_decompress_fast() :
+    outputSize : is the original (uncompressed) size
+    return : the number of bytes read from the source buffer (in other words, the compressed size)
+             If the source stream is malformed, the function will stop decoding and return a negative result.
+    note : This function is a bit faster than LZ4_decompress_safe()
+           This function never writes outside of output buffers, but may read beyond input buffer in case of malicious data packet.
+           Use this function preferably into a trusted environment (data to decode comes from a trusted source).
+           Destination buffer must be already allocated. Its size must be a minimum of 'outputSize' bytes.
+*/
+
+int LZ4_decompress_safe_partial (const char* source, char* dest, int inputSize, int targetOutputSize, int maxOutputSize);
+
+/*
+LZ4_decompress_safe_partial() :
+    This function decompress a compressed block of size 'inputSize' at position 'source'
+    into output buffer 'dest' of size 'maxOutputSize'.
+    The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
+    reducing decompression time.
+    return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)
+       Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
+             Always control how many bytes were decoded.
+             If the source stream is detected malformed, the function will stop decoding and return a negative result.
+             This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
+*/
+
+
+//*****************************
+// Using an external allocation
+//*****************************
+int LZ4_sizeofState();
+int LZ4_compress_withState               (void* state, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/*
+These functions are provided should you prefer to allocate memory for compression tables with your own allocation methods.
+To know how much memory must be allocated for the compression tables, use :
+int LZ4_sizeofState();
+
+Note that tables must be aligned on 4-bytes boundaries, otherwise compression will fail (return code 0).
+
+The allocated memory can be provided to the compressions functions using 'void* state' parameter.
+LZ4_compress_withState() and LZ4_compress_limitedOutput_withState() are equivalent to previously described functions.
+They just use the externally allocated memory area instead of allocating their own (on stack, or on heap).
+*/
+
+
+//****************************
+// Streaming Functions
+//****************************
+
+void* LZ4_create (const char* inputBuffer);
+int   LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize);
+int   LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize);
+char* LZ4_slideInputBuffer (void* LZ4_Data);
+int   LZ4_free (void* LZ4_Data);
+
+/*
+These functions allow the compression of dependent blocks, where each block benefits from prior 64 KB within preceding blocks.
+In order to achieve this, it is necessary to start creating the LZ4 Data Structure, thanks to the function :
+
+void* LZ4_create (const char* inputBuffer);
+The result of the function is the (void*) pointer on the LZ4 Data Structure.
+This pointer will be needed in all other functions.
+If the pointer returned is NULL, then the allocation has failed, and compression must be aborted.
+The only parameter 'const char* inputBuffer' must, obviously, point at the beginning of input buffer.
+The input buffer must be already allocated, and size at least 192KB.
+'inputBuffer' will also be the 'const char* source' of the first block.
+
+All blocks are expected to lay next to each other within the input buffer, starting from 'inputBuffer'.
+To compress each block, use either LZ4_compress_continue() or LZ4_compress_limitedOutput_continue().
+Their behavior are identical to LZ4_compress() or LZ4_compress_limitedOutput(),
+but require the LZ4 Data Structure as their first argument, and check that each block starts right after the previous one.
+If next block does not begin immediately after the previous one, the compression will fail (return 0).
+
+When it's no longer possible to lay the next block after the previous one (not enough space left into input buffer), a call to :
+char* LZ4_slideInputBuffer(void* LZ4_Data);
+must be performed. It will typically copy the latest 64KB of input at the beginning of input buffer.
+Note that, for this function to work properly, minimum size of an input buffer must be 192KB.
+==> The memory position where the next input data block must start is provided as the result of the function.
+
+Compression can then resume, using LZ4_compress_continue() or LZ4_compress_limitedOutput_continue(), as usual.
+
+When compression is completed, a call to LZ4_free() will release the memory used by the LZ4 Data Structure.
+*/
+
+int LZ4_sizeofStreamState();
+int LZ4_resetStreamState(void* state, const char* inputBuffer);
+
+/*
+These functions achieve the same result as :
+void* LZ4_create (const char* inputBuffer);
+
+They are provided here to allow the user program to allocate memory using its own routines.
+
+To know how much space must be allocated, use LZ4_sizeofStreamState();
+Note also that space must be 4-bytes aligned.
+
+Once space is allocated, you must initialize it using : LZ4_resetStreamState(void* state, const char* inputBuffer);
+void* state is a pointer to the space allocated.
+It must be aligned on 4-bytes boundaries, and be large enough.
+The parameter 'const char* inputBuffer' must, obviously, point at the beginning of input buffer.
+The input buffer must be already allocated, and size at least 192KB.
+'inputBuffer' will also be the 'const char* source' of the first block.
+
+The same space can be re-used multiple times, just by initializing it each time with LZ4_resetStreamState().
+return value of LZ4_resetStreamState() must be 0 is OK.
+Any other value means there was an error (typically, pointer is not aligned on 4-bytes boundaries).
+*/
+
+
+int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int inputSize, int maxOutputSize);
+int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int outputSize);
+
+/*
+*_withPrefix64k() :
+    These decoding functions work the same as their "normal name" versions,
+    but can use up to 64KB of data in front of 'char* dest'.
+    These functions are necessary to decode inter-dependant blocks.
+*/
+
+
+//****************************
+// Obsolete Functions
+//****************************
+
+static inline int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
+static inline int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
+
+/*
+These functions are deprecated and should no longer be used.
+They are provided here for compatibility with existing user programs.
+*/
+
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/src/impex/png.cxx b/src/impex/png.cxx
index 92373aa..b3e6db9 100644
--- a/src/impex/png.cxx
+++ b/src/impex/png.cxx
@@ -587,7 +587,7 @@ namespace vigra {
         }
 
         // set offset
-        if (position.x > 0 && position.y > 0) {
+        if (position.x != 0 || position.y != 0) {
             if (setjmp(png_jmpbuf(png)))
                 vigra_postcondition( false, png_error_message.insert(0, "error in png_set_oFFs(): ").c_str() );
             png_set_oFFs(png, info, position.x, position.y, PNG_OFFSET_PIXEL);
diff --git a/src/impex/pnm.cxx b/src/impex/pnm.cxx
index 9cf39d2..575fb39 100644
--- a/src/impex/pnm.cxx
+++ b/src/impex/pnm.cxx
@@ -402,7 +402,7 @@ namespace vigra {
 
     void PnmDecoder::init( const std::string & filename )
     {
-        pimpl = new PnmDecoderImpl( filename.c_str() );
+        pimpl = new PnmDecoderImpl( filename );
     }
 
     PnmDecoder::~PnmDecoder()
diff --git a/src/impex/tiff.cxx b/src/impex/tiff.cxx
index d6e73d8..6d1760c 100644
--- a/src/impex/tiff.cxx
+++ b/src/impex/tiff.cxx
@@ -365,7 +365,7 @@ namespace vigra {
         if( TIFFGetField( tiff, TIFFTAG_TILEWIDTH, &tileWidth ) &&
             TIFFGetField( tiff, TIFFTAG_TILELENGTH, &tileHeight ) )
             vigra_precondition( (tileWidth == width) && (tileHeight == height),
-                                "TIFFDecoderImpl::init(): "
+                                "TIFFDecoder: "
                                 "Cannot read tiled TIFFs (not implemented)." );
 
         // find out strip heights
@@ -376,7 +376,7 @@ namespace vigra {
         extra_samples_per_pixel = 0;
         if ( !TIFFGetFieldDefaulted( tiff, TIFFTAG_SAMPLESPERPIXEL,
                                      &samples_per_pixel ) )
-            vigra_fail( "TIFFDecoderImpl::init(): Samples per pixel not set."
+            vigra_fail( "TIFFDecoder: Samples per pixel not set."
                         " A suitable default was not found." );
 
         // read extra samples (# of alpha channels)
@@ -391,7 +391,7 @@ namespace vigra {
             for (int i=0; i< extra_samples_per_pixel; i++) {
                 if (extra_sample_types[i] ==  EXTRASAMPLE_ASSOCALPHA)
                 {
-                    std::cerr << "WARNING: TIFFDecoderImpl::init(): associated alpha treated"
+                    std::cerr << "WARNING: TIFFDecoder: associated alpha treated"
                                  " as unassociated alpha!" << std::endl;
                 }
             }
@@ -400,9 +400,28 @@ namespace vigra {
         // get photometric
         if ( !TIFFGetFieldDefaulted( tiff, TIFFTAG_PHOTOMETRIC,
                                      &photometric ) )
-            vigra_fail( "TIFFDecoderImpl::init(): Photometric tag is not set."
-                        " A suitable default was not found." );
-
+        {
+            // No photometric found in the file, try to guess.
+            // FIXME: also look at extra_samples_per_pixel here
+            if(samples_per_pixel == 1)
+            {
+                photometric = PHOTOMETRIC_MINISBLACK;
+                std::cerr << "Warning: TIFFDecoder: TIFFTAG_PHOTOMETRIC is not set, "
+                             "guessing PHOTOMETRIC_MINISBLACK." << std::endl;
+            }
+            else if(samples_per_pixel == 3)
+            {
+                photometric = PHOTOMETRIC_RGB;
+                std::cerr << "Warning: TIFFDecoder: TIFFTAG_PHOTOMETRIC is not set, "
+                             "guessing PHOTOMETRIC_RGB." << std::endl;
+            }
+            else
+            {
+                vigra_fail( "TIFFDecoder: TIFFTAG_PHOTOMETRIC is not set."
+                            " A suitable default was not found." );
+            }
+        }
+        
         // check photometric preconditions
         switch ( photometric )
         {
@@ -411,7 +430,7 @@ namespace vigra {
             case PHOTOMETRIC_PALETTE:
             {
                 if ( samples_per_pixel - extra_samples_per_pixel != 1 )
-                vigra_fail("TIFFDecoderImpl::init():"
+                vigra_fail("TIFFDecoder:"
                                 " Photometric tag does not fit the number of"
                                 " samples per pixel." );
                 break;
@@ -423,7 +442,7 @@ namespace vigra {
                     extra_samples_per_pixel = samples_per_pixel - 3;
                 }
                 if ( samples_per_pixel - extra_samples_per_pixel != 3 )
-                    vigra_fail("TIFFDecoderImpl::init():"
+                    vigra_fail("TIFFDecoder:"
                                     " Photometric tag does not fit the number of"
                                     " samples per pixel." );
                 break;
@@ -434,7 +453,7 @@ namespace vigra {
                 uint16 tiffcomp;
                 TIFFGetFieldDefaulted( tiff, TIFFTAG_COMPRESSION, &tiffcomp );
                 if (tiffcomp != COMPRESSION_SGILOG && tiffcomp != COMPRESSION_SGILOG24)
-                    vigra_fail("TIFFDecoderImpl::init():"
+                    vigra_fail("TIFFDecoder:"
                                     " Only SGILOG compression is supported for"
                                     " LogLuv TIFF."
                     );
@@ -447,14 +466,14 @@ namespace vigra {
         if ( samples_per_pixel > 1 ) {
             if ( !TIFFGetFieldDefaulted( tiff, TIFFTAG_PLANARCONFIG,
                                          &planarconfig ) )
-                vigra_fail( "TIFFDecoderImpl::init(): Planarconfig is not"
+                vigra_fail( "TIFFDecoder: TIFFTAG_PLANARCONFIG is not"
                             " set. A suitable default was not found." );
         }
 
         // get bits per pixel
         if ( !TIFFGetField( tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample ) )
         {
-            std::cerr << "Warning: no TIFFTAG_BITSPERSAMPLE, using 8 bits per sample.\n";
+            std::cerr << "Warning: TIFFDecoder: no TIFFTAG_BITSPERSAMPLE, using 8 bits per sample.\n";
             bits_per_sample = 8;
         }
         // get pixeltype
@@ -487,12 +506,12 @@ namespace vigra {
                             pixeltype =  "DOUBLE";
                             break;
                         default:
-                            vigra_fail( "TIFFDecoderImpl::init(): Sampleformat or Datatype tag undefined and guessing sampletype from Bits per Sample failed." );
+                            vigra_fail( "TIFFDecoder: Sampleformat or Datatype tag undefined and guessing sampletype from Bits per Sample failed." );
                             break;
                     }
                     if(bits_per_sample != 8) // issue the warning only for non-trivial cases
-                        std::cerr << "Warning: no TIFFTAG_SAMPLEFORMAT or TIFFTAG_DATATYPE, "
-                                     "guessing pixeltype '" << pixeltype << "'.\n";
+                        std::cerr << "Warning: TIFFDecoder: no TIFFTAG_SAMPLEFORMAT or "
+                                      "TIFFTAG_DATATYPE, guessing pixeltype '" << pixeltype << "'.\n";
                 }
             }
 
@@ -592,7 +611,7 @@ namespace vigra {
         } else {
             stripbuffer = new tdata_t[1];
             stripbuffer[0] = 0;
-            stripbuffer[0] = _TIFFmalloc(stripsize);
+            stripbuffer[0] = _TIFFmalloc(stripsize < width ? width : stripsize);
             if(stripbuffer[0] == 0)
                 throw std::bad_alloc();
         }
@@ -605,10 +624,29 @@ namespace vigra {
     TIFFDecoderImpl::currentScanlineOfBand( unsigned int band ) const
     {
         if ( bits_per_sample == 1 ) {
-            UInt8 * const buf
+            const unsigned int n = TIFFScanlineSize(tiff);
+            UInt8 * const startpointer
                 = static_cast< UInt8 * >(stripbuffer[0]);
-            // XXX probably wrong
-            return buf + ( stripindex * width ) / 8;
+            UInt8 * bytepointer = startpointer;
+
+            bytepointer += n-1;
+            for (int byte = n-1 ; byte >= 0; --byte)
+            {
+                UInt8 currentByte = *bytepointer;
+                --bytepointer;
+
+                UInt8 * bitpointer = startpointer;
+                bitpointer += byte * 8;
+
+                for (unsigned char bit = 7; bit < 8; --bit)
+                {
+                    *bitpointer = ((currentByte & (1 << bit)) ? photometric : 1 - photometric);
+                    ++bitpointer;
+                    if (byte * 8 + 7 - bit == width - 1) break;
+                }
+            }
+            // XXX probably right
+            return startpointer + ( stripindex * width ) / 8;
         } else {
             if ( planarconfig == PLANARCONFIG_SEPARATE ) {
                 UInt8 * const buf
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 4b97958..1d1d6e0 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -2,36 +2,48 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
 
 INCLUDE(VigraAddTest)
 
-ADD_SUBDIRECTORY(error)
-ADD_SUBDIRECTORY(impex)
-ADD_SUBDIRECTORY(utilities)
-ADD_SUBDIRECTORY(pixeltypes)
-ADD_SUBDIRECTORY(colorspaces)
+ADD_SUBDIRECTORY(adjacency_list_graph)
+ADD_SUBDIRECTORY(blockwisealgorithms)
 ADD_SUBDIRECTORY(classifier)
-ADD_SUBDIRECTORY(imgproc)
-ADD_SUBDIRECTORY(functorexpression)
+ADD_SUBDIRECTORY(colorspaces)
 ADD_SUBDIRECTORY(convolution)
-ADD_SUBDIRECTORY(morphology)
+ADD_SUBDIRECTORY(coordinateiterator)
+ADD_SUBDIRECTORY(correlation)
+ADD_SUBDIRECTORY(counting_iterator)
+ADD_SUBDIRECTORY(delegates)
+ADD_SUBDIRECTORY(error)
+ADD_SUBDIRECTORY(features)
+ADD_SUBDIRECTORY(filters)
 ADD_SUBDIRECTORY(fourier)
-ADD_SUBDIRECTORY(math)
-ADD_SUBDIRECTORY(optimization)
-ADD_SUBDIRECTORY(tensorimaging)
-ADD_SUBDIRECTORY(simpleanalysis)
+ADD_SUBDIRECTORY(functorexpression)
+ADD_SUBDIRECTORY(graph_algorithm)
+ADD_SUBDIRECTORY(gridgraph)
+ADD_SUBDIRECTORY(hdf5impex)
 ADD_SUBDIRECTORY(image)
+ADD_SUBDIRECTORY(imgproc)
+ADD_SUBDIRECTORY(impex)
+ADD_SUBDIRECTORY(integral_image)
+ADD_SUBDIRECTORY(math)
+ADD_SUBDIRECTORY(merge_graph_adaptor)
+ADD_SUBDIRECTORY(morphology)
 ADD_SUBDIRECTORY(multiarray)
 ADD_SUBDIRECTORY(multiconvolution)
-ADD_SUBDIRECTORY(voxelneighborhood)
-ADD_SUBDIRECTORY(volumelabeling)
-ADD_SUBDIRECTORY(watersheds3d)
 ADD_SUBDIRECTORY(multidistance)
 ADD_SUBDIRECTORY(multimorphology)
-ADD_SUBDIRECTORY(seededRegionGrowing3d)
+ADD_SUBDIRECTORY(objectfeatures)
+ADD_SUBDIRECTORY(optimization)
+ADD_SUBDIRECTORY(pixeltypes)
+ADD_SUBDIRECTORY(polygon)
+ADD_SUBDIRECTORY(registration)
 ADD_SUBDIRECTORY(sampler)
-ADD_SUBDIRECTORY(hdf5impex)
+ADD_SUBDIRECTORY(seededRegionGrowing3d)
 ADD_SUBDIRECTORY(sifImport)
-ADD_SUBDIRECTORY(features)
-ADD_SUBDIRECTORY(unsupervised)
-ADD_SUBDIRECTORY(coordinateiterator)
-ADD_SUBDIRECTORY(objectfeatures)
+ADD_SUBDIRECTORY(simpleanalysis)
 ADD_SUBDIRECTORY(slic2d)
-ADD_SUBDIRECTORY(gridgraph)
+ADD_SUBDIRECTORY(tensorimaging)
+ADD_SUBDIRECTORY(threadpool)
+ADD_SUBDIRECTORY(unsupervised)
+ADD_SUBDIRECTORY(utilities)
+ADD_SUBDIRECTORY(volumelabeling)
+ADD_SUBDIRECTORY(voxelneighborhood)
+ADD_SUBDIRECTORY(watersheds3d)
diff --git a/test/adjacency_list_graph/CMakeLists.txt b/test/adjacency_list_graph/CMakeLists.txt
new file mode 100644
index 0000000..339cb1b
--- /dev/null
+++ b/test/adjacency_list_graph/CMakeLists.txt
@@ -0,0 +1 @@
+VIGRA_ADD_TEST(test_adjacency_list_graph test.cxx)
diff --git a/test/adjacency_list_graph/test.cxx b/test/adjacency_list_graph/test.cxx
new file mode 100644
index 0000000..88d3c45
--- /dev/null
+++ b/test/adjacency_list_graph/test.cxx
@@ -0,0 +1,1549 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2004 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*                                                                      */
+/************************************************************************/
+
+#include <iostream>
+#include "vigra/unittest.hxx"
+#include "vigra/stdimage.hxx"
+#include "vigra/multi_array.hxx"
+#include "vigra/adjacency_list_graph.hxx"
+
+using namespace vigra;
+
+
+
+
+
+
+struct AdjacencyListGraphTest{
+
+
+    typedef vigra::AdjacencyListGraph                     GraphType;
+    typedef GraphType::Node                      Node;
+    typedef GraphType::Edge                      Edge;
+    typedef GraphType::Arc                       Arc;
+    typedef GraphType::EdgeIt                    EdgeIt;
+    typedef GraphType::NodeIt                    NodeIt;
+    typedef GraphType::ArcIt                     ArcIt;
+    typedef GraphType::IncEdgeIt                 IncEdgeIt;
+    typedef GraphType::InArcIt                   InArcIt;
+    typedef GraphType::OutArcIt                  OutArcIt;
+    typedef GraphType::NeighborNodeIt            NeighborNodeIt;
+    AdjacencyListGraphTest(){       
+
+    }
+
+    void adjGraphSimpleTestStart0(){
+        GraphType g(0,0);
+
+        // add nodes
+        shouldEqual(g.nodeNum(),0);
+        shouldEqual(g.edgeNum(),0);
+        should(g.nodeFromId(0)==lemon::INVALID);
+        should(g.nodeFromId(1)==lemon::INVALID);
+        should(g.nodeFromId(2)==lemon::INVALID);
+        should(g.nodeFromId(3)==lemon::INVALID);
+        should(g.nodeFromId(4)==lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+        Node n1 = g.addNode();
+        shouldEqual(g.nodeNum(),1);
+        shouldEqual(g.edgeNum(),0);
+        shouldEqual(g.maxNodeId(),0);
+        should(g.nodeFromId(0)!=lemon::INVALID);
+        should(g.nodeFromId(1)==lemon::INVALID);
+        should(g.nodeFromId(2)==lemon::INVALID);
+        should(g.nodeFromId(3)==lemon::INVALID);
+        should(g.nodeFromId(4)==lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+        Node n2 = g.addNode();
+        shouldEqual(g.nodeNum(),2);
+        shouldEqual(g.edgeNum(),0);
+        shouldEqual(g.maxNodeId(),1);
+        should(g.nodeFromId(0)!=lemon::INVALID);
+        should(g.nodeFromId(1)!=lemon::INVALID);
+        should(g.nodeFromId(2)==lemon::INVALID);
+        should(g.nodeFromId(3)==lemon::INVALID);
+        should(g.nodeFromId(4)==lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+        Node n3 = g.addNode();
+        shouldEqual(g.nodeNum(),3);
+        shouldEqual(g.edgeNum(),0);
+        shouldEqual(g.maxNodeId(),2);
+        should(g.nodeFromId(0)!=lemon::INVALID);
+        should(g.nodeFromId(1)!=lemon::INVALID);
+        should(g.nodeFromId(2)!=lemon::INVALID);
+        should(g.nodeFromId(3)==lemon::INVALID);
+        should(g.nodeFromId(4)==lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+
+        Node n4 = g.addNode();
+        shouldEqual(g.nodeNum(),4);
+        shouldEqual(g.edgeNum(),0);
+        shouldEqual(g.maxNodeId(),3);
+        should(g.nodeFromId(0)!=lemon::INVALID);
+        should(g.nodeFromId(1)!=lemon::INVALID);
+        should(g.nodeFromId(2)!=lemon::INVALID);
+        should(g.nodeFromId(3)!=lemon::INVALID);
+        should(g.nodeFromId(4)==lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+        shouldEqual(g.edgeNum(),0);
+
+        should(  g.findEdge(n1,n2) == lemon::INVALID  );
+        should(  g.findEdge(n1,n3) == lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) == lemon::INVALID  );
+        should(  g.findEdge(n3,n4) == lemon::INVALID  );
+
+        // add edges
+        // SET UP THIS GRAPH 
+        // 1 |3
+        // __ __
+        // 2 |4
+
+        should(g.edgeFromId(0)==lemon::INVALID);
+        should(g.edgeFromId(1)==lemon::INVALID);
+        should(g.edgeFromId(2)==lemon::INVALID);
+        should(g.edgeFromId(3)==lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+        should(g.edgeFromId(5)==lemon::INVALID);
+
+
+        Edge e12  = g.addEdge(n1,n2);
+        shouldEqual(g.edgeNum(),1);
+        shouldEqual(g.maxEdgeId(),0);
+        should(g.u(e12)==n1);
+        should(g.v(e12)==n2);
+        should(g.edgeFromId(0)!=lemon::INVALID);
+        should(g.edgeFromId(1)==lemon::INVALID);
+        should(g.edgeFromId(2)==lemon::INVALID);
+        should(g.edgeFromId(3)==lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+        should(g.edgeFromId(5)==lemon::INVALID);
+        should(  g.findEdge(n1,n2) != lemon::INVALID  );
+        should(  g.findEdge(n1,n3) == lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) == lemon::INVALID  );
+        should(  g.findEdge(n3,n4) == lemon::INVALID  );
+
+        Edge e13  = g.addEdge(n1,n3);
+        shouldEqual(g.edgeNum(),2);
+        shouldEqual(g.maxEdgeId(),1);
+        should(g.u(e13)==n1);
+        should(g.v(e13)==n3);
+        should(g.edgeFromId(0)!=lemon::INVALID);
+        should(g.edgeFromId(1)!=lemon::INVALID);
+        should(g.edgeFromId(2)==lemon::INVALID);
+        should(g.edgeFromId(3)==lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+        should(g.edgeFromId(5)==lemon::INVALID);
+        should(  g.findEdge(n1,n2) != lemon::INVALID  );
+        should(  g.findEdge(n1,n3) != lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) == lemon::INVALID  );
+        should(  g.findEdge(n3,n4) == lemon::INVALID  );
+
+        Edge e24  = g.addEdge(n2,n4);
+        shouldEqual(g.edgeNum(),3);  
+        shouldEqual(g.maxEdgeId(),2);
+        should(g.u(e24)==n2);
+        should(g.v(e24)==n4);
+        should(g.edgeFromId(0)!=lemon::INVALID);
+        should(g.edgeFromId(1)!=lemon::INVALID);
+        should(g.edgeFromId(2)!=lemon::INVALID);
+        should(g.edgeFromId(3)==lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+        should(g.edgeFromId(5)==lemon::INVALID);
+        should(  g.findEdge(n1,n2) != lemon::INVALID  );
+        should(  g.findEdge(n1,n3) != lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) != lemon::INVALID  );
+        should(  g.findEdge(n3,n4) == lemon::INVALID  );
+
+        Edge e34  = g.addEdge(n3,n4);
+        shouldEqual(g.edgeNum(),4);
+        shouldEqual(g.maxEdgeId(),3);
+        should(g.u(e34)==n3);
+        should(g.v(e34)==n4);
+        should(g.edgeFromId(0)!=lemon::INVALID);
+        should(g.edgeFromId(1)!=lemon::INVALID);
+        should(g.edgeFromId(2)!=lemon::INVALID);
+        should(g.edgeFromId(3)!=lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+        should(g.edgeFromId(5)==lemon::INVALID);
+        should(  g.findEdge(n1,n2) != lemon::INVALID  );
+        should(  g.findEdge(n1,n3) != lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) != lemon::INVALID  );
+        should(  g.findEdge(n3,n4) != lemon::INVALID  );
+
+        // WE HAVE THIS THIS GRAPH 
+        // 1 |3
+        // __ __
+        // 2 |4
+    }
+    void adjGraphSimpleTestStart1(){
+        GraphType g(0,0);
+
+        // add nodes
+        shouldEqual(g.nodeNum(),0);
+        shouldEqual(g.edgeNum(),0);
+        should(g.nodeFromId(0)==lemon::INVALID);
+        should(g.nodeFromId(1)==lemon::INVALID);
+        should(g.nodeFromId(2)==lemon::INVALID);
+        should(g.nodeFromId(3)==lemon::INVALID);
+        should(g.nodeFromId(4)==lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+        Node n1 = g.addNode(1);
+        shouldEqual(g.nodeNum(),1);
+        shouldEqual(g.edgeNum(),0);
+        shouldEqual(g.maxNodeId(),1);
+        should(g.nodeFromId(0)==lemon::INVALID);
+        should(g.nodeFromId(1)!=lemon::INVALID);
+        should(g.nodeFromId(2)==lemon::INVALID);
+        should(g.nodeFromId(3)==lemon::INVALID);
+        should(g.nodeFromId(4)==lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+        Node n2 = g.addNode(2);
+        shouldEqual(g.nodeNum(),2);
+        shouldEqual(g.edgeNum(),0);
+        shouldEqual(g.maxNodeId(),2);
+        should(g.nodeFromId(0)==lemon::INVALID);
+        should(g.nodeFromId(1)!=lemon::INVALID);
+        should(g.nodeFromId(2)!=lemon::INVALID);
+        should(g.nodeFromId(3)==lemon::INVALID);
+        should(g.nodeFromId(4)==lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+        Node n3 = g.addNode(3);
+        shouldEqual(g.nodeNum(),3);
+        shouldEqual(g.edgeNum(),0);
+        shouldEqual(g.maxNodeId(),3);
+        should(g.nodeFromId(0)==lemon::INVALID);
+        should(g.nodeFromId(1)!=lemon::INVALID);
+        should(g.nodeFromId(2)!=lemon::INVALID);
+        should(g.nodeFromId(3)!=lemon::INVALID);
+        should(g.nodeFromId(4)==lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+
+        Node n4 = g.addNode(4);
+        shouldEqual(g.nodeNum(),4);
+        shouldEqual(g.edgeNum(),0);
+        shouldEqual(g.maxNodeId(),4);
+        should(g.nodeFromId(0)==lemon::INVALID);
+        should(g.nodeFromId(1)!=lemon::INVALID);
+        should(g.nodeFromId(2)!=lemon::INVALID);
+        should(g.nodeFromId(3)!=lemon::INVALID);
+        should(g.nodeFromId(4)!=lemon::INVALID);
+        should(g.nodeFromId(5)==lemon::INVALID);
+
+        shouldEqual(g.edgeNum(),0);
+
+        should(  g.findEdge(n1,n2) == lemon::INVALID  );
+        should(  g.findEdge(n1,n3) == lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) == lemon::INVALID  );
+        should(  g.findEdge(n3,n4) == lemon::INVALID  );
+
+        // add edges
+        // SET UP THIS GRAPH 
+        // 1 |3
+        // __ __
+        // 2 |4
+
+        should(g.edgeFromId(0)==lemon::INVALID);
+        should(g.edgeFromId(1)==lemon::INVALID);
+        should(g.edgeFromId(2)==lemon::INVALID);
+        should(g.edgeFromId(3)==lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+
+
+
+        Edge e12  = g.addEdge(n1,n2);
+        shouldEqual(g.edgeNum(),1);
+        shouldEqual(g.maxEdgeId(),0);
+        should(g.u(e12)==n1);
+        should(g.v(e12)==n2);
+        should(g.edgeFromId(0)!=lemon::INVALID);
+        should(g.edgeFromId(1)==lemon::INVALID);
+        should(g.edgeFromId(2)==lemon::INVALID);
+        should(g.edgeFromId(3)==lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+
+        should(  g.findEdge(n1,n2) != lemon::INVALID  );
+        should(  g.findEdge(n1,n3) == lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) == lemon::INVALID  );
+        should(  g.findEdge(n3,n4) == lemon::INVALID  );
+
+        Edge e13  = g.addEdge(n1,n3);
+        shouldEqual(g.edgeNum(),2);
+        shouldEqual(g.maxEdgeId(),1);
+        should(g.u(e13)==n1);
+        should(g.v(e13)==n3);
+        should(g.edgeFromId(0)!=lemon::INVALID);
+        should(g.edgeFromId(1)!=lemon::INVALID);
+        should(g.edgeFromId(2)==lemon::INVALID);
+        should(g.edgeFromId(3)==lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+        should(  g.findEdge(n1,n2) != lemon::INVALID  );
+        should(  g.findEdge(n1,n3) != lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) == lemon::INVALID  );
+        should(  g.findEdge(n3,n4) == lemon::INVALID  );
+
+        Edge e24  = g.addEdge(n2,n4);
+        shouldEqual(g.edgeNum(),3);  
+        shouldEqual(g.maxEdgeId(),2);
+        should(g.u(e24)==n2);
+        should(g.v(e24)==n4);
+        should(g.edgeFromId(0)!=lemon::INVALID);
+        should(g.edgeFromId(1)!=lemon::INVALID);
+        should(g.edgeFromId(2)!=lemon::INVALID);
+        should(g.edgeFromId(3)==lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+        should(  g.findEdge(n1,n2) != lemon::INVALID  );
+        should(  g.findEdge(n1,n3) != lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) != lemon::INVALID  );
+        should(  g.findEdge(n3,n4) == lemon::INVALID  );
+
+        Edge e34  = g.addEdge(n3,n4);
+        shouldEqual(g.edgeNum(),4);
+        shouldEqual(g.maxEdgeId(),3);
+        should(g.u(e34)==n3);
+        should(g.v(e34)==n4);
+        should(g.edgeFromId(0)!=lemon::INVALID);
+        should(g.edgeFromId(1)!=lemon::INVALID);
+        should(g.edgeFromId(2)!=lemon::INVALID);
+        should(g.edgeFromId(3)!=lemon::INVALID);
+        should(g.edgeFromId(4)==lemon::INVALID);
+        should(  g.findEdge(n1,n2) != lemon::INVALID  );
+        should(  g.findEdge(n1,n3) != lemon::INVALID  );
+        should(  g.findEdge(n1,n4) == lemon::INVALID  );
+        should(  g.findEdge(n2,n3) == lemon::INVALID  );
+        should(  g.findEdge(n2,n4) != lemon::INVALID  );
+        should(  g.findEdge(n3,n4) != lemon::INVALID  );
+
+        // WE HAVE THIS THIS GRAPH 
+        // 1 |3
+        // __ __
+        // 2 |4
+    }
+
+    void adjGraphEdgeItTestStart0()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g(0,0);
+
+        Node n1=g.addNode();
+        Node n2=g.addNode();
+        Node n3=g.addNode();
+        Node n4=g.addNode();
+
+        g.addEdge(n1,n2);
+        g.addEdge(n1,n3);
+        g.addEdge(n2,n4);
+        g.addEdge(n3,n4);
+
+
+        
+
+        {
+            EdgeIt begin(g);
+            EdgeIt invalid(lemon::INVALID);
+
+            should(begin!=lemon::INVALID);
+
+            
+            std::vector<Edge> edgeVec(begin,invalid);
+            shouldEqual(4,edgeVec.size());
+            shouldEqual(0,g.id(edgeVec[0]));
+            shouldEqual(1,g.id(edgeVec[1]));
+            shouldEqual(2,g.id(edgeVec[2]));
+            shouldEqual(3,g.id(edgeVec[3]));
+        }
+        {
+            EdgeIt begin(g);
+            should(begin!=lemon::INVALID);
+
+            EdgeIt empty;
+            std::vector<Edge> edgeVec(begin,empty);
+            shouldEqual(4,edgeVec.size());
+            shouldEqual(0,g.id(edgeVec[0]));
+            shouldEqual(1,g.id(edgeVec[1]));
+            shouldEqual(2,g.id(edgeVec[2]));
+            shouldEqual(3,g.id(edgeVec[3]));
+        }
+        {
+            EdgeIt begin(g,g.edgeFromId(1));
+            should(begin!=lemon::INVALID);
+
+            EdgeIt empty;
+            std::vector<Edge> edgeVec(begin,empty);
+            shouldEqual(3,edgeVec.size());
+            shouldEqual(1,g.id(edgeVec[0]));
+            shouldEqual(2,g.id(edgeVec[1]));
+            shouldEqual(3,g.id(edgeVec[2]));
+        }
+        {
+            EdgeIt begin(g,g.edgeFromId(1));
+            EdgeIt end(g,g.edgeFromId(2));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);    
+            should(begin!=end);
+
+            shouldEqual(std::distance(begin,end),1);
+            std::vector<Edge> edgeVec(begin,end);
+            shouldEqual(1,edgeVec.size());
+            shouldEqual(1,g.id(edgeVec[0]));
+        }
+
+        {
+            EdgeIt begin(g,g.edgeFromId(1));
+            EdgeIt end(g,g.edgeFromId(3));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);
+
+            std::vector<Edge> edgeVec(begin,end);
+            shouldEqual(2,edgeVec.size());
+            shouldEqual(1,g.id(edgeVec[0]));
+            shouldEqual(2,g.id(edgeVec[1]));
+        }
+    }
+    void adjGraphEdgeItTestStart1()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g;
+
+        Node n1=g.addNode(1);
+        Node n2=g.addNode(2);
+        Node n3=g.addNode(3);
+        Node n4=g.addNode(4);
+
+        g.addEdge(n1,n2);
+        g.addEdge(n1,n3);
+        g.addEdge(n2,n4);
+        g.addEdge(n3,n4);
+
+
+        
+        {
+            EdgeIt begin(g);
+            EdgeIt invalid(lemon::INVALID);
+
+            should(begin!=lemon::INVALID);
+
+            
+            std::vector<Edge> edgeVec(begin,invalid);
+            shouldEqual(4,edgeVec.size());
+            shouldEqual(0,g.id(edgeVec[0]));
+            shouldEqual(1,g.id(edgeVec[1]));
+            shouldEqual(2,g.id(edgeVec[2]));
+            shouldEqual(3,g.id(edgeVec[3]));
+        }
+        {
+            EdgeIt begin(g);
+            should(begin!=lemon::INVALID);
+
+            EdgeIt empty;
+            std::vector<Edge> edgeVec(begin,empty);
+            shouldEqual(4,edgeVec.size());
+            shouldEqual(0,g.id(edgeVec[0]));
+            shouldEqual(1,g.id(edgeVec[1]));
+            shouldEqual(2,g.id(edgeVec[2]));
+            shouldEqual(3,g.id(edgeVec[3]));
+        }
+        {
+            EdgeIt begin(g,g.edgeFromId(1));
+            should(begin!=lemon::INVALID);
+
+            EdgeIt empty;
+            std::vector<Edge> edgeVec(begin,empty);
+            shouldEqual(3,edgeVec.size());
+            shouldEqual(1,g.id(edgeVec[0]));
+            shouldEqual(2,g.id(edgeVec[1]));
+            shouldEqual(3,g.id(edgeVec[2]));
+        }
+        {
+            EdgeIt begin(g,g.edgeFromId(1));
+            EdgeIt end(g,g.edgeFromId(2));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);    
+            should(begin!=end);
+
+            shouldEqual(std::distance(begin,end),1);
+            std::vector<Edge> edgeVec(begin,end);
+            shouldEqual(1,edgeVec.size());
+            shouldEqual(1,g.id(edgeVec[0]));
+        }
+
+        {
+            EdgeIt begin(g,g.edgeFromId(1));
+            EdgeIt end(g,g.edgeFromId(3));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);
+
+            std::vector<Edge> edgeVec(begin,end);
+            shouldEqual(2,edgeVec.size());
+            shouldEqual(1,g.id(edgeVec[0]));
+            shouldEqual(2,g.id(edgeVec[1]));
+        }
+    }
+
+
+    void adjGraphNodeItTestStart0()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g(0,0);
+
+        Node n1=g.addNode();
+        Node n2=g.addNode();
+        Node n3=g.addNode();
+        Node n4=g.addNode();
+
+        g.addEdge(n1,n2);
+        g.addEdge(n1,n3);
+        g.addEdge(n2,n4);
+        g.addEdge(n3,n4);
+
+        {
+            NodeIt begin(g);
+            NodeIt invalid(lemon::INVALID);
+
+            should(begin!=lemon::INVALID);            
+            std::vector<Node> nodeVec(begin,invalid);
+            shouldEqual(4,nodeVec.size());
+            shouldEqual(0,g.id(nodeVec[0]));
+            shouldEqual(1,g.id(nodeVec[1]));
+            shouldEqual(2,g.id(nodeVec[2]));
+            shouldEqual(3,g.id(nodeVec[3]));
+        }
+        {
+            NodeIt begin(g);
+            should(begin!=lemon::INVALID);
+
+            NodeIt empty;
+            std::vector<Node> nodeVec(begin,empty);
+            shouldEqual(4,nodeVec.size());
+            shouldEqual(0,g.id(nodeVec[0]));
+            shouldEqual(1,g.id(nodeVec[1]));
+            shouldEqual(2,g.id(nodeVec[2]));
+            shouldEqual(3,g.id(nodeVec[3]));
+        }
+        {
+            NodeIt begin(g,g.nodeFromId(1));
+            should(begin!=lemon::INVALID);
+
+            NodeIt empty;
+            std::vector<Node> nodeVec(begin,empty);
+            shouldEqual(3,nodeVec.size());
+            shouldEqual(1,g.id(nodeVec[0]));
+            shouldEqual(2,g.id(nodeVec[1]));
+            shouldEqual(3,g.id(nodeVec[2]));
+        }
+        {
+            NodeIt begin(g,g.nodeFromId(1));
+            NodeIt end(g,g.nodeFromId(2));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);    
+            should(begin!=end);
+
+            shouldEqual(std::distance(begin,end),1);
+            std::vector<Node> nodeVec(begin,end);
+            shouldEqual(1,nodeVec.size());
+            shouldEqual(1,g.id(nodeVec[0]));
+        }
+
+        {
+            NodeIt begin(g,g.nodeFromId(1));
+            NodeIt end(g,g.nodeFromId(3));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);
+
+            std::vector<Node> nodeVec(begin,end);
+            shouldEqual(2,nodeVec.size());
+            shouldEqual(1,g.id(nodeVec[0]));
+            shouldEqual(2,g.id(nodeVec[1]));
+        }
+    }
+    void adjGraphNodeItTestStart1()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g;
+        {
+            NodeIt begin(g);
+            NodeIt invalid(lemon::INVALID);
+            should(std::distance(begin,invalid)==0);
+            should(begin==invalid);
+            should(begin==lemon::INVALID);
+        }
+
+
+        Node n1=g.addNode(1);
+        Node n2=g.addNode(2);
+        Node n3=g.addNode(3);
+        Node n4=g.addNode(4);
+
+        g.addEdge(n1,n2);
+        g.addEdge(n1,n3);
+        g.addEdge(n2,n4);
+        g.addEdge(n3,n4);
+
+        {
+            NodeIt begin(g);
+            NodeIt invalid(lemon::INVALID);
+
+            should(begin!=lemon::INVALID);            
+            std::vector<Node> nodeVec(begin,invalid);
+            shouldEqual(4,nodeVec.size());
+            shouldEqual(1,g.id(nodeVec[0]));
+            shouldEqual(2,g.id(nodeVec[1]));
+            shouldEqual(3,g.id(nodeVec[2]));
+            shouldEqual(4,g.id(nodeVec[3]));
+        }
+        {
+            NodeIt begin(g);
+            should(begin!=lemon::INVALID);
+
+            NodeIt empty;
+            std::vector<Node> nodeVec(begin,empty);
+            shouldEqual(4,nodeVec.size());
+            shouldEqual(1,g.id(nodeVec[0]));
+            shouldEqual(2,g.id(nodeVec[1]));
+            shouldEqual(3,g.id(nodeVec[2]));
+            shouldEqual(4,g.id(nodeVec[3]));
+        }
+        {
+            NodeIt begin(g,g.nodeFromId(2));
+            should(begin!=lemon::INVALID);
+
+            NodeIt empty;
+            std::vector<Node> nodeVec(begin,empty);
+            shouldEqual(3,nodeVec.size());
+            shouldEqual(2,g.id(nodeVec[0]));
+            shouldEqual(3,g.id(nodeVec[1]));
+            shouldEqual(4,g.id(nodeVec[2]));
+        }
+        {
+            NodeIt begin(g,g.nodeFromId(2));
+            NodeIt end(g,g.nodeFromId(3));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);    
+            should(begin!=end);
+
+            shouldEqual(std::distance(begin,end),1);
+            std::vector<Node> nodeVec(begin,end);
+            shouldEqual(1,nodeVec.size());
+            shouldEqual(2,g.id(nodeVec[0]));
+        }
+
+        {
+            NodeIt begin(g,g.nodeFromId(2));
+            NodeIt end(g,g.nodeFromId(4));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);
+
+            std::vector<Node> nodeVec(begin,end);
+            shouldEqual(2,nodeVec.size());
+            shouldEqual(2,g.id(nodeVec[0]));
+            shouldEqual(3,g.id(nodeVec[1]));
+        }
+    }
+    void adjGraphTestStart0()
+    {
+
+        GraphType g(0,0);
+
+        Node n1=g.addNode();
+        Node n2=g.addNode();
+        Node n3=g.addNode();
+        Node n4=g.addNode();
+
+        g.addEdge(n1,n2);
+        g.addEdge(n1,n3);
+        g.addEdge(n2,n4);
+        g.addEdge(n3,n4);
+
+
+
+
+        
+        // assert basic sizes
+        should(g.edgeNum()==4);
+        should(g.nodeNum()==4);
+        should(g.arcNum()==8);
+        should(g.maxEdgeId()==3);
+        should(g.maxNodeId()==3);
+        should(g.maxArcId()==7);
+
+
+
+        NodeIt nbegin(g);
+        NodeIt nend(lemon::INVALID);
+
+        EdgeIt ebegin(g);
+        EdgeIt eend(lemon::INVALID);
+
+
+        ArcIt abegin(g);
+        ArcIt aend(lemon::INVALID);
+
+        std::vector<Node> allNodes(nbegin,nend);
+        should(allNodes.size()==4);
+
+        std::vector<Edge> allEdges(ebegin,eend);
+        should(allEdges.size()==4);
+
+
+        should(0==g.id( allEdges[0] ) );
+        should(1==g.id( allEdges[1] ) );
+        should(2==g.id( allEdges[2] ) );
+        should(3==g.id( allEdges[3] ) );
+        
+
+        std::vector<Arc>  allArcs( abegin,aend);
+
+        should(allArcs.size() ==8);
+
+
+        shouldEqual(g.id(allArcs[0]),0);
+        shouldEqual(g.id(allArcs[1]),1);
+        shouldEqual(g.id(allArcs[2]),2);
+        shouldEqual(g.id(allArcs[3]),3);
+        shouldEqual(g.id(allArcs[4]),4);
+        shouldEqual(g.id(allArcs[5]),5);
+        shouldEqual(g.id(allArcs[6]),6);
+        shouldEqual(g.id(allArcs[7]),7);
+
+        shouldEqual(allArcs[0].edgeId(),0);
+        shouldEqual(allArcs[1].edgeId(),1);
+        shouldEqual(allArcs[2].edgeId(),2);
+        shouldEqual(allArcs[3].edgeId(),3);
+        shouldEqual(allArcs[4].edgeId(),0);
+        shouldEqual(allArcs[5].edgeId(),1);
+        shouldEqual(allArcs[6].edgeId(),2);
+        shouldEqual(allArcs[7].edgeId(),3);
+        
+        shouldEqual(allArcs[0].id(),0);
+        shouldEqual(allArcs[1].id(),1);
+        shouldEqual(allArcs[2].id(),2);
+        shouldEqual(allArcs[3].id(),3);
+        shouldEqual(allArcs[4].id(),4);
+        shouldEqual(allArcs[5].id(),5);
+        shouldEqual(allArcs[6].id(),6);
+        shouldEqual(allArcs[7].id(),7);
+
+
+        shouldEqual( g.id(g.source(allArcs[0])),g.id(g.u(allEdges[0])));
+        shouldEqual( g.id(g.source(allArcs[1])),g.id(g.u(allEdges[1])));
+        shouldEqual( g.id(g.source(allArcs[2])),g.id(g.u(allEdges[2])));
+        shouldEqual( g.id(g.source(allArcs[3])),g.id(g.u(allEdges[3])));
+        shouldEqual( g.id(g.target(allArcs[0])),g.id(g.v(allEdges[0])));
+        shouldEqual( g.id(g.target(allArcs[1])),g.id(g.v(allEdges[1])));
+        shouldEqual( g.id(g.target(allArcs[2])),g.id(g.v(allEdges[2])));
+        shouldEqual( g.id(g.target(allArcs[3])),g.id(g.v(allEdges[3])));
+
+        shouldEqual( g.id(g.source(allArcs[0])),g.id(g.target(allArcs[0+4])));
+        shouldEqual( g.id(g.source(allArcs[1])),g.id(g.target(allArcs[1+4])));
+        shouldEqual( g.id(g.source(allArcs[2])),g.id(g.target(allArcs[2+4])));
+        shouldEqual( g.id(g.source(allArcs[3])),g.id(g.target(allArcs[3+4])));
+        shouldEqual( g.id(g.target(allArcs[0])),g.id(g.source(allArcs[0+4])));
+        shouldEqual( g.id(g.target(allArcs[1])),g.id(g.source(allArcs[1+4])));
+        shouldEqual( g.id(g.target(allArcs[2])),g.id(g.source(allArcs[2+4])));
+        shouldEqual( g.id(g.target(allArcs[3])),g.id(g.source(allArcs[3+4])));
+
+        shouldEqual( g.id(g.source(allArcs[4])),g.id(g.v(allEdges[0])));
+        shouldEqual( g.id(g.source(allArcs[5])),g.id(g.v(allEdges[1])));
+        shouldEqual( g.id(g.source(allArcs[6])),g.id(g.v(allEdges[2])));
+        shouldEqual( g.id(g.source(allArcs[7])),g.id(g.v(allEdges[3])));
+        shouldEqual( g.id(g.target(allArcs[4])),g.id(g.u(allEdges[0])));
+        shouldEqual( g.id(g.target(allArcs[5])),g.id(g.u(allEdges[1])));
+        shouldEqual( g.id(g.target(allArcs[6])),g.id(g.u(allEdges[2])));
+        shouldEqual( g.id(g.target(allArcs[7])),g.id(g.u(allEdges[3])));
+    }
+    void adjGraphTestStart1()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g;
+
+        Node n1=g.addNode(1);
+        Node n2=g.addNode(2);
+        Node n3=g.addNode(3);
+        Node n4=g.addNode(4);
+
+       g.addEdge(n1,n2);
+       g.addEdge(n1,n3);
+       g.addEdge(n2,n4);
+       g.addEdge(n3,n4);
+
+
+
+
+        
+        // assert basic sizes
+        should(g.edgeNum()==4);
+        should(g.nodeNum()==4);
+        should(g.arcNum()==8);
+        should(g.maxEdgeId()==3);
+        should(g.maxNodeId()==4);
+        should(g.maxArcId()==7);
+
+        should( g.findEdge(g.nodeFromId(1),g.nodeFromId(3) )!=lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(1),g.nodeFromId(2) )!=lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(2),g.nodeFromId(4) )!=lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(3),g.nodeFromId(4) )!=lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(1),g.nodeFromId(4) )==lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(2),g.nodeFromId(3) )==lemon::INVALID);
+
+        NodeIt nbegin(g);
+        NodeIt nend(lemon::INVALID);
+
+        EdgeIt ebegin(g);
+        EdgeIt eend(lemon::INVALID);
+
+
+        ArcIt abegin(g);
+        ArcIt aend(lemon::INVALID);
+
+        std::vector<Node> allNodes(nbegin,nend);
+        should(allNodes.size()==4);
+
+        std::vector<Edge> allEdges(ebegin,eend);
+        should(allEdges.size()==4);
+
+
+        should(0==g.id( allEdges[0] ) );
+        should(1==g.id( allEdges[1] ) );
+        should(2==g.id( allEdges[2] ) );
+        should(3==g.id( allEdges[3] ) );
+        
+
+        std::vector<Arc>  allArcs( abegin,aend);
+        should(allArcs.size() ==8);
+
+        shouldEqual(g.id(allArcs[0]),0);
+        shouldEqual(g.id(allArcs[1]),1);
+        shouldEqual(g.id(allArcs[2]),2);
+        shouldEqual(g.id(allArcs[3]),3);
+        shouldEqual(g.id(allArcs[4]),4);
+        shouldEqual(g.id(allArcs[5]),5);
+        shouldEqual(g.id(allArcs[6]),6);
+        shouldEqual(g.id(allArcs[7]),7);
+
+        shouldEqual(allArcs[0].edgeId(),0);
+        shouldEqual(allArcs[1].edgeId(),1);
+        shouldEqual(allArcs[2].edgeId(),2);
+        shouldEqual(allArcs[3].edgeId(),3);
+        shouldEqual(allArcs[4].edgeId(),0);
+        shouldEqual(allArcs[5].edgeId(),1);
+        shouldEqual(allArcs[6].edgeId(),2);
+        shouldEqual(allArcs[7].edgeId(),3);
+        
+        shouldEqual(allArcs[0].id(),0);
+        shouldEqual(allArcs[1].id(),1);
+        shouldEqual(allArcs[2].id(),2);
+        shouldEqual(allArcs[3].id(),3);
+        shouldEqual(allArcs[4].id(),4);
+        shouldEqual(allArcs[5].id(),5);
+        shouldEqual(allArcs[6].id(),6);
+        shouldEqual(allArcs[7].id(),7);
+        
+
+        should( g.id(g.source(allArcs[0]))==g.id(g.u(allEdges[0])));
+        should( g.id(g.source(allArcs[1]))==g.id(g.u(allEdges[1])));
+        should( g.id(g.source(allArcs[2]))==g.id(g.u(allEdges[2])));
+        should( g.id(g.source(allArcs[3]))==g.id(g.u(allEdges[3])));
+
+        should( g.id(g.target(allArcs[0]))==g.id(g.v(allEdges[0])));
+        should( g.id(g.target(allArcs[1]))==g.id(g.v(allEdges[1])));
+        should( g.id(g.target(allArcs[2]))==g.id(g.v(allEdges[2])));
+        should( g.id(g.target(allArcs[3]))==g.id(g.v(allEdges[3])));
+
+
+        should( g.id(g.source(allArcs[0]))==g.id(g.target(allArcs[0+4])));
+        should( g.id(g.source(allArcs[1]))==g.id(g.target(allArcs[1+4])));
+        should( g.id(g.source(allArcs[2]))==g.id(g.target(allArcs[2+4])));
+        should( g.id(g.source(allArcs[3]))==g.id(g.target(allArcs[3+4])));
+
+        should( g.id(g.target(allArcs[0]))==g.id(g.source(allArcs[0+4])));
+        should( g.id(g.target(allArcs[1]))==g.id(g.source(allArcs[1+4])));
+        should( g.id(g.target(allArcs[2]))==g.id(g.source(allArcs[2+4])));
+        should( g.id(g.target(allArcs[3]))==g.id(g.source(allArcs[3+4])));
+
+
+        should( g.id(g.source(allArcs[4]))==g.id(g.v(allEdges[0])));
+        should( g.id(g.source(allArcs[5]))==g.id(g.v(allEdges[1])));
+        should( g.id(g.source(allArcs[6]))==g.id(g.v(allEdges[2])));
+        should( g.id(g.source(allArcs[7]))==g.id(g.v(allEdges[3])));
+
+        should( g.id(g.target(allArcs[4]))==g.id(g.u(allEdges[0])));
+        should( g.id(g.target(allArcs[5]))==g.id(g.u(allEdges[1])));
+        should( g.id(g.target(allArcs[6]))==g.id(g.u(allEdges[2])));
+        should( g.id(g.target(allArcs[7]))==g.id(g.u(allEdges[3])));
+    }
+
+    void adjGraphArcTest()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g;
+
+        Node n1=g.addNode(1);
+        Node n2=g.addNode(2);
+        Node n3=g.addNode(3);
+        Node n4=g.addNode(4);
+
+        g.addEdge(n1,n2);
+        g.addEdge(n1,n3);
+        g.addEdge(n2,n4);
+        g.addEdge(n3,n4);
+        
+        // check sources and targets of arcs which are just the "natural edges"
+        should(  g.source(g.arcFromId(0)) == g.u(g.edgeFromId(0)) );
+        should(  g.source(g.arcFromId(1)) == g.u(g.edgeFromId(1)) );
+        should(  g.source(g.arcFromId(2)) == g.u(g.edgeFromId(2)) );
+        should(  g.source(g.arcFromId(3)) == g.u(g.edgeFromId(3)) );
+
+        should(  g.target(g.arcFromId(0)) == g.v(g.edgeFromId(0)) );
+        should(  g.target(g.arcFromId(1)) == g.v(g.edgeFromId(1)) );
+        should(  g.target(g.arcFromId(2)) == g.v(g.edgeFromId(2)) );
+        should(  g.target(g.arcFromId(3)) == g.v(g.edgeFromId(3)) );
+
+
+
+
+        // check sources and targets of arcs which are flipped "natural edges"
+        should(  g.source(g.arcFromId(4)) == g.v(g.edgeFromId(0)) );
+        should(  g.source(g.arcFromId(5)) == g.v(g.edgeFromId(1)) );
+        should(  g.source(g.arcFromId(6)) == g.v(g.edgeFromId(2)) );
+        should(  g.source(g.arcFromId(7)) == g.v(g.edgeFromId(3)) );
+        should(  g.target(g.arcFromId(4)) == g.u(g.edgeFromId(0)) );
+        should(  g.target(g.arcFromId(5)) == g.u(g.edgeFromId(1)) );
+        should(  g.target(g.arcFromId(6)) == g.u(g.edgeFromId(2)) );
+        should(  g.target(g.arcFromId(7)) == g.u(g.edgeFromId(3)) );
+
+        // check that arcs are convertible to edges
+        should(Edge(g.arcFromId(0))==g.edgeFromId(0));
+        should(Edge(g.arcFromId(1))==g.edgeFromId(1));
+        should(Edge(g.arcFromId(2))==g.edgeFromId(2));
+        should(Edge(g.arcFromId(3))==g.edgeFromId(3));
+
+        should(Edge(g.arcFromId(0))==g.edgeFromId(0));
+        should(Edge(g.arcFromId(1))==g.edgeFromId(1));
+        should(Edge(g.arcFromId(2))==g.edgeFromId(2));
+        should(Edge(g.arcFromId(3))==g.edgeFromId(3));
+
+    }
+
+    void adjGraphArcItTest()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g;
+
+        Node n1=g.addNode(1);
+        Node n2=g.addNode(2);
+        Node n3=g.addNode(3);
+        Node n4=g.addNode(4);
+
+        g.addEdge(n1,n2);
+        g.addEdge(n1,n3);
+        g.addEdge(n2,n4);
+        g.addEdge(n3,n4);
+        {
+            ArcIt begin(g);
+            ArcIt invalid(lemon::INVALID);
+            should(begin!=lemon::INVALID);
+            shouldEqual(std::distance(begin,invalid),8);            
+            std::vector<Arc> arcVec(begin,invalid);
+            shouldEqual(8,arcVec.size());
+            shouldEqual(0,g.id(arcVec[0]));
+            shouldEqual(1,g.id(arcVec[1]));
+            shouldEqual(2,g.id(arcVec[2]));
+            shouldEqual(3,g.id(arcVec[3]));
+            shouldEqual(4,g.id(arcVec[4]));
+            shouldEqual(5,g.id(arcVec[5]));
+            shouldEqual(6,g.id(arcVec[6]));
+            shouldEqual(7,g.id(arcVec[7]));
+        }
+        {
+            ArcIt begin(g);
+            should(begin!=lemon::INVALID);
+
+            ArcIt empty;
+            std::vector<Arc> arcVec(begin,empty);
+            shouldEqual(8,arcVec.size());
+            shouldEqual(0,g.id(arcVec[0]));
+            shouldEqual(1,g.id(arcVec[1]));
+            shouldEqual(2,g.id(arcVec[2]));
+            shouldEqual(3,g.id(arcVec[3]));
+            shouldEqual(4,g.id(arcVec[4]));
+            shouldEqual(5,g.id(arcVec[5]));
+            shouldEqual(6,g.id(arcVec[6]));
+            shouldEqual(7,g.id(arcVec[7]));
+        }
+        {
+            ArcIt begin(g,g.arcFromId(1));
+            should(begin!=lemon::INVALID);
+
+            ArcIt empty;
+            std::vector<Arc> arcVec(begin,empty);
+            shouldEqual(7,arcVec.size());
+            shouldEqual(1,g.id(arcVec[0]));
+            shouldEqual(2,g.id(arcVec[1]));
+            shouldEqual(3,g.id(arcVec[2]));
+            shouldEqual(4,g.id(arcVec[3]));
+            shouldEqual(5,g.id(arcVec[4]));
+            shouldEqual(6,g.id(arcVec[5]));
+            shouldEqual(7,g.id(arcVec[6]));
+        }
+        {
+            ArcIt begin(g,g.arcFromId(1));
+            ArcIt end(g,g.arcFromId(2));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);    
+            should(begin!=end);
+
+            shouldEqual(std::distance(begin,end),1);
+            std::vector<Arc> arcVec(begin,end);
+            shouldEqual(1,arcVec.size());
+            shouldEqual(1,g.id(arcVec[0]));
+        }
+
+        {
+            ArcIt begin(g,g.arcFromId(1));
+            ArcIt end(g,g.arcFromId(3));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);
+
+            std::vector<Arc> arcVec(begin,end);
+            shouldEqual(2,arcVec.size());
+            shouldEqual(1,g.id(arcVec[0]));
+            shouldEqual(2,g.id(arcVec[1]));
+        }
+    }
+
+    void adjGraphFindEdgeTest(){
+
+
+        {
+
+        GraphType g(0,0);
+
+        Node n1=g.addNode(1);
+        Node n2=g.addNode(2);
+        Node n3=g.addNode(3);
+        Node n4=g.addNode(4);
+
+        Edge e12 = g.addEdge(n1,n2);
+        Edge e13 = g.addEdge(n1,n3);
+        Edge e24 = g.addEdge(n2,n4);
+        Edge e34 = g.addEdge(n3,n4);
+
+
+        e12 = g.findEdge(n1,n2);
+        e13 = g.findEdge(n1,n3);
+        e24 = g.findEdge(n2,n4);
+        e34 = g.findEdge(n3,n4);
+
+
+
+        should(e12!=lemon::INVALID);
+        should(e13!=lemon::INVALID);
+        should(e24!=lemon::INVALID);
+        should(e34!=lemon::INVALID);
+
+
+        should(g.findEdge(n2,n3)==lemon::INVALID);
+        should(g.findEdge(n3,n2)==lemon::INVALID);
+        should(g.findEdge(n1,n4)==lemon::INVALID);
+        should(g.findEdge(n4,n1)==lemon::INVALID);
+
+        }
+
+        {
+        GraphType g(0,0);
+
+        Node n1=g.addNode();
+        Node n2=g.addNode();
+        Node n3=g.addNode();
+        Node n4=g.addNode();
+
+        Edge e12 = g.addEdge(n1,n2);
+        Edge e13 = g.addEdge(n1,n3);
+        Edge e24 = g.addEdge(n2,n4);
+        Edge e34 = g.addEdge(n3,n4);
+
+
+        e12 = g.findEdge(n1,n2);
+        e13 = g.findEdge(n1,n3);
+        e24 = g.findEdge(n2,n4);
+        e34 = g.findEdge(n3,n4);
+
+
+
+        should(e12!=lemon::INVALID);
+        should(e13!=lemon::INVALID);
+        should(e24!=lemon::INVALID);
+        should(e34!=lemon::INVALID);
+
+
+        should(g.findEdge(n2,n3)==lemon::INVALID);
+        should(g.findEdge(n3,n2)==lemon::INVALID);
+        should(g.findEdge(n1,n4)==lemon::INVALID);
+        should(g.findEdge(n4,n1)==lemon::INVALID);
+        }
+    }
+
+
+    void adjGraphIncEdgeItTestStart0()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g(0,0);
+
+        Node n1=g.addNode();
+        Node n2=g.addNode();
+        Node n3=g.addNode();
+        Node n4=g.addNode();
+
+        Edge e12 = g.addEdge(n1,n2);
+        Edge e13 = g.addEdge(n1,n3);
+        Edge e24 = g.addEdge(n2,n4);
+        Edge e34 = g.addEdge(n3,n4);
+
+        // get edges
+
+
+        {
+            IncEdgeIt a(g,n1);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e13)!=eSet.end());
+            should(eSet.find(e12)!=eSet.end());
+            should(eSet.find(e34)==eSet.end());
+            should(eSet.find(e24)==eSet.end());
+        }
+        {
+            IncEdgeIt a(g,n2);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e12)!=eSet.end());
+            should(eSet.find(e24)!=eSet.end());
+            should(eSet.find(e34)==eSet.end());
+            should(eSet.find(e13)==eSet.end());
+        }
+        {
+            IncEdgeIt a(g,n3);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e13)!=eSet.end());
+            should(eSet.find(e34)!=eSet.end());
+            should(eSet.find(e12)==eSet.end());
+            should(eSet.find(e24)==eSet.end());
+        }
+        {
+            IncEdgeIt a(g,n4);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e24)!=eSet.end());
+            should(eSet.find(e34)!=eSet.end());
+            should(eSet.find(e12)==eSet.end());
+            should(eSet.find(e13)==eSet.end());
+        }
+    }
+    void adjGraphIncEdgeItTestStart1()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g;
+
+        Node n1=g.addNode(1);
+        Node n2=g.addNode(2);
+        Node n3=g.addNode(3);
+        Node n4=g.addNode(4);
+
+        Edge e12 = g.addEdge(n1,n2);
+        Edge e13 = g.addEdge(n1,n3);
+        Edge e24 = g.addEdge(n2,n4);
+        Edge e34 = g.addEdge(n3,n4);
+
+        // get edges
+
+
+        {
+            IncEdgeIt a(g,n1);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e13)!=eSet.end());
+            should(eSet.find(e12)!=eSet.end());
+            should(eSet.find(e34)==eSet.end());
+            should(eSet.find(e24)==eSet.end());
+        }
+        {
+            IncEdgeIt a(g,n2);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e12)!=eSet.end());
+            should(eSet.find(e24)!=eSet.end());
+            should(eSet.find(e34)==eSet.end());
+            should(eSet.find(e13)==eSet.end());
+        }
+        {
+            IncEdgeIt a(g,n3);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e13)!=eSet.end());
+            should(eSet.find(e34)!=eSet.end());
+            should(eSet.find(e12)==eSet.end());
+            should(eSet.find(e24)==eSet.end());
+        }
+        {
+            IncEdgeIt a(g,n4);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e24)!=eSet.end());
+            should(eSet.find(e34)!=eSet.end());
+            should(eSet.find(e12)==eSet.end());
+            should(eSet.find(e13)==eSet.end());
+        }
+    }
+
+    void adjGraphInArcItTest()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g;
+
+        Node n1=g.addNode(1);
+        Node n2=g.addNode(2);
+        Node n3=g.addNode(3);
+        Node n4=g.addNode(4);
+
+        Edge e12 = g.addEdge(n1,n2);
+        Edge e13 = g.addEdge(n1,n3);
+        Edge e24 = g.addEdge(n2,n4);
+        Edge e34 = g.addEdge(n3,n4);
+
+        n1=g.nodeFromId(1);
+        n2=g.nodeFromId(2);
+        n3=g.nodeFromId(3);
+        n4=g.nodeFromId(4);
+
+        e12 = g.findEdge(n1,n2);
+        e13 = g.findEdge(n1,n3);
+        e24 = g.findEdge(n2,n4);
+        e34 = g.findEdge(n3,n4);
+
+        // get incoming arcs
+        {
+            InArcIt a(g,n1);
+            InArcIt b(lemon::INVALID);
+            // this node has NO in arcs !
+            should(a==b);
+            shouldEqual(std::distance(a,b),0);
+        }
+        {
+            InArcIt a(g,n2);
+            InArcIt b(lemon::INVALID);
+            // this node has 1 incoming arc
+            should(a!=b);
+            shouldEqual(std::distance(a,b),1);
+            Arc arc(*a);
+            Node source = g.source(arc);
+            Node target = g.target(arc);
+            shouldEqual(g.id(target),g.id(n2));
+            shouldEqual(g.id(source),g.id(n1));
+        }
+        {
+            InArcIt a(g,n3);
+            InArcIt b(lemon::INVALID);
+            should(a!=b);
+            shouldEqual(std::distance(a,b),1);
+            Arc arc(*a);
+            Node source = g.source(arc);
+            Node target = g.target(arc);
+            shouldEqual(g.id(target),g.id(n3));
+            shouldEqual(g.id(source),g.id(n1));
+        }
+        {
+            InArcIt a(g,n4);
+            InArcIt b(lemon::INVALID);
+            // this node has 1 incoming arc
+            should(a!=b);
+            shouldEqual(std::distance(a,b),2);
+            Arc arc1(*a); ++a;
+            Arc arc2(*a); ++a;
+            should(a==b);
+            should(a==lemon::INVALID);
+            Node source1 = g.source(arc1);
+            Node target1 = g.target(arc1);
+            Node source2 = g.source(arc2);
+            Node target2 = g.target(arc2);
+            shouldEqual(g.id(target1),g.id(n4));
+            shouldEqual(g.id(target2),g.id(n4));
+            should(source1 !=source2 );
+            should(source1==n2 || source2==n2);
+            should(source1==n3 || source2==n3);
+
+        }
+    
+    }
+
+    void adjGraphOutArcItTest()
+    {
+        // 1 |3
+        // __ __
+        // 2 |4
+        // create g
+        GraphType g;
+
+        Node n1=g.addNode(1);
+        Node n2=g.addNode(2);
+        Node n3=g.addNode(3);
+        Node n4=g.addNode(4);
+
+        Edge e12 = g.addEdge(n1,n2);
+        Edge e13 = g.addEdge(n1,n3);
+        Edge e24 = g.addEdge(n2,n4);
+        Edge e34 = g.addEdge(n3,n4);
+
+        n1=g.nodeFromId(1);
+        n2=g.nodeFromId(2);
+        n3=g.nodeFromId(3);
+        n4=g.nodeFromId(4);
+
+        e12 = g.findEdge(n1,n2);
+        e13 = g.findEdge(n1,n3);
+        e24 = g.findEdge(n2,n4);
+        e34 = g.findEdge(n3,n4);
+
+
+        {
+            OutArcIt a(g,n1);
+            OutArcIt b(lemon::INVALID);
+            should(a!=b);
+            shouldEqual(std::distance(a,b),2);
+            Arc arc1(*a); ++a;
+            Arc arc2(*a); ++a;
+            should(a==b);
+            should(a==lemon::INVALID);
+            Node source1 = g.source(arc1);
+            Node target1 = g.target(arc1);
+            Node source2 = g.source(arc2);
+            Node target2 = g.target(arc2);
+            shouldEqual(g.id(source1),g.id(n1));
+            shouldEqual(g.id(source2),g.id(n1));
+            should(target1 !=target2 );
+            should(target1==n2 || target2==n2);
+            should(target1==n3 || target2==n3);
+        }
+        {
+            OutArcIt a(g,n2);
+            OutArcIt b(lemon::INVALID);
+            should(a!=b);
+            shouldEqual(std::distance(a,b),1);
+            Arc arc(*a);
+            Node source = g.source(arc);
+            Node target = g.target(arc);
+            shouldEqual(g.id(source),g.id(n2));
+            shouldEqual(g.id(target),g.id(n4));
+            
+        }
+        {
+            OutArcIt a(g,n3);
+            OutArcIt b(lemon::INVALID);
+            should(a!=b);
+            shouldEqual(std::distance(a,b),1);
+            Arc arc(*a);
+            Node source = g.source(arc);
+            Node target = g.target(arc);
+            shouldEqual(g.id(target),g.id(n4));
+            shouldEqual(g.id(source),g.id(n3));
+        }
+        {
+            OutArcIt a(g,n4);
+            OutArcIt b(lemon::INVALID);
+            should(a==lemon::INVALID);
+            should(a==b);
+            shouldEqual(std::distance(a,b),0);
+        }
+    
+    }
+
+};
+
+
+ 
+struct AdjacencyListGraphTestSuite
+: public vigra::test_suite
+{
+    AdjacencyListGraphTestSuite()
+    : vigra::test_suite("AdjacencyListGraphTestSuite")
+    {   
+        
+
+
+        add( testCase( &AdjacencyListGraphTest::adjGraphSimpleTestStart0));
+        add( testCase( &AdjacencyListGraphTest::adjGraphSimpleTestStart1));
+        add( testCase( &AdjacencyListGraphTest::adjGraphNodeItTestStart0));
+        add( testCase( &AdjacencyListGraphTest::adjGraphNodeItTestStart1));
+        add( testCase( &AdjacencyListGraphTest::adjGraphEdgeItTestStart0));
+        add( testCase( &AdjacencyListGraphTest::adjGraphEdgeItTestStart1));
+        add( testCase( &AdjacencyListGraphTest::adjGraphFindEdgeTest));
+        add( testCase( &AdjacencyListGraphTest::adjGraphIncEdgeItTestStart0));
+        add( testCase( &AdjacencyListGraphTest::adjGraphIncEdgeItTestStart1));
+        add( testCase( &AdjacencyListGraphTest::adjGraphTestStart0));
+        add( testCase( &AdjacencyListGraphTest::adjGraphTestStart1));
+
+        add( testCase( &AdjacencyListGraphTest::adjGraphArcTest));
+        add( testCase( &AdjacencyListGraphTest::adjGraphArcItTest));
+        //add( testCase( &AdjacencyListGraphTest::adjGraphInArcItTest));
+        //add( testCase( &AdjacencyListGraphTest::adjGraphOutArcItTest));
+
+
+    }
+};
+
+int main(int argc, char ** argv)
+{
+    AdjacencyListGraphTestSuite test;
+
+    int failed = test.run(vigra::testsToBeExecuted(argc, argv));
+
+    std::cout << test.report() << std::endl;
+
+    return (failed != 0);
+}
+
diff --git a/test/blockwisealgorithms/CMakeLists.txt b/test/blockwisealgorithms/CMakeLists.txt
new file mode 100644
index 0000000..c2a751d
--- /dev/null
+++ b/test/blockwisealgorithms/CMakeLists.txt
@@ -0,0 +1,14 @@
+VIGRA_CONFIGURE_THREADING()
+if(NOT THREADING_FOUND)
+    MESSAGE(STATUS "** WARNING: Your compiler does not support C++ threading.")
+    MESSAGE(STATUS "**          test_blockwiselabeling will not be executed on this platform.")
+    if(NOT WITH_BOOST_THREAD)
+        MESSAGE(STATUS "**          Try to run cmake with '-DWITH_BOOST_THREAD=1' to use boost threading.")
+    endif()
+    
+else()
+    SET(MULTIARRAY_CHUNKED_LIBRARIES ${THREADING_LIBRARIES})
+    VIGRA_ADD_TEST(test_blockwiselabeling test_labeling.cxx LIBRARIES ${MULTIARRAY_CHUNKED_LIBRARIES})
+    VIGRA_ADD_TEST(test_blockwisewatersheds test_watersheds.cxx LIBRARIES ${MULTIARRAY_CHUNKED_LIBRARIES})
+    VIGRA_ADD_TEST(test_blockwiseconvolution test_convolution.cxx LIBRARIES ${MULTIARRAY_CHUNKED_LIBRARIES})
+endif()
\ No newline at end of file
diff --git a/test/blockwisealgorithms/test_convolution.cxx b/test/blockwisealgorithms/test_convolution.cxx
new file mode 100644
index 0000000..621aa4d
--- /dev/null
+++ b/test/blockwisealgorithms/test_convolution.cxx
@@ -0,0 +1,129 @@
+#include <vigra/blockwise_convolution.hxx>
+#include <vigra/blockwise_convolution.hxx>
+
+#include <vigra/multi_convolution.hxx>
+#include <vigra/unittest.hxx>
+#include <vigra/multi_blocking.hxx>
+#include <vigra/multi_blockwise.hxx>
+
+#include <iostream>
+#include "utils.hxx"
+
+using namespace std;
+using namespace vigra;
+
+struct BlockwiseConvolutionTest
+{
+    void simpleTest()
+    {
+        typedef MultiArray<2, double> Array;
+        typedef Array::difference_type Shape;
+ 
+        Shape shape(40);
+        Shape block_shape(2);
+
+        Array data(shape);
+        fillRandom(data.begin(), data.end(), 2000);
+
+        Kernel1D<double> kernel;
+        kernel.initAveraging(3, 2);
+
+        Array correct_output(shape);
+        separableConvolveMultiArray(data, correct_output, kernel);
+        
+        Array tested_output(shape);
+        separableConvolveBlockwise(data, tested_output, kernel, block_shape);
+        
+        shouldEqualSequenceTolerance(correct_output.begin(), correct_output.end(), tested_output.begin(), 1e-14);
+    }
+
+    void chunkedTest()
+    {
+        static const int N = 3;
+
+        typedef MultiArray<3, int> NormalArray;
+        typedef ChunkedArrayLazy<3, int> ChunkedArray;
+
+        typedef NormalArray::difference_type Shape;
+        
+        Shape shape(40);
+        
+        NormalArray data(shape);
+        fillRandom(data.begin(), data.end(), 2000);
+        ChunkedArray chunked_data(shape);
+        chunked_data.commitSubarray(Shape(0), data);
+
+        Kernel1D<double> kernel;
+        kernel.initAveraging(3, 2);
+        vector<Kernel1D<double> > kernels(N, kernel);
+        
+        separableConvolveMultiArray(data, data, kernels.begin()); // data now contains output
+        
+        separableConvolveBlockwise(chunked_data, chunked_data, kernels.begin());
+        
+        NormalArray checked_out_data(shape);
+        chunked_data.checkoutSubarray(Shape(0), checked_out_data);
+        for(int i = 0; i != data.size(); ++i)
+        {
+            shouldEqual(data[i], checked_out_data[i]);
+        }
+    }
+
+    void testParallel()
+    {
+        double sigma = 1.0;
+        BlockwiseConvolutionOptions<2>   opt;
+        TinyVector<double, 2> sigmaV(sigma, sigma);
+
+        opt.setStdDev(sigmaV);
+        opt.blockShape(TinyVector<int, 2>(5,7));
+        opt.numThreads(ParallelOptions::Nice);
+        std::cout << "running testParallel() with " << opt.getNumThreads() << " threads." << std::endl;
+
+        typedef MultiArray<2, double> Array;
+        typedef Array::difference_type Shape;
+        
+        // random array
+        Shape shape(200,200);
+        Array data(shape);
+        fillRandom(data.begin(), data.end(), 2000);
+
+        // blockwise
+        Array resB(shape);
+        gaussianSmoothMultiArray(data, resB, opt);
+
+        // sequential
+        Array res(shape);
+        gaussianSmoothMultiArray(data, res, sigma);
+
+        shouldEqualSequenceTolerance(
+            res.begin(), 
+            res.end(), 
+            resB.begin(), 
+            1e-14
+        );
+
+    }
+};
+
+struct BlockwiseConvolutionTestSuite
+: public test_suite
+{
+    BlockwiseConvolutionTestSuite()
+    : test_suite("blockwise convolution test")
+    {
+        add(testCase(&BlockwiseConvolutionTest::simpleTest));
+        add(testCase(&BlockwiseConvolutionTest::chunkedTest));
+        add(testCase(&BlockwiseConvolutionTest::testParallel));
+    }
+};
+
+int main(int argc, char** argv)
+{
+    BlockwiseConvolutionTestSuite test;
+    int failed = test.run(testsToBeExecuted(argc, argv));
+
+    cout << test.report() << endl;
+
+    return failed != 0;
+}
diff --git a/test/blockwisealgorithms/test_labeling.cxx b/test/blockwisealgorithms/test_labeling.cxx
new file mode 100644
index 0000000..d29bfd4
--- /dev/null
+++ b/test/blockwisealgorithms/test_labeling.cxx
@@ -0,0 +1,310 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#define VIGRA_CHECK_BOUNDS
+
+#include <vigra/blockwise_labeling.hxx>
+
+#include <vigra/multi_array.hxx>
+#include <vigra/multi_array_chunked.hxx>
+#include <vigra/multi_labeling.hxx>
+#include <vigra/unittest.hxx>
+
+#include <vector>
+#include <utility>
+#include <functional>
+
+#include "utils.hxx"
+
+using namespace vigra;
+using namespace std;
+
+template <class DatasIterator, class ShapesIterator>
+void testOnData(DatasIterator datas_begin, DatasIterator datas_end,
+                  ShapesIterator shapes_begin, ShapesIterator shapes_end)
+{
+    for(DatasIterator datas_it = datas_begin ; datas_it != datas_end; ++datas_it)
+    {
+        typedef typename DatasIterator::reference DataRef;
+        DataRef data = *datas_it;
+        for(ShapesIterator shapes_it = shapes_begin; shapes_it != shapes_end; ++shapes_it)
+        {
+            typedef typename ShapesIterator::reference ShapeRef;
+            ShapeRef shape = *shapes_it;
+            
+            vector<NeighborhoodType> neighborhoods;
+            neighborhoods.push_back(DirectNeighborhood);
+            neighborhoods.push_back(IndirectNeighborhood);
+            typedef vector<NeighborhoodType>::iterator NeighborhoodIterator;
+            
+            for(NeighborhoodIterator neighborhood_it = neighborhoods.begin();
+                neighborhood_it != neighborhoods.end();
+                ++neighborhood_it)
+            {   
+                NeighborhoodType neighborhood = *neighborhood_it;
+                typedef typename DatasIterator::value_type Data;
+
+                std::vector<bool> with_backgrounds;
+                with_backgrounds.push_back(true);
+                with_backgrounds.push_back(false);
+                for(std::vector<bool>::iterator backgrounds_it = with_backgrounds.begin();
+                        backgrounds_it != with_backgrounds.end();
+                        ++backgrounds_it)
+                {
+                    bool with_background = *backgrounds_it;
+                    Data correct_labels(data.shape());
+                    Data tested_labels(data.shape());
+                    
+                    BlockwiseLabelOptions options;
+                    options.neighborhood(neighborhood);
+                    options.blockShape(shape);
+
+                    int correct_label_number;
+                    int tested_label_number;
+                    if(with_background)
+                    {
+                        correct_label_number = labelMultiArrayWithBackground(data, correct_labels, neighborhood, 1u);
+                        options.ignoreBackgroundValue(1u);
+                    }
+                    else
+                    {
+                        correct_label_number = labelMultiArray(data, correct_labels, neighborhood);
+                    }
+                    
+                    tested_label_number = labelMultiArrayBlockwise(data, tested_labels, options);
+
+                    if(!equivalentLabels(correct_labels.begin(), correct_labels.end(),
+                                         tested_labels.begin(), tested_labels.end()) ||
+                       correct_label_number != tested_label_number)
+                    {
+                        std::ostringstream oss;
+                        oss << "labeling not equivalent" << endl;
+                        oss << "with background: " << boolalpha << with_background << endl;
+                        oss << "array shape: " << data.shape() << endl;
+                        oss << "block shape: " << shape << endl;
+                        oss << "neighborhood: " << neighborhood << endl;
+                        oss << "data: " << endl;
+                        for(int i = 0; i != data.size(); ++i)
+                            oss << data[i] << " ";
+                        oss << endl;
+                        oss << "expected_labels: " << endl;
+                        for(int i = 0; i != correct_labels.size(); ++i)
+                            oss << correct_labels[i] << " ";
+                        oss << endl;
+                        oss << "got" << endl;
+                        for(int i = 0; i != tested_labels.size(); ++i)
+                            oss << tested_labels[i] << " ";
+                        oss << endl;
+                        failTest(oss.str().c_str());
+                    }
+                }
+            }
+        }
+    }
+}
+
+struct BlockwiseLabelingTest
+{   
+    typedef MultiArray<5, unsigned int> Array5;
+    typedef MultiArray<2, unsigned int> Array2;
+    typedef MultiArray<1, unsigned int> Array1;
+
+    typedef Array5::difference_type Shape5;
+    typedef Array2::difference_type Shape2;
+    typedef Array1::difference_type Shape1;
+
+    vector<Array5> array_fives;
+    vector<Array2> array_twos;
+    vector<Array1> array_ones;
+
+    vector<Shape5> shape_fives;
+    vector<Shape2> shape_twos;
+    vector<Shape1> shape_ones;
+
+    BlockwiseLabelingTest()
+    {
+        array_fives.push_back(Array5(Shape5(1)));
+        array_fives.push_back(Array5(Shape5(2,2,3,4,3)));
+        array_fives.push_back(Array5(Shape5(5,6,2,2,3)));
+        for(int i = 0; i != array_fives.size(); ++i)
+        {
+            fillRandom(array_fives[i].begin(), array_fives[i].end(), 3);
+        }
+
+        array_twos.push_back(Array2(Shape2(1)));
+        array_twos.push_back(Array2(Shape2(1,2)));
+        array_twos.push_back(Array2(Shape2(2,2)));
+        array_twos.push_back(Array2(Shape2(4,4)));
+        array_twos.push_back(Array2(Shape2(6,10)));
+        array_twos.push_back(Array2(Shape2(19,25)));
+        for(int i = 0; i != array_twos.size(); ++i)
+        {
+            fillRandom(array_twos[i].begin(), array_twos[i].end(), 3);
+        }
+        
+        array_ones.push_back(Array1(Shape1(1)));
+        array_ones.push_back(Array1(Shape1(2)));
+        array_ones.push_back(Array1(Shape1(47)));
+        array_ones.push_back(Array1(Shape1(81)));
+        array_ones.push_back(Array1(Shape1(997)));
+        for(int i = 0; i != array_ones.size(); ++i)
+        {
+            fillRandom(array_ones[i].begin(), array_ones[i].end(), 3);
+        }
+
+        shape_fives.push_back(Shape5(1));
+        shape_fives.push_back(Shape5(2));
+        shape_fives.push_back(Shape5(5,4,3,2,1));
+        shape_fives.push_back(Shape5(100000));
+
+        shape_twos.push_back(Shape2(1));
+        shape_twos.push_back(Shape2(2));
+        shape_twos.push_back(Shape2(5,4));
+        shape_twos.push_back(Shape2(1000000));
+
+        shape_ones.push_back(Shape1(1));
+        shape_ones.push_back(Shape1(2));
+        shape_ones.push_back(Shape1(3));
+        shape_ones.push_back(Shape1(5));
+        shape_ones.push_back(Shape1(213));
+    }
+    
+    void debugTest()
+    {
+        typedef MultiArray<2, int> Array;
+        typedef Array::difference_type Shape;
+
+        Shape shape = Shape(2);
+        Array data(shape);
+
+        data(0,0) = 1;
+        data(1,0) = 1;
+        data(0,1) = 1;
+        data(1,1) = 1;
+        
+        MultiArray<2, size_t> blockwise_labels(shape);
+        MultiArray<2, size_t> labels(shape);
+    
+        Shape block_shape(1, 1);
+        //TinyVector<MultiArrayIndex, 3> block_shape(1, 1, 1);
+
+        NeighborhoodType neighborhood = IndirectNeighborhood;
+        using namespace vigra::blockwise;
+    
+        size_t count = labelMultiArrayWithBackground(data, labels, neighborhood, 1);
+        size_t blockwise_count = labelMultiArrayBlockwise(data, blockwise_labels, 
+                                                          BlockwiseLabelOptions().neighborhood(neighborhood)
+                                                                                 .ignoreBackgroundValue(1)
+                                                                                 .blockShape(block_shape));
+        shouldEqual(count, blockwise_count);
+        shouldEqual(equivalentLabels(labels.begin(), labels.end(),
+                                     blockwise_labels.begin(), blockwise_labels.end()),
+                    true);
+    }
+    void chunkedArrayTest()
+    {
+        typedef ChunkedArrayLazy<3, int> DataArray;
+        typedef ChunkedArrayLazy<3, size_t> LabelArray;
+        typedef DataArray::shape_type Shape;
+        
+        Shape shape = Shape(100, 200, 300);
+        Shape chunk_shape = Shape(32);
+
+        DataArray data(shape, chunk_shape);
+        fillRandom(data.begin(), data.end(), 3);
+        LabelArray labels(shape, chunk_shape);
+
+        using namespace vigra::blockwise;
+        
+        BlockwiseLabelOptions options;
+        options.neighborhood(IndirectNeighborhood).ignoreBackgroundValue(1);
+
+        size_t tested_label_number = labelMultiArrayBlockwise(data, labels, options);
+        MultiArray<3, size_t> checked_out_labels(shape);
+        labels.checkoutSubarray(Shape(0), checked_out_labels);
+        
+        MultiArray<3, int> oldschool_data_array(shape);
+        MultiArray<3, size_t> oldschool_label_array(shape);
+        
+        data.checkoutSubarray(Shape(0), oldschool_data_array);
+        size_t actual_label_number = labelMultiArrayWithBackground(oldschool_data_array, oldschool_label_array,
+                                                                   IndirectNeighborhood, 1);
+        
+        shouldEqual(tested_label_number, actual_label_number);
+        shouldEqual(equivalentLabels(checked_out_labels.begin(), checked_out_labels.end(),
+                                     oldschool_label_array.begin(), oldschool_label_array.end()), true);
+    }
+
+    void fiveDimensionalRandomTest()
+    {
+        testOnData(array_fives.begin(), array_fives.end(),
+                     shape_fives.begin(), shape_fives.end());
+    }
+    void twoDimensionalRandomTest()
+    {
+        testOnData(array_twos.begin(), array_twos.end(),
+                     shape_twos.begin(), shape_twos.end());
+    }
+    void oneDimensionalRandomTest()
+    {
+        testOnData(array_ones.begin(), array_ones.end(),
+                     shape_ones.begin(), shape_ones.end());
+    }
+};
+
+struct BlockwiseLabelingTestSuite
+  : public test_suite
+{
+    BlockwiseLabelingTestSuite()
+      : test_suite("blockwise labeling test")
+    {
+        add(testCase(&BlockwiseLabelingTest::oneDimensionalRandomTest));
+        add(testCase(&BlockwiseLabelingTest::twoDimensionalRandomTest));
+        add(testCase(&BlockwiseLabelingTest::fiveDimensionalRandomTest));
+        add(testCase(&BlockwiseLabelingTest::debugTest));
+        add(testCase(&BlockwiseLabelingTest::chunkedArrayTest));
+    }
+};
+
+int main(int argc, char** argv)
+{
+    BlockwiseLabelingTestSuite test;
+    int failed = test.run(testsToBeExecuted(argc, argv));
+
+    cout << test.report() << endl;
+
+    return failed != 0;
+}
+
diff --git a/test/blockwisealgorithms/test_watersheds.cxx b/test/blockwisealgorithms/test_watersheds.cxx
new file mode 100644
index 0000000..96d1823
--- /dev/null
+++ b/test/blockwisealgorithms/test_watersheds.cxx
@@ -0,0 +1,227 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#define VIGRA_CHECK_BOUNDS
+
+#include <vigra/blockwise_watersheds.hxx>
+
+#include <vigra/multi_array.hxx>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/unittest.hxx>
+#include <vigra/multi_watersheds.hxx>
+
+#include <iostream>
+#include <sstream>
+
+#include "utils.hxx"
+
+using namespace std;
+using namespace vigra;
+
+struct BlockwiseWatershedTest
+{
+    void oneDimensionalTest()
+    {
+        typedef MultiArray<1, unsigned int> Array;
+        typedef Array::difference_type Shape;
+
+        vector<Array> data_sets;
+        data_sets.push_back(Array(Shape(1)));
+        data_sets.push_back(Array(Shape(5)));
+        data_sets.push_back(Array(Shape(997)));
+        data_sets.push_back(Array(Shape(10000)));
+        for(int i = 0; i != data_sets.size(); ++i)
+        {
+            fillRandom(data_sets[i].begin(), data_sets[i].end(), 3);
+        }
+        
+        for(int i = 0; i != data_sets.size(); ++i)
+        {
+            const Array& data = data_sets[i];
+            
+            NeighborhoodType neighborhood = DirectNeighborhood;
+            Shape block_shape(1);
+
+
+            typedef MultiArray<1, size_t> LabelArray;
+            
+            LabelArray tested_labels(data.shape());
+            size_t tested_label_number = unionFindWatershedsBlockwise(data, tested_labels, 
+                                                                      BlockwiseLabelOptions().neighborhood(neighborhood)
+                                                                                             .blockShape(block_shape));
+            
+            LabelArray correct_labels(data.shape());
+            size_t correct_label_number = watershedsMultiArray(data, correct_labels, neighborhood,
+                                                               WatershedOptions().unionFind());
+            if(tested_label_number != correct_label_number ||
+               !equivalentLabels(tested_labels.begin(), tested_labels.end(),
+                                 correct_labels.begin(), correct_labels.end()))
+            {
+                ostringstream oss;
+                oss << "labeling not equivalent" << endl;
+                oss << "shape: " << data.shape() << endl;
+                failTest(oss.str().c_str());
+            }
+        }
+    }
+    void fourDimensionalRandomTest()
+    {
+        typedef MultiArray<4, unsigned int> Array;
+        typedef MultiArray<4, size_t> LabelArray;
+        typedef Array::difference_type Shape;
+        
+        vector<Array> data_sets;
+        data_sets.push_back(Array(Shape(1)));
+        data_sets.push_back(Array(Shape(2)));
+        data_sets.push_back(Array(Shape(4, 2, 1, 5)));
+        data_sets.push_back(Array(Shape(4, 5, 7, 3)));
+        data_sets.push_back(Array(Shape(6)));
+        data_sets.push_back(Array(Shape(1, 10, 100, 1)));
+
+        for(int i = 0; i != data_sets.size(); ++i)
+        {
+            fillRandom(data_sets[i].begin(), data_sets[i].end(), 3);
+        }
+
+        vector<Shape> block_shapes;
+        block_shapes.push_back(Shape(1));
+        block_shapes.push_back(Shape(2));
+        block_shapes.push_back(Shape(1,10,10,2));
+        block_shapes.push_back(Shape(1000000));
+        block_shapes.push_back(Shape(4,3,10,1000));
+        
+        vector<NeighborhoodType> neighborhoods;
+        neighborhoods.push_back(DirectNeighborhood);
+        neighborhoods.push_back(IndirectNeighborhood);
+
+        for(int i = 0; i != data_sets.size(); ++i)
+        {
+            const Array& data = data_sets[i];
+            for(int j = 0; j != block_shapes.size(); ++j)
+            {
+                const Shape& block_shape = block_shapes[j];
+                for(int k = 0; k != neighborhoods.size(); ++k)
+                {
+                    NeighborhoodType neighborhood = neighborhoods[k];
+                    
+                    LabelArray tested_labels(data.shape());
+                    size_t tested_label_number = unionFindWatershedsBlockwise(data, tested_labels, 
+                                                                              BlockwiseLabelOptions().neighborhood(neighborhood)
+                                                                                                     .blockShape(block_shape));
+
+                    LabelArray correct_labels(data.shape());
+                    size_t correct_label_number = watershedsMultiArray(data, correct_labels, neighborhood,
+                                                                       WatershedOptions().unionFind());
+                    if(tested_label_number != correct_label_number ||
+                       !equivalentLabels(tested_labels.begin(), tested_labels.end(),
+                                         correct_labels.begin(), correct_labels.end()))
+                    {
+                        ostringstream oss;
+                        oss << "labeling not equivalent" << endl;
+                        oss << "array shape: " << data.shape() << endl;
+                        oss << "block shape: " << block_shape << endl;
+                        oss << "neighborhood: " << neighborhood << endl;
+                        oss << "data:" << endl;
+                        for(int i = 0; i != data.size(); ++i)
+                            oss << data[i] << " ";
+                        oss << endl;
+                        oss << "expected labels:" << endl;
+                        for(int i = 0; i != correct_labels.size(); ++i)
+                            oss << correct_labels[i] << " ";
+                        oss << endl;
+                        oss << "got" << endl;
+                        for(int i = 0; i != tested_labels.size(); ++i)
+                            oss << tested_labels[i] << " ";
+                        oss << endl;
+                        failTest(oss.str().c_str());
+                    }
+                }
+            }
+        }
+    }
+    void chunkedTest()
+    {
+        typedef MultiArray<3, int> OldschoolArray;
+        typedef MultiArray<3, size_t> OldschoolLabelArray;
+
+        typedef ChunkedArrayLazy<3, int> Array;
+        typedef ChunkedArrayLazy<3, size_t> LabelArray;
+        
+        typedef OldschoolArray::difference_type Shape;
+        
+        Shape shape(20, 30, 10);
+        Shape chunk_shape(20, 30, 10);
+        NeighborhoodType neighborhood = IndirectNeighborhood;
+
+        OldschoolArray oldschool_data(shape);
+
+        fillRandom(oldschool_data.begin(), oldschool_data.end(), 3);
+        OldschoolLabelArray correct_labels(shape);
+        size_t correct_label_number = watershedsMultiArray(oldschool_data, correct_labels, neighborhood,
+                                                           WatershedOptions().unionFind());
+        
+        Array data(shape);
+        data.commitSubarray(Shape(0), oldschool_data);
+        LabelArray tested_labels(shape);
+        size_t tested_label_number = unionFindWatershedsBlockwise(data, tested_labels, 
+                                                                  BlockwiseLabelOptions().neighborhood(neighborhood));
+        shouldEqual(correct_label_number, tested_label_number);
+        shouldEqual(equivalentLabels(tested_labels.begin(), tested_labels.end(),
+                                     correct_labels.begin(), correct_labels.end()),
+                    true);
+    }
+};
+
+struct BlockwiseWatershedTestSuite
+  : public test_suite
+{
+    BlockwiseWatershedTestSuite()
+      : test_suite("blockwise watershed test")
+    {
+        add(testCase(&BlockwiseWatershedTest::fourDimensionalRandomTest));
+        add(testCase(&BlockwiseWatershedTest::oneDimensionalTest));
+        add(testCase(&BlockwiseWatershedTest::chunkedTest));
+    }
+};
+
+int main(int argc, char** argv)
+{
+    BlockwiseWatershedTestSuite test;
+    int failed = test.run(testsToBeExecuted(argc, argv));
+
+    cout << test.report() << endl;
+
+    return failed != 0;
+}
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/test/blockwisealgorithms/utils.hxx
similarity index 62%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to test/blockwisealgorithms/utils.hxx
index 37a8c81..48df861 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/test/blockwisealgorithms/utils.hxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,52 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#ifndef VIGRA_BLOCKWISE_ALGORITHMS_TEST_UTILS_HXX
+#define VIGRA_BLOCKWISE_ALGORITHMS_TEST_UTILS_HXX
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
-#include <vigra/numpy_array.hxx>
-#include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
+#include <cstdlib>
 #include <vector>
 
-namespace python = boost::python;
-
-namespace vigra {
-
-UInt32 pychecksum(python::str const & s)
+template <class Iterator1,class Iterator2>
+bool equivalentLabels(Iterator1 begin1, Iterator1 end1,
+                      Iterator2 begin2, Iterator2 end2)
 {
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
+    using namespace std;
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+    if(end1 - begin1 != end2 - begin2)
+        return false;
+    
+    typedef vector<int> LabelMap;
+    LabelMap left_to_right; // from range 1 to range 2
+    LabelMap right_to_left;
+    for( ; begin1 != end1; ++begin1, ++begin2)
+    {
+        if(left_to_right.size() <= *begin1)
+            left_to_right.resize(*begin1 + 1, -1); // "-1" means unmapped
+        if(right_to_left.size() <= *begin2)
+            right_to_left.resize(*begin2 + 1, -1);
 
-} // namespace vigra
+        if(left_to_right[*begin1] == -1) // unmapped -> map it
+            left_to_right[*begin1] = *begin2;
+        else if(left_to_right[*begin1] != *begin2) // already mapped to different value -> not equivalent labels
+            return false;
 
-using namespace boost::python;
-using namespace vigra;
+        if(right_to_left[*begin2] == -1)
+            right_to_left[*begin2] = *begin1;
+        else if(right_to_left[*begin2] != *begin1)
+            return false;
+    }
+    
+    return true;
+}
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
+template <class Iterator>
+void fillRandom(Iterator begin, Iterator end, int maximum)
 {
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
+    using namespace std;
+
+    for( ; begin != end; ++begin)
+        *begin = rand() % maximum;
 }
+
+#endif // VIGRA_BLOCKWISE_ALGORITHMS_TEST_UTILS_HXX
diff --git a/test/classifier/data/CMakeLists.txt b/test/classifier/data/CMakeLists.txt
index ed89cfd..beb1625 100644
--- a/test/classifier/data/CMakeLists.txt
+++ b/test/classifier/data/CMakeLists.txt
@@ -4,4 +4,4 @@
 #       configure_file(${CMAKE_CURRENT_SOURCE_DIR}/oldClassifier.log 
 #                      ${CMAKE_CURRENT_BINARY_DIR}/oldClassifier.log
 #                      COPYONLY)
-VIGRA_COPY_TEST_DATA(oldClassifier.log oldsetTest.log)
+VIGRA_COPY_TEST_DATA(oldClassifier.log oldsetTest.log empty.hdf5 bare.hdf5)
diff --git a/test/classifier/data/bare.hdf5 b/test/classifier/data/bare.hdf5
new file mode 100644
index 0000000..9ee1092
Binary files /dev/null and b/test/classifier/data/bare.hdf5 differ
diff --git a/test/classifier/data/empty.hdf5 b/test/classifier/data/empty.hdf5
new file mode 100644
index 0000000..e69de29
diff --git a/test/classifier/test.cxx b/test/classifier/test.cxx
index 0212cd6..1e26292 100644
--- a/test/classifier/test.cxx
+++ b/test/classifier/test.cxx
@@ -496,7 +496,7 @@ struct ClassifierTest
      */
     void RFresponseTest()
     {
-        int ii = 2; 
+        int ii = 2;
         // learn on glass data set and predict: 
         // this is interesting because there is no label with number 4
         // in this dataset.
@@ -576,6 +576,33 @@ struct ClassifierTest
         std::cerr << "done \n";
     }
 
+    /*
+     * Check weather the new implemented depth and size stop criterion compiles
+     * if the condition is not met the criterion will throw internally an error
+     */
+    void RFDepthAndSizeEarlyStopTest()
+    {
+        std::cerr << "RFDepthAndSizeEarlyStopTest(): Learning on Datasets\n";
+        int ii = 2;
+
+        vigra::RandomForest<>
+            RF(vigra::RandomForestOptions().tree_count(2));
+
+        int maxdepth=1;
+        DepthAndSizeStopping early_depth(maxdepth,10);
+
+        RF.learn( data.features(ii),
+                  data.labels(ii),
+                  rf_default(),
+                  rf_default(),
+                  early_depth,
+                  vigra::RandomMT19937(1));
+
+    }
+
+
+
+
 /** Learns The Refactored Random Forest with 100 trees 10 times and
  *  calulates the mean oob error. The distribution of the oob error
  *  is gaussian as a first approximation. The mean oob error should
@@ -701,12 +728,12 @@ struct ClassifierTest
 
     void RFvariableImportanceTest()
     {
-        double pina_var_imp[] = 
+        double pina_var_imp[] =
         {
-            0.017263, 0.040776, 0.003548, 0.003463, 0.005085, 0.015100, 0.005815, 0.019693, 
-            0.000555, 0.034199, 0.000093, 0.001263, 0.000669, 0.014896, 0.002777, 0.007323, 
-            0.017818, 0.074975, 0.003641, 0.004726, 0.005754, 0.029996, 0.008591, 0.027016, 
-            13.743281, 48.682308, 15.098506, 10.868249, 11.145719, 29.414823, 22.270783, 23.060834 
+            0.0177306,   0.0403224,  0.00387167, 0.0034106,  0.00471615,  0.0153205, 0.00530416, 0.019674,
+            0.000552956, 0.0335148, -8.2882e-05, 0.00100585, 0.000792797, 0.0143894, 0.00297142, 0.00743654,
+            0.0182836,   0.0738372, 0.00378879,  0.00441645, 0.00550894,  0.02971, 	 0.00827557, 0.0271106,
+            13.7433,     48.6823,   15.0985,     10.8682,    11.1457,     29.4148,   22.2708,    23.0608
         };
 
         vigra::MultiArrayView<2, double> p_imp(MultiArrayShape<2>::type(8, 4), pina_var_imp);
@@ -729,12 +756,10 @@ struct ClassifierTest
                             rf_default(),
                             vigra::RandomMT19937(1));
                 
-                var_imp.variable_importance_ -= p_imp;
                 for(int jj = 0; jj < p_imp.shape(0);  ++jj)
                     for(int gg = 0; gg < p_imp.shape(1); ++gg)
-                        shouldEqualTolerance(var_imp
-                                               .variable_importance_(jj, gg)
-                                             , 0.0,0.0001);
+                        shouldEqualTolerance(var_imp.variable_importance_(jj, gg)
+                                             , p_imp(jj,gg),0.01);
                 std::cerr << std::endl;
                 std::cerr << "[";
                 for(int ss = 0; ss < ii+1; ++ss)
@@ -800,6 +825,7 @@ struct ClassifierTest
                 std::string filename = data.names(ii) + "_rf.hdf5";
                 std::string filename_b = data.names(ii) + "_b_rf.hdf5";
                 std::remove(filename.c_str());
+                std::remove(filename_b.c_str());
                 vigra::RandomForest<> RF(vigra::RandomForestOptions()
                                              .tree_count(100));
 
@@ -826,6 +852,36 @@ struct ClassifierTest
                  rf_import_HDF5(RF5, filename_b);
                  should_all(RF, RF5);
 
+		  // test loading into an existing random forest object
+                 rf_import_HDF5(RF5, filename_b);
+                 should_all(RF, RF5);
+
+                hid_t fileId = H5Fopen(filename.c_str(),
+                        H5F_ACC_RDONLY, H5P_DEFAULT);
+
+                // reading from hid_t
+                rf_import_HDF5(RF5, fileId);
+                should_all(RF, RF5);
+
+                // reading from hid_t with group name
+                vigra::RandomForest<> RF6;
+                rf_import_HDF5(RF6, fileId, "/");
+                should_all(RF, RF6);
+
+                // writing to hid_t
+                hid_t fileId2 = H5Fopen(filename_b.c_str(),
+                        H5F_ACC_RDWR, H5P_DEFAULT);
+                rf_export_HDF5(RF, fileId2, "/t/");
+
+                // reading from the hid_t we wrote to
+                vigra::RandomForest<> RF7;
+                rf_import_HDF5(RF7, fileId2, "/t/");
+                should_all(RF, RF7);
+
+                // reading from hid_t with relative group name
+                rf_import_HDF5(RF6, fileId2, "t");
+                should_all(RF, RF6);
+
                  std::cerr << "[";
                  for(int ss = 0; ss < ii+1; ++ss)
                      std::cerr << "#";
@@ -836,6 +892,30 @@ struct ClassifierTest
             }
             std::cerr << "done!\n";
     }
+
+    void HDF5InvalidImportTest()
+    {
+        // at the very least, this should not crash (regression test)
+        HDF5DisableErrorOutput hdf5DisableErrorOutput;
+        RandomForest<> rf;
+        try {
+            bool emptyLoaded = rf_import_HDF5(rf, "data/empty.hdf5");
+            shouldNot(emptyLoaded);
+            failTest("rf_import_HDF5() didn't throw on 0-byte file.");
+        }
+		catch( std::runtime_error const & )
+        {
+        }
+
+        try {
+            bool bareHDF5Loaded = rf_import_HDF5(rf, "data/bare.hdf5");
+            shouldNot(bareHDF5Loaded);
+            failTest("rf_import_HDF5() didn't throw on empty, but valid HDF5 file.");
+        }
+		catch( PreconditionViolation const & )
+        {
+        }
+    }
 #endif
 //};
 
@@ -989,11 +1069,13 @@ struct ClassifierTestSuite
         add( testCase( &ClassifierTest::RF_AlgorithmTest));
 #endif
         add( testCase( &ClassifierTest::RFresponseTest));
-        
+        add( testCase( &ClassifierTest::RFDepthAndSizeEarlyStopTest));
+
         add( testCase( &ClassifierTest::RFridgeRegressionTest));
         add( testCase( &ClassifierTest::RFSplitFunctorTest));
 #ifdef HasHDF5
         add( testCase( &ClassifierTest::HDF5ImpexTest));
+        add( testCase( &ClassifierTest::HDF5InvalidImportTest));
 #endif
          
     }
diff --git a/test/correlation/CMakeLists.txt b/test/correlation/CMakeLists.txt
new file mode 100644
index 0000000..8c515b0
--- /dev/null
+++ b/test/correlation/CMakeLists.txt
@@ -0,0 +1,9 @@
+if(FFTW3_FOUND)
+    INCLUDE_DIRECTORIES(${FFTW3_INCLUDE_DIR})
+
+    VIGRA_CONFIGURE_THREADING()
+      
+    VIGRA_ADD_TEST(test_correlation test.cxx LIBRARIES ${FFTW3_LIBRARIES} ${FFTW3F_LIBRARIES} ${THREADING_LIBRARIES})
+else()
+    MESSAGE(STATUS "** WARNING: test_correlation will not be executed")
+endif()
diff --git a/test/correlation/test.cxx b/test/correlation/test.cxx
new file mode 100755
index 0000000..e18fae1
--- /dev/null
+++ b/test/correlation/test.cxx
@@ -0,0 +1,317 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2013 by Benjamin Seppke                    */      
+/*                                                                      */
+/************************************************************************/
+
+#include <iostream>
+
+#include "vigra/unittest.hxx"
+#include "vigra/multi_array.hxx"
+#include "vigra/multi_math.hxx"
+#include "vigra/correlation.hxx"
+
+using namespace vigra;
+using namespace vigra::multi_math;
+
+
+typedef MultiArray<2,float> ImageType;
+
+static double test_epsilon = 1.0e-5;
+static double test_vs_epsilon = 1.0e-3;
+
+void printMultiArray(const ImageType & img)
+{    
+    for (int y=0; y<img.height(); ++y)
+    {
+        for (int x=0; x<img.width(); ++x)
+        {
+            printf("img(%d,%d) = %1.10f; ", x , y , img(x,y));
+        }      
+        printf("\n");  
+    }
+}
+
+
+struct FastVsSlowCorrelationTest
+{
+    
+    ImageType img;
+    ImageType mask;
+    
+    FastVsSlowCorrelationTest()
+    : img(10,10),
+      mask(5,5)
+    {
+        ImageType::iterator iter = img.begin();
+        
+        for ( ; iter != img.end(); ++iter)
+        {
+            *iter =  rand() % 10 + 1;
+        }
+        
+        for (iter = mask.begin(); iter != mask.end(); ++iter)
+        {
+            *iter =  rand() % 10 + 1;
+        }
+    }
+    
+    
+    void testCorrelation()
+    {
+        ImageType result_slow(10,10);
+        ImageType result_fast(10,10);
+        
+        for(int mask_size=3; mask_size<10; mask_size+=2)
+        {
+            result_fast=0;
+            fastCrossCorrelation(img,
+                                 img.subarray(Shape2(0,0),Shape2(mask_size,mask_size)),
+                                 result_fast);
+            
+            result_slow=0;
+            crossCorrelation(img,
+                             img.subarray(Shape2(0,0),Shape2(mask_size,mask_size)),
+                             result_slow);
+
+            shouldEqualSequenceTolerance(result_fast.begin(), result_fast.end(), result_slow.begin(), test_vs_epsilon);
+        }
+    }
+    
+    
+    void testNormalizedCorrelation()
+    {
+        ImageType result_slow(10,10);
+        ImageType result_fast(10,10);
+        
+        for(int mask_size=3; mask_size<10; mask_size+=2)
+        {
+            result_fast=0;
+            fastNormalizedCrossCorrelation(img,
+                                           img.subarray(Shape2(0,0),Shape2(mask_size,mask_size)),
+                                           result_fast);
+            
+            result_slow=0;
+            normalizedCrossCorrelation(img,
+                                       img.subarray(Shape2(0,0),Shape2(mask_size,mask_size)),
+                                       result_slow);
+            
+            shouldEqualSequenceTolerance(result_fast.begin(), result_fast.end(), result_slow.begin(), test_vs_epsilon);
+        }
+    }
+};
+
+struct FastNormalizedCrossCorrelationEssentialTest
+{
+    ImageType img;
+    ImageType mask;
+    
+    FastNormalizedCrossCorrelationEssentialTest()
+    : img(10,10),
+      mask(5,5)
+    {
+        ImageType::iterator iter = img.begin();
+        
+        for ( ; iter != img.end(); ++iter)
+        {
+            *iter =  rand() % 10 + 1;
+        }
+        
+        for (iter = mask.begin(); iter != mask.end(); ++iter)
+        {
+            *iter =  rand() % 10 + 1;
+        }
+    }
+    
+    void testImagePatch()
+    {
+        ImageType result(10,10);
+        
+        for(int mask_size=3; mask_size<10; mask_size+=2)
+        {
+            fastNormalizedCrossCorrelation(img,
+                                           img.subarray(Shape2(0,0),Shape2(mask_size,mask_size)),
+                                           result);
+            
+            float min, max;
+            result.minmax(&min, &max);
+            should(min >= -1.0); //correlation coeff. minimum should always be >= 0.0
+            should(max <=  1.0); //correlation coeff. maximum should always be <= 1.0
+            
+            shouldEqualTolerance(result(mask_size/2,mask_size/2), 1.0, test_epsilon);
+        }
+    }
+    void testRandomPatch()
+    {
+        ImageType result(10,10);
+        
+        fastNormalizedCrossCorrelation(img,
+                                       img.subarray(Shape2(0,0),Shape2(3,3)),
+                                       result);
+        
+        float min, max;
+        result.minmax(&min, &max);
+        should(min >= -1.0); //correlation coeff. minimum should always be >= 0.0
+        should(max <=  1.0); //correlation coeff. maximum should always be <= 1.0
+    }
+};
+
+struct FastNormalizedCrossCorrelationExactTest
+{
+    ImageType img;
+    ImageType mask;
+            
+    FastNormalizedCrossCorrelationExactTest()
+    : img(7,7),
+      mask(5,5)
+    {
+        img(0,0) = 1;  img(1,0) = 1;  img(2,0) = 1;  img(3,0) = 1;  img(4,0) = 1;  img(5,0) = 1;  img(6,0) = 1;
+        img(0,1) = 1;  img(1,1) = 2;  img(2,1) = 2;  img(3,1) = 2;  img(4,1) = 2;  img(5,1) = 2;  img(6,1) = 1;
+        img(0,2) = 1;  img(1,2) = 2;  img(2,2) = 3;  img(3,2) = 3;  img(4,2) = 3;  img(5,2) = 2;  img(6,2) = 1;
+        img(0,3) = 1;  img(1,3) = 2;  img(2,3) = 3;  img(3,3) = 4;  img(4,3) = 3;  img(5,3) = 2;  img(6,3) = 1;
+        img(0,4) = 1;  img(1,4) = 2;  img(2,4) = 3;  img(3,4) = 3;  img(4,4) = 3;  img(5,4) = 2;  img(6,4) = 1;
+        img(0,5) = 1;  img(1,5) = 2;  img(2,5) = 2;  img(3,5) = 2;  img(4,5) = 2;  img(5,5) = 2;  img(6,5) = 1;
+        img(0,6) = 1;  img(1,6) = 1;  img(2,6) = 1;  img(3,6) = 1;  img(4,6) = 1;  img(5,6) = 1;  img(6,6) = 1;
+        
+        mask(0,0) = 3;  mask(1,0) = 3;  mask(2,0) = 3;  mask(3,0) = 3;   mask(4,0) = 3;  
+        mask(0,1) = 3;  mask(1,1) = 4;  mask(2,1) = 3;  mask(3,1) = 3;   mask(4,1) = 3;  
+        mask(0,2) = 3;  mask(1,2) = 3;  mask(2,2) = 3;  mask(3,2) = 3;   mask(4,2) = 3;  
+        mask(0,3) = 3;  mask(1,3) = 3;  mask(2,3) = 3;  mask(3,3) = 3;   mask(4,3) = 3;  
+        mask(0,4) = 3;  mask(1,4) = 3;  mask(2,4) = 3;  mask(3,4) = 3;   mask(4,4) = 3;  
+    }
+    
+    void testMask1x1()
+    {
+        ImageType result(7,7), ref_img(7,7);
+        result = 0.0;
+        
+        //Nothing is more or less equal to a one element mask
+        ref_img = 0.0;
+                
+        fastNormalizedCrossCorrelation(img,
+                                       mask.subarray(Shape2(0,0),Shape2(1,1)),
+                                       result);
+        
+        shouldEqualSequenceTolerance(result.begin(), result.end(), ref_img.begin(), test_epsilon);
+    }
+    
+    void testMask3x3()
+    {
+        ImageType result(7,7), ref_img(7,7);
+        result = 0.0;
+        ref_img = 0.0;
+        
+        fastNormalizedCrossCorrelation(img,
+                                       mask.subarray(Shape2(0,0),Shape2(3,3)),
+                                       result);
+        
+        ref_img(1,1) = 0.2294157356f; ref_img(2,1) = 0.0533001795f; ref_img(3,1) = 0.0000000000f; ref_img(4,1) = 0.0533001795f; ref_img(5,1) = 0.2294157356f;
+        ref_img(1,2) = 0.0533001795f; ref_img(2,2) = 0.2294157356f; ref_img(3,2) = 0.1250000009f; ref_img(4,2) = 0.2294157356f; ref_img(5,2) = 0.0533001795f;
+        ref_img(1,3) = 0.0000000000f; ref_img(2,3) = 0.1250000009f; ref_img(3,3) = 1.0000000075f; ref_img(4,3) = 0.1250000009f; ref_img(5,3) = 0.0000000000f;
+        ref_img(1,4) = 0.0533001795f; ref_img(2,4) = 0.2294157356f; ref_img(3,4) = 0.1250000009f; ref_img(4,4) = 0.2294157356f; ref_img(5,4) = 0.0533001795f;
+        ref_img(1,5) = 0.2294157356f; ref_img(2,5) = 0.0533001795f; ref_img(3,5) = 0.0000000000f; ref_img(4,5) = 0.0533001795f; ref_img(5,5) = 0.2294157356f;
+        
+        shouldEqualSequenceTolerance(result.begin(), result.end(), ref_img.begin(), test_epsilon);
+    }
+    
+    
+    void testMask3x5()
+    {
+        ImageType result(7,7), ref_img(7,7);
+        result = 0.0;
+        ref_img = 0.0;
+        
+        fastNormalizedCrossCorrelation(img,
+                                       mask.subarray(Shape2(1,0),Shape2(4,5)),
+                                       result);
+        
+        ref_img(1,2) = -0.2539664209f; ref_img(2,2) = -0.0834784210f; ref_img(3,2) = -0.1410190463f; ref_img(4,2) = -0.0834784210f; ref_img(5,2) = 0.0923513919f; 
+        ref_img(1,3) = -0.3225896060f; ref_img(2,3) = -0.2017366886f; ref_img(3,3) =  0.1494035274f; ref_img(4,3) =  0.2305561155f; ref_img(5,3) = 0.4218478799f;
+        ref_img(1,4) = -0.2539664209f; ref_img(2,4) = -0.0834784210f; ref_img(3,4) =  0.1611645669f; ref_img(4,4) =  0.5426095128f; ref_img(5,4) = 0.4386692047f; 
+        
+        shouldEqualSequenceTolerance(result.begin(), result.end(), ref_img.begin(), test_epsilon);
+    }
+    
+    
+    void testMask5x3()
+    {
+        ImageType result(7,7), ref_img(7,7);
+        result = 0.0;
+        ref_img = 0.0;
+        
+        fastNormalizedCrossCorrelation(img,
+                                       mask.subarray(Shape2(0,1),Shape2(5,4)),
+                                       result);
+        
+        ref_img(2,1) = -0.2539664209f; ref_img(3,1) = -0.3225896060f; ref_img(4,1) = -0.2539664209f; 
+        ref_img(2,2) = -0.0834784210f; ref_img(3,2) = -0.2017366886f; ref_img(4,2) = -0.0834784210f; 
+        ref_img(2,3) = -0.1410190463f; ref_img(3,3) =  0.1494035274f; ref_img(4,3) =  0.1611645669f;
+        ref_img(2,4) = -0.0834784210f; ref_img(3,4) =  0.2305561155f; ref_img(4,4) =  0.5426095128f;
+        ref_img(2,5) =  0.0923513919f; ref_img(3,5) =  0.4218478799f; ref_img(4,5) =  0.4386692047f;
+        
+        shouldEqualSequenceTolerance(result.begin(), result.end(), ref_img.begin(), test_epsilon);
+    }
+    
+    void testMask5x5()
+    {
+        ImageType result(7,7), ref_img(7,7);
+        result = 0.0;
+        ref_img = 0.0;
+        
+        fastNormalizedCrossCorrelation(img,
+                                       mask.subarray(Shape2(0,0),Shape2(5,5)),
+                                       result);
+        
+        
+        ref_img(2,2) = -0.0089172045f; ref_img(3,2) = -0.0510310352f; ref_img(4,2) = -0.0089172045f; 
+        ref_img(2,3) = -0.0510310352f; ref_img(3,3) =  0.2165063461f; ref_img(4,3) =  0.2041241407f;
+        ref_img(2,4) = -0.0089172045f; ref_img(3,4) =  0.2041241407f; ref_img(4,4) =  0.4369430199f;
+        
+        shouldEqualSequenceTolerance(result.begin(), result.end(), ref_img.begin(), test_epsilon);
+    }
+};
+
+
+struct FastNormalizedCrossCorrelationTestSuite
+: public test_suite
+{
+    FastNormalizedCrossCorrelationTestSuite()
+    : test_suite("FastNormalizedCrossCorrelationTestSuite")
+    {
+        
+        add( testCase( &FastVsSlowCorrelationTest::testCorrelation));
+        add( testCase( &FastVsSlowCorrelationTest::testNormalizedCorrelation));
+        
+        add( testCase( &FastNormalizedCrossCorrelationEssentialTest::testImagePatch));
+        add( testCase( &FastNormalizedCrossCorrelationEssentialTest::testRandomPatch));
+        
+        add( testCase( &FastNormalizedCrossCorrelationExactTest::testMask1x1));
+        add( testCase( &FastNormalizedCrossCorrelationExactTest::testMask3x3));
+        add( testCase( &FastNormalizedCrossCorrelationExactTest::testMask3x5));
+        add( testCase( &FastNormalizedCrossCorrelationExactTest::testMask5x3));
+        add( testCase( &FastNormalizedCrossCorrelationExactTest::testMask5x5));
+   }
+};
+
+
+struct CorrelationTestCollection
+: public test_suite
+{
+    CorrelationTestCollection()
+    : test_suite("CorrelationTestCollection")
+    {
+        add( new FastNormalizedCrossCorrelationTestSuite);
+   }
+};
+
+int main(int argc, char ** argv)
+{
+    CorrelationTestCollection test;
+ 
+    int failed = test.run(testsToBeExecuted(argc, argv));
+
+    std::cout << test.report() << std::endl;
+
+    return (failed != 0);
+}
+
diff --git a/test/counting_iterator/CMakeLists.txt b/test/counting_iterator/CMakeLists.txt
new file mode 100644
index 0000000..44f4c5c
--- /dev/null
+++ b/test/counting_iterator/CMakeLists.txt
@@ -0,0 +1 @@
+VIGRA_ADD_TEST(test_counting_iterator test.cxx)
diff --git a/test/counting_iterator/test.cxx b/test/counting_iterator/test.cxx
new file mode 100644
index 0000000..1ff3790
--- /dev/null
+++ b/test/counting_iterator/test.cxx
@@ -0,0 +1,281 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2004 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*                                                                      */
+/************************************************************************/
+
+#include <iostream>
+#include <numeric>
+#include "vigra/unittest.hxx"
+#include "vigra/counting_iterator.hxx"
+
+using namespace vigra;
+
+struct CountingIteratorTest
+{
+    void testCountingIterator()
+    {
+        {
+            auto iter1 = range(0,7,3);
+            auto iter2 = range(0,8,3);
+            auto iter3 = range(0,9,3);
+            auto iterEnd   = iter1.end();
+            shouldEqual( *iterEnd, 9);
+            should( iterEnd == iter2.end());
+            should( iterEnd == iter3.end());
+            shouldEqual( std::distance(iter1,iterEnd), 3);
+            shouldEqual( std::distance(iter2,iterEnd), 3);
+            shouldEqual( std::distance(iter3,iterEnd), 3);
+
+            for(int i=0; i<3; ++i){
+                shouldEqual( iter1[i], 3*i);
+                shouldEqual( iter2[i], 3*i);
+                shouldEqual( iter3[i], 3*i);
+                shouldEqual( iterEnd[-i], 9-3*i);
+            }
+
+            for(int i=0; i<6; ++i){
+
+                shouldEqual( std::distance(iter1,iterEnd), 3-i);
+                shouldEqual( std::distance(iter2,iterEnd), 3-i);
+                shouldEqual( std::distance(iter3,iterEnd), 3-i);
+
+                should(iter1 == iter2);
+                should(iter1 == iter3);
+                shouldNot(iter1 != iter2);
+                shouldNot(iter1 != iter3);
+
+                if(i != 3)
+                {
+                    should(iter1 != iterEnd);
+                    shouldNot(iter1 == iterEnd);
+                }
+                else
+                {
+                    shouldNot(iter1 != iterEnd);
+                    should(iter1 == iterEnd);
+                }
+                if(i < 3)
+                {
+                    should(iter1 < iterEnd);
+                    shouldNot(iter1 >= iterEnd);
+                    shouldNot(iter1.empty());
+                }
+                else
+                {
+                    shouldNot(iter1 < iterEnd);
+                    should(iter1 >= iterEnd);
+                    should(iter1.empty());
+                }
+                if(i < 4)
+                {
+                    should(iter1 <= iterEnd);
+                    shouldNot(iter1 > iterEnd);
+                }
+                else
+                {
+                    shouldNot(iter1 <= iterEnd);
+                    should(iter1 > iterEnd);
+                }
+
+                shouldEqual( *iter1, 3*i);
+                shouldEqual( *iter2, 3*i);
+                shouldEqual( *iter3, 3*i);
+
+                ++iter1;
+                iter2++;
+                iter3+=1;
+            }
+
+            iter1 = iterEnd;
+            --iter1;
+            shouldEqual( *iter1, 6);
+            iter1--;
+            shouldEqual( *iter1, 3);
+            iter1-=1;
+            shouldEqual( *iter1, 0);
+        }
+
+        {
+            auto iter1 = range(10, 1, -2);
+            auto iter2 = range(10, 0, -2);
+            auto iterEnd   = iter1.end();
+            shouldEqual( *iterEnd, 0);
+            should( iterEnd == iter2.end());
+            shouldEqual( std::distance(iter1,iterEnd), 5);
+            shouldEqual( std::distance(iter2,iterEnd), 5);
+
+            for(int i=0; i<5; ++i){
+                shouldEqual( iter1[i], 10-2*i);
+                shouldEqual( iter2[i], 10-2*i);
+                shouldEqual( iterEnd[-i], 2*i);
+            }
+
+            for(int i=0; i<5; ++i){
+
+                shouldEqual( std::distance(iter1,iterEnd), 5-i);
+                shouldEqual( std::distance(iter2,iterEnd), 5-i);
+
+                should(iter1!=iterEnd);
+                should(iter2!=iterEnd);
+
+                shouldEqual( *iter1, 10-2*i);
+                shouldEqual( *iter2, 10-2*i);
+
+                ++iter1;
+                iter2++;
+            }
+
+            should(iter1.empty());
+            should(iter1==iterEnd);
+            should(iter2.empty());
+            should(iter2==iterEnd);
+            --iter1;
+            shouldEqual( *iter1, 2);
+            iter1--;
+            shouldEqual( *iter1, 4);
+        }
+
+        int count = 0;
+        for(auto i: range(0, 19, 2))
+        {
+            shouldEqual( i, count);
+            count += 2;
+        }
+        shouldEqual(20, count);
+        for(auto i: range(20, 0, -2))
+        {
+            shouldEqual( i, count);
+            count -= 2;
+        }
+        shouldEqual(0, count);
+
+        {
+            auto iter = range(5),
+                 end  = iter.end();
+            shouldEqual(std::accumulate(iter, end, 0), 10);
+        }
+
+        {
+            double c = 1.0;
+            for(auto i: range(1.0, 1.6, 0.1)) // 1.6 is excluded
+            {
+                shouldEqualTolerance(c, i, 1e-15);
+                c += 0.1;
+            }
+            shouldEqualTolerance(c, 1.6, 1e-15);
+
+            c = 1.0;
+            for(auto i: range(1.0, 1.61, 0.1)) // 1.6 is included
+            {
+                shouldEqualTolerance(c, i, 1e-15);
+                c += 0.1;
+            }
+            shouldEqualTolerance(c, 1.7, 1e-15);
+
+            auto iter = range(1.0, 1.6, 0.1),
+                 end  = iter.end();
+            shouldEqual(end-iter, 6);
+            c = 1.0;
+            for(int i=0; i < 9; ++i, ++iter)
+            {
+                if(i != 6)
+                {
+                    should(iter != end);
+                    shouldNot(iter == end);
+                }
+                else
+                {
+                    should(iter == end);
+                    shouldNot(iter != end);
+                }
+                if(i < 6)
+                {
+                    should(iter < end);
+                    shouldNot(iter >= end);
+                    shouldNot(iter.empty());
+                }
+                else
+                {
+                    shouldNot(iter < end);
+                    should(iter >= end);
+                    should(iter.empty());
+                }
+                if(i < 7)
+                {
+                    should(iter <= end);
+                    shouldNot(iter > end);
+                }
+                else
+                {
+                    shouldNot(iter <= end);
+                    should(iter > end);
+                }
+                shouldEqualTolerance(*iter, c, 1e-15);
+                c += 0.1;
+            }
+            shouldEqualTolerance(c, 1.9, 1e-15);
+
+            c = 1.6;
+            iter = range(1.6, 1.0, -0.1);
+            end  = iter.end();
+            for(; iter <= end; ++iter)
+            {
+                shouldEqual(*iter, c);
+                c -= 0.1;
+            }
+            shouldEqualTolerance(c, 0.9, 1e-15);
+        }
+    }
+};
+ 
+struct CountingIteratorTestSuite
+: public vigra::test_suite
+{
+    CountingIteratorTestSuite()
+    : vigra::test_suite("CountingIteratorTestSuite")
+    {   
+        add( testCase( &CountingIteratorTest::testCountingIterator));
+    }
+};
+
+int main(int argc, char ** argv)
+{
+    CountingIteratorTestSuite test;
+
+    int failed = test.run(vigra::testsToBeExecuted(argc, argv));
+
+    std::cout << test.report() << std::endl;
+
+    return (failed != 0);
+}
+
diff --git a/test/delegates/CMakeLists.txt b/test/delegates/CMakeLists.txt
new file mode 100644
index 0000000..01b9f7b
--- /dev/null
+++ b/test/delegates/CMakeLists.txt
@@ -0,0 +1 @@
+VIGRA_ADD_TEST(test_delegates test.cxx)
diff --git a/include/vigra/memory.hxx b/test/delegates/test.cxx
similarity index 57%
copy from include/vigra/memory.hxx
copy to test/delegates/test.cxx
index 3d3b9fa..4e490e4 100644
--- a/include/vigra/memory.hxx
+++ b/test/delegates/test.cxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*         Copyright 2002-2003 by Ullrich Koethe, Hans Meine            */
+/*                 Copyright 2004 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,87 +33,108 @@
 /*                                                                      */
 /************************************************************************/
 
-#ifndef VIGRA_MEMORY_HXX
-#define VIGRA_MEMORY_HXX
+#include <iostream>
+#include "vigra/unittest.hxx"
+#include "vigra/delegate/delegate.hxx"
 
-#include "metaprogramming.hxx"
+using namespace vigra;
 
-namespace vigra { 
 
-enum SkipInitializationTag { SkipInitialization};
 
-template<class T>
-struct CanSkipInitialization
-{
-    typedef typename TypeTraits<T>::isBuiltinType type;
-    static const bool value = type::asBool;
-};
-
-namespace detail {
-
-// differs from std::uninitialized_copy by explicit type conversion
-template <class Src, class Dest>
-Dest uninitializedCopy(Src s, Src end, Dest d)
-{
-    typedef typename std::iterator_traits<Dest>::value_type T;
-    for(; s != end; ++s, ++d)
-        new(d) T(static_cast<T const &>(*s));
-    return d;
+int ff1(int a){
+    return a;
 }
 
-template <class T>
-inline void destroy_n(T * /* p */, std::ptrdiff_t /* n */, VigraTrueType /* isPOD */)
-{
-}
 
-template <class T>
-inline void destroy_n(T * p, std::ptrdiff_t n, VigraFalseType /* isPOD */)
-{
-    T * end = p + n;
-    for(; p != end; ++p)
-        p->~T();
-}
-
-template <class T>
-inline void destroy_n(T * p, std::ptrdiff_t n)
-{
-    destroy_n(p, n, typename TypeTraits<T>::isPOD());
+int ff2(int a,int b){
+    return a+b;
 }
 
-/********************************************************************/
 
-// g++ 2.95 has std::destroy() in the STL
-#if !defined(__GNUC__) ||  __GNUC__ >= 3
 
-template <class T>
-inline void destroy(T * p, VigraTrueType /* isPOD */)
-{
-}
 
-template <class T>
-inline void destroy(T * p, VigraFalseType /* isPOD */)
-{
-    p->~T();
-}
+struct DelegateTest{   
+    typedef  vigra::delegate1<int,int> D1;
+    typedef  vigra::delegate2<int,int,int> D2;
+
+
+    int mf1(int a){
+        return a;
+    }
+
+
+    int mf2(int a,int b){
+        return a+b;
+    }
+
+    int mf1(int a)const{
+        return a+1;
+    }
+
+
+    int mf2(int a,int b)const{
+        return a+b+1;
+    }
+
+    void test1(){
+        {
+        D1 d1(D1::from_method< DelegateTest,&DelegateTest::mf1 >(this));
+        shouldEqual(d1(2),2);
+        shouldEqual(d1(3),3);
+        }
+        {
+        D1 d1(D1::from_const_method< DelegateTest,&DelegateTest::mf1 >(this));
+        shouldEqual(d1(2),2+1);
+        shouldEqual(d1(3),3+1);
+        }
+        {
+        D1 d1(D1::from_function< &ff1 >());
+        shouldEqual(d1(2),2);
+        shouldEqual(d1(3),3);
+        }
+    }
+    void test2(){
+        {
+        D2 d2(D2::from_method< DelegateTest,&DelegateTest::mf2 >(this));
+        shouldEqual(d2(2,2),4);
+        shouldEqual(d2(3,2),5);
+        }
+        {
+        D2 d2(D2::from_const_method< DelegateTest,&DelegateTest::mf2 >(this));
+        shouldEqual(d2(2,2),4+1);
+        shouldEqual(d2(3,2),5+1);
+        }
+        {
+        D2 d2(D2::from_function< &ff2 >());
+        shouldEqual(d2(2,2),4);
+        shouldEqual(d2(3,2),5);
+        }
+    }
+};
 
-template <class T>
-inline void destroy(T * p)
-{
-    destroy(p, typename TypeTraits<T>::isPOD());
-}
 
-#else
 
-} } // namespace vigra::detail
 
-#include <memory>
+ 
+struct DelegatesTestSuite
+: public vigra::test_suite
+{
+    DelegatesTestSuite()
+    : vigra::test_suite("DelegatesTestSuite")
+    {   
+        add( testCase( &DelegateTest::test1));
+        add( testCase( &DelegateTest::test2));
+    }
+};
 
-namespace vigra { namespace detail {
+int main(int argc, char ** argv)
+{
+    DelegatesTestSuite test;
 
-using std::destroy;
+    int failed = test.run(vigra::testsToBeExecuted(argc, argv));
 
-#endif
+    std::cout << test.report() << std::endl;
 
-} } // namespace vigra::detail
+    return (failed != 0);
+}
 
-#endif // VIGRA_MEMORY_HXX
diff --git a/test/filters/CMakeLists.txt b/test/filters/CMakeLists.txt
new file mode 100644
index 0000000..83c99ee
--- /dev/null
+++ b/test/filters/CMakeLists.txt
@@ -0,0 +1 @@
+VIGRA_ADD_TEST(test_filters test.cxx)
\ No newline at end of file
diff --git a/test/filters/test.cxx b/test/filters/test.cxx
new file mode 100755
index 0000000..ea92eb1
--- /dev/null
+++ b/test/filters/test.cxx
@@ -0,0 +1,477 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2013 by Benjamin Seppke                    */      
+/*                                                                      */
+/************************************************************************/
+
+#include <iostream>
+#include <cstdio>
+
+#include "vigra/unittest.hxx"
+
+#include "vigra/stdimage.hxx"
+#include "vigra/impex.hxx"
+
+#include "vigra/medianfilter.hxx"
+#include "vigra/shockfilter.hxx"
+#include "vigra/specklefilters.hxx"
+
+using namespace vigra;
+
+template <class T>
+void printBasicImage(const BasicImage<T> & img)
+{    
+    for (int y=0; y<img.height(); ++y)
+    {
+        for (int x=0; x<img.width(); ++x)
+        {
+            std::printf("img(%d,%d) = %10.3f; ", x , y , img(x,y));
+        }      
+        std::printf("\n");  
+    }
+}
+
+
+struct MedianFilterEssentialTest
+{
+    FImage img;
+    Diff2D filterShape;
+    
+    MedianFilterEssentialTest()
+    : img(10,10),
+      filterShape(3,3)
+    {
+    }
+    
+    void testZeros()
+    {
+        img = 0;
+        FImage result(img.size());
+        
+        //testing all reflect modes, none should produce a difference for an
+        //image consisting only of zeros..
+        
+        //1. BORDER_TREATMENT_AVOID
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_AVOID);        
+        shouldEqualSequence(img.begin(),img.end(), result.begin());
+        
+        //2. BORDER_TREATMENT_REPEAT
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_REPEAT);        
+        shouldEqualSequence(img.begin(),img.end(), result.begin());
+        
+        //3. BORDER_TREATMENT_REFLECT
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_REFLECT);        
+        shouldEqualSequence(img.begin(),img.end(), result.begin());
+        
+        //4. BORDER_TREATMENT_WRAP
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_WRAP);        
+        shouldEqualSequence(img.begin(),img.end(), result.begin());
+    
+        //5. BORDER_TREATMENT_ZEROPAD
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_ZEROPAD);        
+        shouldEqualSequence(img.begin(),img.end(), result.begin());
+    }
+    
+    void testOnes()
+    {
+        float value=1;
+        img = value;
+        FImage result(img.size());
+                
+        //testing all reflect modes, none should produce a difference for an
+        //image consisting only of zeros..
+        
+        //1. BORDER_TREATMENT_AVOID
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_AVOID);        
+        border_zero_checker(result, value,false);
+        
+        //2. BORDER_TREATMENT_REPEAT
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_REPEAT);        
+        shouldEqualSequence(img.begin(),img.end(), result.begin());
+        
+        //3. BORDER_TREATMENT_REFLECT
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_REFLECT);        
+        shouldEqualSequence(img.begin(),img.end(), result.begin());
+        
+        //4. BORDER_TREATMENT_WRAP
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_WRAP);        
+        shouldEqualSequence(img.begin(),img.end(), result.begin());
+        
+        //5. BORDER_TREATMENT_ZEROPAD
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_ZEROPAD);  
+        border_zero_checker(result, value, true);
+    }
+    
+    
+    void border_zero_checker(const FImage & result, float value, bool corners_only=false)
+    {
+        for (int y=0; y!=result.height(); ++y)
+        {
+            bool top    = y==0, bottom = y==result.height()-1;
+            
+            for (int x=0; x!=result.width(); ++x)
+            {
+                bool left  = x==0, right = x==result.width()-1;
+                
+                //std::cerr << "(" << x << ", " << y << ") -> "<< result(x,y) << std::endl;
+                if (left || right || top || bottom)
+                {
+                    if (corners_only && (left || right) && (top || bottom))
+                    {
+                        shouldEqual(result(x,y), 0);                        
+                    }
+                    else if (!corners_only) 
+                    {
+                        shouldEqual(result(x,y), 0);
+                    }
+                }
+                else
+                {
+                    shouldEqual(result(x,y), value);
+                }
+            }
+        }
+    }
+    
+};
+
+
+struct MedianFilterExactTest
+{
+    FImage img;
+    FImage ref_img;
+    Diff2D filterShape;
+    
+    MedianFilterExactTest()
+    : img(5,5),
+      ref_img(5,5),
+      filterShape(3,3)
+    {
+        img(0,0) = 1; img(0,1) = 2; img(0,2) = 3; img(0,3) = 2; img(0,4) = 1; 
+        img(1,0) = 2; img(1,1) = 3; img(1,2) = 4; img(1,3) = 3; img(1,4) = 2; 
+        img(2,0) = 3; img(2,1) = 4; img(2,2) = 5; img(2,3) = 4; img(2,4) = 3; 
+        img(3,0) = 2; img(3,1) = 3; img(3,2) = 4; img(3,3) = 3; img(3,4) = 2; 
+        img(4,0) = 1; img(4,1) = 2; img(4,2) = 3; img(4,3) = 2; img(4,4) = 1; 
+    }
+    
+    void testAVOID()
+    {
+        FImage result(img.size());
+        
+        ref_img(0,0) =      0.000; ref_img(1,0) =      0.000; ref_img(2,0) =      0.000; ref_img(3,0) =      0.000; ref_img(4,0) =      0.000; 
+        ref_img(0,1) =      0.000; ref_img(1,1) =      3.000; ref_img(2,1) =      3.000; ref_img(3,1) =      3.000; ref_img(4,1) =      0.000; 
+        ref_img(0,2) =      0.000; ref_img(1,2) =      3.000; ref_img(2,2) =      4.000; ref_img(3,2) =      3.000; ref_img(4,2) =      0.000; 
+        ref_img(0,3) =      0.000; ref_img(1,3) =      3.000; ref_img(2,3) =      3.000; ref_img(3,3) =      3.000; ref_img(4,3) =      0.000; 
+        ref_img(0,4) =      0.000; ref_img(1,4) =      0.000; ref_img(2,4) =      0.000; ref_img(3,4) =      0.000; ref_img(4,4) =      0.000; 
+        
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_AVOID);        
+        shouldEqualSequence(result.begin(), result.end(), ref_img.begin());
+    }
+    
+    void testREPEAT()
+    {
+        FImage result(img.size());
+        
+        ref_img(0,0) =      2.000; ref_img(1,0) =      2.000; ref_img(2,0) =      3.000; ref_img(3,0) =      2.000; ref_img(4,0) =      2.000; 
+        ref_img(0,1) =      2.000; ref_img(1,1) =      3.000; ref_img(2,1) =      3.000; ref_img(3,1) =      3.000; ref_img(4,1) =      2.000; 
+        ref_img(0,2) =      3.000; ref_img(1,2) =      3.000; ref_img(2,2) =      4.000; ref_img(3,2) =      3.000; ref_img(4,2) =      3.000; 
+        ref_img(0,3) =      2.000; ref_img(1,3) =      3.000; ref_img(2,3) =      3.000; ref_img(3,3) =      3.000; ref_img(4,3) =      2.000; 
+        ref_img(0,4) =      2.000; ref_img(1,4) =      2.000; ref_img(2,4) =      3.000; ref_img(3,4) =      2.000; ref_img(4,4) =      2.000; 
+    
+        
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_REPEAT);        
+        shouldEqualSequence(result.begin(), result.end(), ref_img.begin());
+    }
+    
+    void testREFLECT()
+    {
+        FImage result(img.size());
+        
+        ref_img(0,0) =      2.000; ref_img(1,0) =      2.000; ref_img(2,0) =      3.000; ref_img(3,0) =      2.000; ref_img(4,0) =      2.000; 
+        ref_img(0,1) =      2.000; ref_img(1,1) =      3.000; ref_img(2,1) =      3.000; ref_img(3,1) =      3.000; ref_img(4,1) =      2.000; 
+        ref_img(0,2) =      3.000; ref_img(1,2) =      3.000; ref_img(2,2) =      4.000; ref_img(3,2) =      3.000; ref_img(4,2) =      3.000; 
+        ref_img(0,3) =      2.000; ref_img(1,3) =      3.000; ref_img(2,3) =      3.000; ref_img(3,3) =      3.000; ref_img(4,3) =      2.000; 
+        ref_img(0,4) =      2.000; ref_img(1,4) =      2.000; ref_img(2,4) =      3.000; ref_img(3,4) =      2.000; ref_img(4,4) =      2.000; 
+        
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_REFLECT);    
+        shouldEqualSequence(result.begin(), result.end(), ref_img.begin());
+    }
+    void testWRAP()
+    {
+        FImage result(img.size());
+        
+        ref_img(0,0) =      2.000; ref_img(1,0) =      2.000; ref_img(2,0) =      3.000; ref_img(3,0) =      2.000; ref_img(4,0) =      2.000; 
+        ref_img(0,1) =      2.000; ref_img(1,1) =      3.000; ref_img(2,1) =      3.000; ref_img(3,1) =      3.000; ref_img(4,1) =      2.000; 
+        ref_img(0,2) =      3.000; ref_img(1,2) =      3.000; ref_img(2,2) =      4.000; ref_img(3,2) =      3.000; ref_img(4,2) =      3.000; 
+        ref_img(0,3) =      2.000; ref_img(1,3) =      3.000; ref_img(2,3) =      3.000; ref_img(3,3) =      3.000; ref_img(4,3) =      2.000; 
+        ref_img(0,4) =      2.000; ref_img(1,4) =      2.000; ref_img(2,4) =      3.000; ref_img(3,4) =      2.000; ref_img(4,4) =      2.000; 
+        
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_WRAP);        
+        shouldEqualSequence(result.begin(), result.end(), ref_img.begin());
+    }
+    void testZEROPAD()
+    {
+        FImage result(img.size());
+        
+        ref_img(0,0) =      0.000; ref_img(1,0) =      2.000; ref_img(2,0) =      2.000; ref_img(3,0) =      2.000; ref_img(4,0) =      0.000; 
+        ref_img(0,1) =      2.000; ref_img(1,1) =      3.000; ref_img(2,1) =      3.000; ref_img(3,1) =      3.000; ref_img(4,1) =      2.000; 
+        ref_img(0,2) =      2.000; ref_img(1,2) =      3.000; ref_img(2,2) =      4.000; ref_img(3,2) =      3.000; ref_img(4,2) =      2.000; 
+        ref_img(0,3) =      2.000; ref_img(1,3) =      3.000; ref_img(2,3) =      3.000; ref_img(3,3) =      3.000; ref_img(4,3) =      2.000; 
+        ref_img(0,4) =      0.000; ref_img(1,4) =      2.000; ref_img(2,4) =      2.000; ref_img(3,4) =      2.000; ref_img(4,4) =      0.000; 
+        
+        medianFilter(srcImageRange(img), destImage(result), filterShape, BORDER_TREATMENT_ZEROPAD);   
+        shouldEqualSequence(result.begin(), result.end(), ref_img.begin());
+    }
+    
+};
+
+struct MedianFilterTestSuite
+: public vigra::test_suite
+{
+    MedianFilterTestSuite()
+    : vigra::test_suite("MedianFilterTestSuite")
+    {
+        add( testCase( &MedianFilterEssentialTest::testZeros));
+        add( testCase( &MedianFilterEssentialTest::testOnes));
+        add( testCase( &MedianFilterExactTest::testAVOID));
+        add( testCase( &MedianFilterExactTest::testREPEAT));
+        add( testCase( &MedianFilterExactTest::testREFLECT));
+        add( testCase( &MedianFilterExactTest::testWRAP));
+        add( testCase( &MedianFilterExactTest::testZEROPAD));
+   }
+};
+
+
+struct ShockFilterTest
+{
+    FImage img;
+    
+    ShockFilterTest()
+    : img(100,100)
+    {
+    }
+    
+    void test()
+    {
+        img = 0;
+        FImage result(img.size());
+        
+        float sigma = 0.7f;
+        float rho   = 3.0f;
+        float upwind_factor_h = 0.3f;
+        unsigned int iterations = 10;
+        
+        //Just test, if it's running with properly set parameters
+        shockFilter(srcImageRange(img), destImage(result), sigma, rho, upwind_factor_h, iterations);
+    }
+};
+
+
+struct ShockFilterTestSuite
+: public vigra::test_suite
+{
+    ShockFilterTestSuite()
+    : vigra::test_suite("ShockFilterTestSuite")
+    {
+        add( testCase( &ShockFilterTest::test));
+    }
+};
+
+
+struct SpeckleFilterTest
+{
+    FImage img;
+    Diff2D filterShape;
+    
+    SpeckleFilterTest()
+    : img(100,100),
+      filterShape(3,3)
+    {
+    }
+    
+    void testFrostFilter()
+    {
+        img = 0;
+        FImage result(img.size());
+        
+        float k = 0.7f;
+        
+        //Just test, if it's running with properly set parameters
+        //1. BORDER_TREATMENT_AVOID
+        frostFilter(srcImageRange(img), destImage(result), filterShape, k, BORDER_TREATMENT_AVOID);
+        
+        //2. BORDER_TREATMENT_REPEAT
+        frostFilter(srcImageRange(img), destImage(result), filterShape, k, BORDER_TREATMENT_REPEAT);
+        
+        //3. BORDER_TREATMENT_REFLECT
+        frostFilter(srcImageRange(img), destImage(result), filterShape, k, BORDER_TREATMENT_REFLECT);
+        
+        //4. BORDER_TREATMENT_WRAP
+        frostFilter(srcImageRange(img), destImage(result), filterShape, k, BORDER_TREATMENT_WRAP);
+        
+        //5. BORDER_TREATMENT_ZEROPAD
+        frostFilter(srcImageRange(img), destImage(result), filterShape, k, BORDER_TREATMENT_ZEROPAD);
+    }
+    void testEnhancedFrostFilter()
+    {
+        img = 0;
+        FImage result(img.size());
+        
+        float k = 0.5;
+        unsigned int enl = 10;
+        
+        //Just test, if it's running with properly set parameters
+        //1. BORDER_TREATMENT_AVOID
+        enhancedFrostFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_AVOID);
+        
+        //2. BORDER_TREATMENT_REPEAT
+        enhancedFrostFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_REPEAT);
+        
+        //3. BORDER_TREATMENT_REFLECT
+        enhancedFrostFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_REFLECT);
+        
+        //4. BORDER_TREATMENT_WRAP
+        enhancedFrostFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_WRAP);
+        
+        //5. BORDER_TREATMENT_ZEROPAD
+        enhancedFrostFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_ZEROPAD);
+    }
+    
+    void testGammaMAPFilter()
+    {
+        img = 0;
+        FImage result(img.size());
+        
+        unsigned int enl = 10;
+        
+        //Just test, if it's running with properly set parameters
+        //1. BORDER_TREATMENT_AVOID
+        gammaMAPFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_AVOID);
+        
+        //2. BORDER_TREATMENT_REPEAT
+        gammaMAPFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_REPEAT);
+        
+        //3. BORDER_TREATMENT_REFLECT
+        gammaMAPFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_REFLECT);
+        
+        //4. BORDER_TREATMENT_WRAP
+        gammaMAPFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_WRAP);
+        
+        //5. BORDER_TREATMENT_ZEROPAD
+        gammaMAPFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_ZEROPAD);
+    }
+    
+    
+    void testKuanFilter()
+    {
+        img = 0;
+        FImage result(img.size());
+        
+        unsigned int enl = 10;
+        
+        //Just test, if it's running with properly set parameters
+        //1. BORDER_TREATMENT_AVOID
+        kuanFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_AVOID);
+        
+        //2. BORDER_TREATMENT_REPEAT
+        kuanFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_REPEAT);
+        
+        //3. BORDER_TREATMENT_REFLECT
+        kuanFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_REFLECT);
+        
+        //4. BORDER_TREATMENT_WRAP
+        kuanFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_WRAP);
+        
+        //5. BORDER_TREATMENT_ZEROPAD
+        kuanFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_ZEROPAD);
+    }
+    
+    void testLeeFilter()
+    {
+        img = 0;
+        FImage result(img.size());
+        
+        unsigned int enl = 10;
+        
+        //Just test, if it's running with properly set parameters
+        //1. BORDER_TREATMENT_AVOID
+        leeFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_AVOID);
+        
+        //2. BORDER_TREATMENT_REPEAT
+        leeFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_REPEAT);
+        
+        //3. BORDER_TREATMENT_REFLECT
+        leeFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_REFLECT);
+        
+        //4. BORDER_TREATMENT_WRAP
+        leeFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_WRAP);
+        
+        //5. BORDER_TREATMENT_ZEROPAD
+        leeFilter(srcImageRange(img), destImage(result), filterShape, enl, BORDER_TREATMENT_ZEROPAD);
+    }
+    
+    void testEnhancedLeeFilter()
+    {
+        img = 0;
+        FImage result(img.size());
+        
+        float k = 0.5;
+        unsigned int enl = 10;
+        
+        //Just test, if it's running with properly set parameters
+        //1. BORDER_TREATMENT_AVOID
+        enhancedLeeFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_AVOID);
+        
+        //2. BORDER_TREATMENT_REPEAT
+        enhancedLeeFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_REPEAT);
+        
+        //3. BORDER_TREATMENT_REFLECT
+        enhancedLeeFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_REFLECT);
+        
+        //4. BORDER_TREATMENT_WRAP
+        enhancedLeeFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_WRAP);
+        
+        //5. BORDER_TREATMENT_ZEROPAD
+        enhancedLeeFilter(srcImageRange(img), destImage(result), filterShape, k, enl, BORDER_TREATMENT_ZEROPAD);
+    }
+};
+
+
+struct SpeckleFilterTestSuite
+: public vigra::test_suite
+{
+    SpeckleFilterTestSuite()
+    : vigra::test_suite("SpeckleFilterTestSuite")
+    {
+        add( testCase( &SpeckleFilterTest::testFrostFilter));
+        add( testCase( &SpeckleFilterTest::testEnhancedFrostFilter));
+        add( testCase( &SpeckleFilterTest::testGammaMAPFilter));
+        add( testCase( &SpeckleFilterTest::testKuanFilter));
+        add( testCase( &SpeckleFilterTest::testLeeFilter));
+        add( testCase( &SpeckleFilterTest::testEnhancedLeeFilter));
+    }
+};
+
+struct FilterTestCollection
+: public vigra::test_suite
+{
+    FilterTestCollection()
+    : vigra::test_suite("FilterTestCollection")
+    {
+        add( new MedianFilterTestSuite);
+        add( new ShockFilterTestSuite);
+        add( new SpeckleFilterTestSuite);
+   }
+};
+
+int main(int argc, char ** argv)
+{
+    FilterTestCollection test;
+ 
+    int failed = test.run(vigra::testsToBeExecuted(argc, argv));
+
+    std::cout << test.report() << std::endl;
+
+    return (failed != 0);
+}
+
diff --git a/test/fourier/CMakeLists.txt b/test/fourier/CMakeLists.txt
index 3857311..115a0a7 100644
--- a/test/fourier/CMakeLists.txt
+++ b/test/fourier/CMakeLists.txt
@@ -1,7 +1,9 @@
 if(FFTW3_FOUND)
     INCLUDE_DIRECTORIES(${FFTW3_INCLUDE_DIR})
 
-    VIGRA_ADD_TEST(test_fourier test.cxx LIBRARIES vigraimpex ${FFTW3_LIBRARIES})
+    VIGRA_CONFIGURE_THREADING()
+      
+    VIGRA_ADD_TEST(test_fourier test.cxx LIBRARIES vigraimpex ${FFTW3_LIBRARIES} ${THREADING_LIBRARIES})
 
     VIGRA_COPY_TEST_DATA(ghouse.gif filter.xv gaborresult.xv)
 else()
diff --git a/test/graph_algorithm/CMakeLists.txt b/test/graph_algorithm/CMakeLists.txt
new file mode 100644
index 0000000..2297279
--- /dev/null
+++ b/test/graph_algorithm/CMakeLists.txt
@@ -0,0 +1 @@
+VIGRA_ADD_TEST(test_graph_algorithm test.cxx)
\ No newline at end of file
diff --git a/test/graph_algorithm/test.cxx b/test/graph_algorithm/test.cxx
new file mode 100644
index 0000000..ba62de3
--- /dev/null
+++ b/test/graph_algorithm/test.cxx
@@ -0,0 +1,575 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2004 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*                                                                      */
+/************************************************************************/
+
+#include <iostream>
+#include "vigra/unittest.hxx"
+#include "vigra/stdimage.hxx"
+#include "vigra/multi_array.hxx"
+#include "vigra/adjacency_list_graph.hxx"
+#include "vigra/graph_algorithms.hxx"
+#include "vigra/multi_resize.hxx"
+
+using namespace vigra;
+
+struct GraphAlgorithmTest{
+
+
+    typedef vigra::AdjacencyListGraph            GraphType;
+    typedef GraphType::Node                      Node;
+    typedef GraphType::Edge                      Edge;
+    typedef GraphType::Arc                       Arc;
+    typedef GraphType::EdgeIt                    EdgeIt;
+    typedef GraphType::NodeIt                    NodeIt;
+    typedef GraphType::ArcIt                     ArcIt;
+    typedef GraphType::IncEdgeIt                 IncEdgeIt;
+    typedef GraphType::InArcIt                   InArcIt;
+    typedef GraphType::OutArcIt                  OutArcIt;
+    typedef GraphType::NeighborNodeIt            NeighborNodeIt;
+
+    GraphAlgorithmTest(){       
+
+    }
+
+
+    void testShortestPathGridGraph2()
+    {
+        typedef GridGraph<2, boost_graph::undirected_tag> GridGraph2d;
+        typedef TinyVector< MultiArrayIndex, 2> Shape2;
+        typedef GridGraph2d::EdgeMap<float> EdgeMap;
+
+        GridGraph2d gridGraph(Shape2(3,3),DirectNeighborhood);
+
+        EdgeMap edgeMap(gridGraph);
+
+        for(GridGraph2d::EdgeIt ei(gridGraph); ei!=lemon::INVALID; ++ei ){
+            edgeMap[*ei] = 1.0;
+        }
+
+        typedef ShortestPathDijkstra<GridGraph2d,float> Sp;
+        typedef Sp::PredecessorsMap PredMap;
+        typedef Sp::DistanceMap     DistMap;
+
+        Sp pf(gridGraph);
+
+        Shape2 n00(0,0);
+
+        pf.run(edgeMap,n00);
+
+        const DistMap & dmap  = pf.distances();
+        const PredMap & pmap  = pf.predecessors();
+
+        // check the length and the path 
+        shouldEqual( pathLength(Shape2(0,0), Shape2(0,0),pmap) , 1);
+        shouldEqual( pathLength(Shape2(0,0), Shape2(0,1),pmap) , 2);
+        shouldEqual( pathLength(Shape2(0,0), Shape2(0,2),pmap) , 3);
+        shouldEqual( pathLength(Shape2(0,0), Shape2(1,0),pmap) , 2);
+        shouldEqual( pathLength(Shape2(0,0), Shape2(2,0),pmap) , 3);
+
+        shouldEqual( pathLength(Shape2(0,0), Shape2(1,1),pmap) , 3);
+        shouldEqual( pathLength(Shape2(0,0), Shape2(1,2),pmap) , 4);
+        shouldEqual( pathLength(Shape2(0,0), Shape2(2,1),pmap) , 4);
+        shouldEqual( pathLength(Shape2(0,0), Shape2(2,2),pmap) , 5);
+
+
+
+        shouldEqualTolerance(dmap[Shape2(0,0)],0.0f , 0.00001);
+        shouldEqualTolerance(dmap[Shape2(0,1)],1.0f , 0.00001);
+        shouldEqualTolerance(dmap[Shape2(0,2)],2.0f , 0.00001);
+        shouldEqualTolerance(dmap[Shape2(1,0)],1.0f , 0.00001);
+        shouldEqualTolerance(dmap[Shape2(1,1)],2.0f , 0.00001);
+        shouldEqualTolerance(dmap[Shape2(1,2)],3.0f , 0.00001);
+        shouldEqualTolerance(dmap[Shape2(2,0)],2.0f , 0.00001);
+        shouldEqualTolerance(dmap[Shape2(2,1)],3.0f , 0.00001);
+        shouldEqualTolerance(dmap[Shape2(2,2)],4.0f , 0.00001);
+
+
+        should(pmap[Shape2(0,0)] == Shape2(0,0));
+        should(pmap[Shape2(1,0)] == Shape2(0,0));
+        should(pmap[Shape2(2,0)] == Shape2(1,0));
+
+        should(pmap[Shape2(2,1)] == Shape2(2,0) || pmap[Shape2(2,1)] == Shape2(1,1));
+        should(pmap[Shape2(1,2)] == Shape2(0,2) || pmap[Shape2(2,1)] == Shape2(1,1));
+
+        should(pmap[Shape2(0,0)] == Shape2(0,0));
+        should(pmap[Shape2(0,1)] == Shape2(0,0));
+        should(pmap[Shape2(0,2)] == Shape2(0,1));
+
+        should(pmap[Shape2(1,1)] == Shape2(0,1) || pmap[Shape2(1,1)] == Shape2(1,0) );
+        should(pmap[Shape2(2,2)] == Shape2(2,1) || pmap[Shape2(2,2)] == Shape2(1,2) );
+
+        //shouldEqual(pmap[Shape2(1,1)], );
+        //shouldEqual(pmap[Shape2(1,2)], );
+        //shouldEqual(pmap[Shape2(2,0)], );
+        //shouldEqual(pmap[Shape2(2,1)], );
+        //shouldEqual(pmap[Shape2(2,2)], );
+
+
+    }
+
+    template <class Graph>
+    void testShortestPathImpl(Graph const & g)
+    {
+        typedef ShortestPathDijkstra<Graph,float> Sp;
+        typedef typename Sp::PredecessorsMap PredMap;
+        typedef typename Sp::DistanceMap     DistMap;
+        typedef typename Graph::Node Node;
+        typedef typename Graph::Edge Edge;
+
+        //   1 | 2
+        //   _   _ 
+        //   3 | 4 
+        
+        typename Graph::NodeIt node(g);
+        const Node n1=*node++;
+        const Node n2=*node++;
+        const Node n3=*node++;
+        const Node n4=*node;
+        const Edge e12= g.findEdge(n1,n2);
+        const Edge e13= g.findEdge(n1,n3);
+        const Edge e24= g.findEdge(n2,n4);
+        const Edge e34= g.findEdge(n3,n4);
+
+        typename Graph::template EdgeMap<float> ew(g);
+        ew[e12]=10.0;
+        ew[e13]=2.0;
+        ew[e24]=3.0;
+        ew[e34]=4.0;
+        {
+            Sp pf(g);
+            pf.run(ew,n1,n2);
+
+            should(pf.source() == n1);
+            should(pf.target() == n2);
+
+            const PredMap & pmap = pf.predecessors();
+            const DistMap & dmap = pf.distances();
+
+            should(pmap[n2]==n4);
+            should(pmap[n4]==n3);
+            should(pmap[n3]==n1);
+            should(pmap[n1]==n1);
+
+            shouldEqual(pf.discoveryOrder().size(), 4);
+            shouldEqual(pf.discoveryOrder()[0], n1);
+            shouldEqual(pf.discoveryOrder()[1], n3);
+            shouldEqual(pf.discoveryOrder()[2], n4);
+            shouldEqual(pf.discoveryOrder()[3], n2);
+
+            shouldEqualTolerance(dmap[n1],0.0f , 0.00001);
+            shouldEqualTolerance(dmap[n3],2.0f , 0.00001);
+            shouldEqualTolerance(dmap[n4],6.0f , 0.00001);
+            shouldEqualTolerance(dmap[n2],9.0f , 0.00001);
+
+            pf.run(ew,n1,n2, 8.0f);
+
+            should(pf.source() == n1);
+            should(pf.target() == lemon::INVALID);
+
+            shouldEqual(pf.discoveryOrder().size(), 3);
+            shouldEqual(pf.discoveryOrder()[0], n1);
+            shouldEqual(pf.discoveryOrder()[1], n3);
+            shouldEqual(pf.discoveryOrder()[2], n4);
+        }
+        {
+            Sp pf(g);
+            pf.run(ew,n1);
+
+            const PredMap & pmap = pf.predecessors();
+            const DistMap & dmap = pf.distances();
+
+            should(pf.source() == n1);
+            should(pf.target() == n2);
+
+            should(pmap[n2]==n4);
+            should(pmap[n4]==n3);
+            should(pmap[n3]==n1);
+            should(pmap[n1]==n1);
+
+            shouldEqual(pf.discoveryOrder().size(), 4);
+            shouldEqual(pf.discoveryOrder()[0], n1);
+            shouldEqual(pf.discoveryOrder()[1], n3);
+            shouldEqual(pf.discoveryOrder()[2], n4);
+            shouldEqual(pf.discoveryOrder()[3], n2);
+
+            shouldEqualTolerance(dmap[n1],0.0f , 0.00001);
+            shouldEqualTolerance(dmap[n3],2.0f , 0.00001);
+            shouldEqualTolerance(dmap[n4],6.0f , 0.00001);
+            shouldEqualTolerance(dmap[n2],9.0f , 0.00001);
+
+            pf.run(ew,n1, lemon::INVALID, 8.0f);
+
+            should(pf.source() == n1);
+            should(pf.target() == n4); // n2 is now unreachable within maxDistance = 8.0
+
+            should(pmap[n2]==lemon::INVALID);
+            should(pmap[n4]==n3);
+            should(pmap[n3]==n1);
+            should(pmap[n1]==n1);
+
+            shouldEqual(pf.discoveryOrder().size(), 3);
+            shouldEqual(pf.discoveryOrder()[0], n1);
+            shouldEqual(pf.discoveryOrder()[1], n3);
+            shouldEqual(pf.discoveryOrder()[2], n4);
+        }
+    }
+
+    template <class Graph>
+    void testShortestPathWithROIImpl(Graph const & g)
+    {
+        typedef ShortestPathDijkstra<Graph,float> Sp;
+        typedef typename Sp::PredecessorsMap PredMap;
+        typedef typename Sp::DistanceMap     DistMap;
+        typedef typename Graph::Node Node;
+        typedef typename Graph::Edge Edge;
+
+        //   1 | 2
+        //   _   _ 
+        //   3 | 4 
+        
+        typename Graph::NodeIt node(g);
+        const Node n1=*node++;
+        const Node n2=*node++;
+        const Node n3=*node++;
+        const Node n4=*node;
+        const Edge e12= g.findEdge(n1,n2);
+        const Edge e13= g.findEdge(n1,n3);
+        const Edge e24= g.findEdge(n2,n4);
+        const Edge e34= g.findEdge(n3,n4);
+
+        typename Graph::template EdgeMap<float> ew(g);
+        ew[e12]=10.0;
+        ew[e13]=2.0;
+        ew[e24]=3.0;
+        ew[e34]=4.0;
+        {
+            Sp pf(g);
+
+            // ROI = entire graph
+            pf.run(Node(0), g.shape(), ew, n1, n2);
+
+            should(pf.source() == n1);
+            should(pf.target() == n2);
+
+            const PredMap & pmap = pf.predecessors();
+            const DistMap & dmap = pf.distances();
+
+            should(pmap[n2]==n4);
+            should(pmap[n4]==n3);
+            should(pmap[n3]==n1);
+            should(pmap[n1]==n1);
+
+            shouldEqual(pf.discoveryOrder().size(), 4);
+            shouldEqual(pf.discoveryOrder()[0], n1);
+            shouldEqual(pf.discoveryOrder()[1], n3);
+            shouldEqual(pf.discoveryOrder()[2], n4);
+            shouldEqual(pf.discoveryOrder()[3], n2);
+
+            shouldEqualTolerance(dmap[n1],0.0f , 0.00001);
+            shouldEqualTolerance(dmap[n3],2.0f , 0.00001);
+            shouldEqualTolerance(dmap[n4],6.0f , 0.00001);
+            shouldEqualTolerance(dmap[n2],9.0f , 0.00001);
+
+            // ROI = top half
+            pf.run(n1, n2+Node(1), ew, n1, n2);
+
+            should(pf.source() == n1);
+            should(pf.target() == n2);
+
+            should(pmap[n2]==n1);
+            should(pmap[n1]==n1);
+
+            shouldEqual(pf.discoveryOrder().size(), 2);
+            shouldEqual(pf.discoveryOrder()[0], n1);
+            shouldEqual(pf.discoveryOrder()[1], n2);
+
+            shouldEqualTolerance(dmap[n1],0.0f , 0.00001);
+            shouldEqualTolerance(dmap[n2],10.0f , 0.00001);
+
+            // ROI = top half, maxWeight less then weight of e12
+            pf.run(n1, n2+Node(1), ew, n1, n2, 8.0f);
+
+            should(pf.source() == n1);
+            should(pf.target() == lemon::INVALID);
+
+            shouldEqual(pf.discoveryOrder().size(), 1);
+            shouldEqual(pf.discoveryOrder()[0], n1);
+        }
+        {
+            Sp pf(g);
+            // ROI = bottom half
+            pf.run(n3, g.shape(), ew, n4, n3);
+
+            should(pf.source() == n4);
+            should(pf.target() == n3);
+
+            const PredMap & pmap = pf.predecessors();
+            const DistMap & dmap = pf.distances();
+
+            should(pmap[n3]==n4);
+            should(pmap[n4]==n4);
+
+            shouldEqual(pf.discoveryOrder().size(), 2);
+            shouldEqual(pf.discoveryOrder()[0], n4);
+            shouldEqual(pf.discoveryOrder()[1], n3);
+
+            shouldEqualTolerance(dmap[n4],0.0f , 0.00001);
+            shouldEqualTolerance(dmap[n3],4.0f , 0.00001);
+
+            // ROI = bottom half, maxWeight less then weight of e34
+            pf.run(n3, g.shape(), ew, n4, n3, 2.0);
+
+            should(pf.source() == n4);
+            should(pf.target() == lemon::INVALID);
+
+            shouldEqual(pf.discoveryOrder().size(), 1);
+            shouldEqual(pf.discoveryOrder()[0], n4);
+        }
+    }
+
+    void testShortestPathAdjacencyListGraph()
+    {
+        GraphType g(0,0);
+        const Node n1=g.addNode(1);
+        const Node n2=g.addNode(2);
+        const Node n3=g.addNode(3);
+        const Node n4=g.addNode(4);
+        g.addEdge(n1,n2);
+        g.addEdge(n1,n3);
+        g.addEdge(n2,n4);
+        g.addEdge(n3,n4);
+
+        testShortestPathImpl(g);
+    }
+
+    void testShortestPathGridGraph()
+    {
+        GridGraph<2> g(Shape2(2,2), DirectNeighborhood);
+
+        testShortestPathImpl(g);
+        testShortestPathWithROIImpl(g);
+    }
+
+    void testRegionAdjacencyGraph(){
+        {
+            GraphType g(0,0);
+            const Node n1=g.addNode(1);
+            const Node n2=g.addNode(2);
+            const Node n3=g.addNode(3);
+            const Node n4=g.addNode(4);
+            const Node n5=g.addNode(5);
+            const Edge e12= g.addEdge(n1,n2);
+            g.addEdge(n1,n3);
+            g.addEdge(n2,n4);
+            const Edge e34= g.addEdge(n3,n4);
+            const Edge e45= g.addEdge(n4,n5);
+
+            //   1 | 2
+            //   _   _ 
+            //   3 | 4 | 5 
+
+            //labeling
+            //   1 | 7
+            //   _   _ 
+            //   1 | 7 | 3 
+
+            GraphType::NodeMap<int> labels(g);
+            labels[n1]=1;
+            labels[n2]=7;
+            labels[n3]=1;
+            labels[n4]=7;
+            labels[n5]=3;
+
+            GraphType rag;
+            GraphType::EdgeMap< std::vector<Edge> > affEdges;
+
+            makeRegionAdjacencyGraph(g,labels,rag,affEdges);
+
+            shouldEqual(rag.nodeNum(),3);
+            shouldEqual(rag.edgeNum(),2);
+
+            const Node rn1 = rag.nodeFromId(1);
+            const Node rn7 = rag.nodeFromId(7);
+            const Node rn3 = rag.nodeFromId(3);
+
+            should(rag.nodeFromId(0)==lemon::INVALID);
+            should(rag.nodeFromId(2)==lemon::INVALID);
+            should(rag.nodeFromId(4)==lemon::INVALID);
+            should(rag.nodeFromId(5)==lemon::INVALID);
+            should(rag.nodeFromId(6)==lemon::INVALID);
+            should(rag.nodeFromId(8)==lemon::INVALID);
+
+            should(rn1!=lemon::INVALID);
+            should(rn7!=lemon::INVALID);
+            should(rn3!=lemon::INVALID);
+
+            const Edge re17 = rag.findEdge(rn1,rn7);
+            const Edge re73 = rag.findEdge(rn7,rn3);
+
+            should(re17!=lemon::INVALID);
+            should(re73!=lemon::INVALID);
+
+            should(rag.findEdge(rn1,rn3)==lemon::INVALID);
+
+
+            shouldEqual(affEdges[re17].size(),2);
+            shouldEqual(affEdges[re73].size(),1);
+
+            should(affEdges[re73][0]==e45);
+            should(affEdges[re17][0]==e12 || affEdges[re17][1]==e12 );
+            should(affEdges[re17][0]==e34 || affEdges[re17][1]==e34 );
+        }   
+    }
+
+
+    void testEdgeSort(){
+        {
+            GraphType g(0,0);
+            const Node n1=g.addNode(1);
+            const Node n2=g.addNode(2);
+            const Node n3=g.addNode(3);
+            const Node n4=g.addNode(4);
+            const Node n5=g.addNode(5);
+            const Edge e12= g.addEdge(n1,n2);
+            const Edge e13= g.addEdge(n1,n3);
+            const Edge e24= g.addEdge(n2,n4);
+            const Edge e34= g.addEdge(n3,n4);
+            const Edge e45= g.addEdge(n4,n5);
+
+            //   1 | 2
+            //   _   _ 
+            //   3 | 4 | 5 
+
+            GraphType::EdgeMap<float> ew(g);
+
+            ew[e12]=2.0;
+            ew[e13]=1.0;
+            ew[e24]=5.0;
+            ew[e34]=4.0;
+            ew[e45]=3.0;
+
+
+            std::vector<Edge> edgeVec;
+
+            std::less<float> l;
+            edgeSort(g,ew,l,edgeVec);
+
+            shouldEqual(edgeVec.size(),g.edgeNum());
+            should(edgeVec[0]==e13);
+            should(edgeVec[1]==e12);
+            should(edgeVec[2]==e45);
+            should(edgeVec[3]==e34);
+            should(edgeVec[4]==e24);
+
+
+            std::greater<float> gr;
+            edgeSort(g,ew,gr,edgeVec);
+
+            shouldEqual(edgeVec.size(),g.edgeNum());
+            should(edgeVec[4]==e13);
+            should(edgeVec[3]==e12);
+            should(edgeVec[2]==e45);
+            should(edgeVec[1]==e34);
+            should(edgeVec[0]==e24);
+
+        }
+    }
+
+    void testEdgeWeightComputation()
+    {
+        MultiArray<2, double> nodeMap(Shape2(3,2), LinearSequence);
+        MultiArray<2, double> interpolated(Shape2(5,3));
+        resizeImageLinearInterpolation(nodeMap, interpolated);
+
+        GridGraph<2> g(nodeMap.shape(), IndirectNeighborhood);
+        GridGraph<2>::EdgeMap<double> edgeMap1(g), edgeMap2(g);
+
+        edgeWeightsFromNodeWeights(g, nodeMap, edgeMap1);
+        edgeWeightsFromInterpolatedImage(g, interpolated, edgeMap2);
+
+        shouldEqual(edgeMap1.shape(), Shape3(3,2,4));
+
+        double ref[] = {
+            0.0, 0.0, 0.0, 0.0, 2.0, 3.0,
+            0.0, 0.0, 0.0, 1.5, 2.5, 3.5,
+            0.0, 0.0, 0.0, 2.0, 3.0, 0.0,
+            0.0, 0.5, 1.5, 0.0, 3.5, 4.5
+        };
+
+        shouldEqualSequence(edgeMap1.begin(), edgeMap1.end(), ref);
+        shouldEqualSequence(edgeMap2.begin(), edgeMap2.end(), ref);
+
+        edgeWeightsFromNodeWeights(g, nodeMap, edgeMap1, true);
+        edgeWeightsFromInterpolatedImage(g, interpolated, edgeMap2, true);
+
+        double ref2[] = {
+            0.0, 0.0, 0.0, 0.0, 2.0*M_SQRT2, 3.0*M_SQRT2,
+            0.0, 0.0, 0.0, 1.5, 2.5, 3.5,
+            0.0, 0.0, 0.0, 2.0*M_SQRT2, 3.0*M_SQRT2, 0.0,
+            0.0, 0.5, 1.5, 0.0, 3.5, 4.5
+        };
+
+        shouldEqualSequence(edgeMap1.begin(), edgeMap1.end(), ref2);
+        shouldEqualSequence(edgeMap2.begin(), edgeMap2.end(), ref2);
+    }
+};
+
+
+ 
+struct GraphAlgorithmTestSuite
+: public vigra::test_suite
+{
+    GraphAlgorithmTestSuite()
+    : vigra::test_suite("GraphAlgorithmTestSuite")
+    {   
+        add( testCase( &GraphAlgorithmTest::testShortestPathAdjacencyListGraph));
+        add( testCase( &GraphAlgorithmTest::testShortestPathGridGraph));
+        add( testCase( &GraphAlgorithmTest::testRegionAdjacencyGraph));
+        add( testCase( &GraphAlgorithmTest::testEdgeSort));
+        add( testCase( &GraphAlgorithmTest::testEdgeWeightComputation));
+        add( testCase( &GraphAlgorithmTest::testShortestPathGridGraph2));
+    }
+};
+
+int main(int argc, char ** argv)
+{
+    GraphAlgorithmTestSuite test;
+
+    int failed = test.run(vigra::testsToBeExecuted(argc, argv));
+
+    std::cout << test.report() << std::endl;
+
+    return (failed != 0);
+}
+
diff --git a/test/gridgraph/test.cxx b/test/gridgraph/test.cxx
index fb7cd49..5162e19 100644
--- a/test/gridgraph/test.cxx
+++ b/test/gridgraph/test.cxx
@@ -549,7 +549,7 @@ struct GridGraphTests
     template <class DirectedTag, NeighborhoodType NType>
     void testBasics()
     {
-        using namespace boost;
+        using namespace boost_graph;
         typedef GridGraph<N, DirectedTag> G;
         
         static const bool directed = IsSameType<DirectedTag, directed_tag>::value;
@@ -594,7 +594,7 @@ struct GridGraphTests
     template <class DirectedTag, NeighborhoodType NType>
     void testVertexIterator()
     {
-        using namespace boost;
+        using namespace boost_graph;
         
         typedef GridGraph<N, DirectedTag> Graph;
 
@@ -636,8 +636,8 @@ struct GridGraphTests
                 shouldEqual(g.forward_degree(j) + g.back_degree(j), g.out_degree(j));
                 shouldEqual(g.in_degree(j), g.out_degree(j));
                 shouldEqual(g.degree(j), g.isDirected() ? 2*g.out_degree(j) : g.out_degree(j));
-                shouldEqual(g.out_degree(j), boost::out_degree(*j, g));
-                shouldEqual(g.in_degree(j), boost::in_degree(*j, g));
+                shouldEqual(g.out_degree(j), boost_graph::out_degree(*j, g));
+                shouldEqual(g.in_degree(j), boost_graph::in_degree(*j, g));
                 shouldEqual(g.out_degree(j), outDegreeMap[*j]);
                 shouldEqual(g.in_degree(j), inDegreeMap[*j]);
 
@@ -663,7 +663,7 @@ struct GridGraphTests
     template <class DirectedTag, NeighborhoodType NType>
     void testNeighborIterator()
     {
-        using namespace boost;
+        using namespace boost_graph;
         
         static const bool directed = IsSameType<DirectedTag, directed_tag>::value;
         
@@ -682,6 +682,8 @@ struct GridGraphTests
             
             typename Graph::template ArcMap<int> arcIdMap(g);            
             typename Graph::template EdgeMap<int> edgeIdMap(g);            
+            ArrayVector<unsigned char> arcExistsMap(g.maxArcId()+1, 0);
+            ArrayVector<unsigned char> edgeExistsMap(g.maxEdgeId()+1, 0);
 
             linearSequence(arcIdMap.begin(), arcIdMap.end());
             linearSequence(edgeIdMap.begin(), edgeIdMap.end());
@@ -691,7 +693,7 @@ struct GridGraphTests
             shouldEqual((arcIdMap.shape().template subarray<0, N>()), s);
             shouldEqual(arcIdMap.shape(N), g.maxDegree());
             shouldEqual(edgeMap.shape(), edgeIdMap.shape());
-            
+
             int totalCount = 0;
         
             typename Graph::vertex_iterator j = g.get_vertex_iterator(), 
@@ -795,9 +797,15 @@ struct GridGraphTests
                     shouldEqual(g.oppositeNode(v, *le), u);
                     shouldEqual(g.oppositeNode(lemon::INVALID, *le), Node(lemon::INVALID));
                     
-                    shouldEqual(arcIdMap[*la], g.id(la));
+                    MultiArrayIndex arcId = g.id(*la);
+                    shouldEqual(arcIdMap[*la], arcId);
+                    arcExistsMap[arcId] = 1;  // mark arc as found
+
+                    MultiArrayIndex edgeId = g.id(*le);
                     shouldEqual(edgeIdMap[*la], g.id((typename Graph::Edge &)*la));
                     shouldEqual(edgeIdMap[*le], g.id(*le));
+                    edgeExistsMap[edgeId] = 1;  // mark edge as found
+
                     shouldEqual(*la, g.arcFromId(g.id(*la)));
                     shouldEqual(*le, g.edgeFromId(g.id(*le)));
                 }
@@ -839,13 +847,31 @@ struct GridGraphTests
                 else
                     shouldEqual(edgeMap.bindInner(*j).template sum<int>(), 2*g.back_degree(j));
             }
+
+            for(int id=0; id <= g.maxEdgeId(); ++id)
+            {
+                typename Graph::Edge e = g.edgeFromId(id);
+                if(edgeExistsMap[id])
+                    should(e != lemon::INVALID);
+                else
+                    should(e == lemon::INVALID);
+            }
+
+            for(int id=0; id <= g.maxArcId(); ++id)
+            {
+                typename Graph::Arc a = g.arcFromId(id);
+                if(arcExistsMap[id])
+                    should(a != lemon::INVALID);
+                else
+                    should(a == lemon::INVALID);
+            }
         }
     }
     
     template <class DirectedTag, NeighborhoodType NType>
     void testBackNeighborIterator()
     {
-        using namespace boost;
+        using namespace boost_graph;
         
         static const bool directed = IsSameType<DirectedTag, directed_tag>::value;
         
@@ -997,7 +1023,7 @@ struct GridGraphTests
     template <class DirectedTag, NeighborhoodType NType>
     void testEdgeIterator()
     {
-        using namespace boost;
+        using namespace boost_graph;
         
         static const bool directed = IsSameType<DirectedTag, directed_tag>::value;
         
@@ -1082,7 +1108,7 @@ struct GridGraphTests
     template <class DirectedTag, NeighborhoodType NType>
     void testArcIterator()
     {
-        using namespace boost;
+        using namespace boost_graph;
         
         static const bool directed = IsSameType<DirectedTag, directed_tag>::value;
         
diff --git a/test/hdf5impex/test.cxx b/test/hdf5impex/test.cxx
index c324e5c..629eda5 100644
--- a/test/hdf5impex/test.cxx
+++ b/test/hdf5impex/test.cxx
@@ -37,6 +37,7 @@
 #include <cmath>
 #include <cstdlib>
 #include <cstring>
+#include <set>
 #include "vigra/stdimage.hxx"
 #include "vigra/unittest.hxx"
 #include "vigra/hdf5impex.hxx"
@@ -404,6 +405,7 @@ public:
 
         //create a file
         HDF5File file (file_name, HDF5File::New);
+        shouldEqual(file.file_use_count(), 1);
 
         //write one dataset in each group level
         file.write("/dataset",out_data_1);
@@ -413,10 +415,32 @@ public:
         file.mkdir("subgroup1");
         file.write("subgroup1/dataset",out_data_3);
         file.cd("..");
-        file.write("/dataset_rgb",out_data_4);
-        file.write("/atomicint", (int)-42);
-        file.write("/atomicuint", (unsigned int)42);
-        file.write("/atomicdouble", (double)3.1);
+
+        // continue writing on a copies of the file
+        HDF5File file_copy(file);
+        shouldEqual(file.file_use_count(), 2);
+        shouldEqual(file_copy.file_use_count(), 2);
+
+        file_copy.write("/dataset_rgb",out_data_4);
+        file_copy.write("/atomicint", (int)-42);
+
+        HDF5File file_copy2;
+        shouldEqual(file_copy2.file_use_count(), 0);
+        file_copy2 = file_copy;
+        shouldEqual(file.file_use_count(), 3);
+        shouldEqual(file_copy.file_use_count(), 3);
+        shouldEqual(file_copy2.file_use_count(), 3);
+
+        file_copy2.write("/atomicuint", (unsigned int)42);
+        file_copy2.write("/atomicdouble", (double)3.1);
+        file_copy2.close();
+        shouldEqual(file.file_use_count(), 2);
+        shouldEqual(file_copy.file_use_count(), 2);
+        shouldEqual(file_copy2.file_use_count(), 0);
+
+        file_copy.close();
+        shouldEqual(file.file_use_count(), 1);
+        shouldEqual(file_copy.file_use_count(), 0);
 
         //create a new dataset
         MultiArrayShape<3>::type shape (50,50,50);
@@ -710,6 +734,10 @@ public:
         file.writeAttribute("/string/dataset","tinyvector attribute", out_attr_3);
         file.writeAttribute("/string/dataset","rgb attribute", out_attr_4);
 
+        std::vector<std::string> attr = file.listAttributes("/double/dataset");
+        shouldEqual(attr.size(), 2);
+        shouldEqual(attr[0], "int attribute");
+        shouldEqual(attr[1], "string attribute");
 
         // read attributes
         MultiArray<2,int> in_attr_1(MultiArrayShape<2>::type(2,3));
@@ -752,6 +780,24 @@ public:
         file.writeAttribute("attrset","set_string",std::string("abc").c_str());
         file.writeAttribute("attrset","set_string2",std::string("abcdef"));
 
+        std::set<std::string> many_attr;
+        file.listAttributes("attrset", many_attr);
+        shouldEqual(many_attr.size(), 14);
+        should(many_attr.find("set_char") != many_attr.end());
+        should(many_attr.find("set_int8") != many_attr.end());
+        should(many_attr.find("set_int16") != many_attr.end());
+        should(many_attr.find("set_int32") != many_attr.end());
+        should(many_attr.find("set_int64") != many_attr.end());
+        should(many_attr.find("set_uint8") != many_attr.end());
+        should(many_attr.find("set_uint16") != many_attr.end());
+        should(many_attr.find("set_uint32") != many_attr.end());
+        should(many_attr.find("set_uint64") != many_attr.end());
+        should(many_attr.find("set_float") != many_attr.end());
+        should(many_attr.find("set_double") != many_attr.end());
+        should(many_attr.find("set_longdouble") != many_attr.end());
+        should(many_attr.find("set_string") != many_attr.end());
+        should(many_attr.find("set_string2") != many_attr.end());
+
         char read_char = 0;
         file.readAttribute("attrset","set_char",read_char);
         should(read_char=='A');
diff --git a/test/impex/CMakeLists.txt b/test/impex/CMakeLists.txt
index a879d78..45ccfbe 100644
--- a/test/impex/CMakeLists.txt
+++ b/test/impex/CMakeLists.txt
@@ -17,5 +17,5 @@ ENDIF(OPENEXR_FOUND)
 
 VIGRA_ADD_TEST(test_impex test.cxx LIBRARIES vigraimpex)
 
-VIGRA_COPY_TEST_DATA(lenna.xv lenna_gifref.xv lennafloat.xv lennafloatrgb.xv lennargb.xv no-image.txt lenna_0.tif lenna_1.tif lenna_2.tif lenna_masked_color.tif  lenna_masked_gray.tif)
+VIGRA_COPY_TEST_DATA(lenna.xv lenna_gifref.xv lennafloat.xv lennafloatrgb.xv lennargb.xv no-image.txt lenna_0.tif lenna_1.tif lenna_2.tif lenna_masked_color.tif  lenna_masked_gray.tif bilevel.tiff)
 
diff --git a/test/impex/bilevel.tiff b/test/impex/bilevel.tiff
new file mode 100644
index 0000000..2db1f69
Binary files /dev/null and b/test/impex/bilevel.tiff differ
diff --git a/test/impex/test.cxx b/test/impex/test.cxx
index 2e70fb9..c4d8b92 100755
--- a/test/impex/test.cxx
+++ b/test/impex/test.cxx
@@ -254,6 +254,17 @@ public:
         TIFFClose(tiff);
 
         shouldEqualSequence(res2.begin(), res2.end(), img.data());
+        
+        // test bilevel
+        MultiArray<2, unsigned char> bilevel;
+        importImage("bilevel.tiff", bilevel);
+        shouldEqual(bilevel.shape(), Shape2(1577, 1083));
+        UInt8 m, M;
+        bilevel.minmax(&m, &M);
+        shouldEqual(m, 0);
+        shouldEqual(M, 1);
+        shouldEqual(bilevel.sum<int>(), 1653050); // 96% white pixels
+        
 #endif
     }
 
@@ -665,6 +676,58 @@ class CanvasSizeTest
     }
 };
 
+class PositionTest
+{
+  public:
+    void testFile(const char* filename)
+    {
+        ImageExportInfo exportinfo(filename);
+        FRGBImage img(1, 1);
+        img(0, 0) = 1;
+
+        const Diff2D position(0, 100);
+        exportinfo.setPosition(position);
+        exportinfo.setXResolution(1.0);
+        exportinfo.setYResolution(1.0);
+
+        exportImage(srcImageRange(img), exportinfo);
+
+        ImageImportInfo info(filename);
+
+        should (info.getPosition() == position);
+    }
+
+    void testEXRPosition()
+    {
+#if !defined(HasEXR)
+        FRGBImage img(1, 1);
+        failCodec(img, vigra::ImageExportInfo("res.exr"));
+#else
+        testFile("res.exr");
+#endif
+    }
+
+    void testTIFFPosition()
+    {
+#if !defined(HasTIFF)
+        FRGBImage img(1, 1);
+        failCodec(img, vigra::ImageExportInfo("res.tif"));
+#else
+        testFile("res.tif");
+#endif
+    }
+
+    void testPNGPosition()
+    {
+#if !defined(HasPNG)
+        FRGBImage img(1, 1);
+        failCodec(img, vigra::ImageExportInfo("res.png"));
+#else
+        testFile("res.png");
+#endif
+    }
+};
+
 class PNGInt16Test
 {
   public:
@@ -1792,6 +1855,10 @@ struct ImageImportExportTestSuite : public vigra::test_suite
 
         add(testCase(&CanvasSizeTest::testTIFFCanvasSize));
 
+        add(testCase(&PositionTest::testEXRPosition));
+        add(testCase(&PositionTest::testTIFFPosition));
+        add(testCase(&PositionTest::testPNGPosition));
+
         // grayscale float images
         add(testCase(&FloatImageExportImportTest::testGIF));
         add(testCase(&FloatImageExportImportTest::testJPEG));
diff --git a/test/integral_image/CMakeLists.txt b/test/integral_image/CMakeLists.txt
new file mode 100644
index 0000000..dc8eca5
--- /dev/null
+++ b/test/integral_image/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+VIGRA_ADD_TEST(test_integral_image test.cxx LIBRARIES vigraimpex)
diff --git a/test/integral_image/test.cxx b/test/integral_image/test.cxx
new file mode 100644
index 0000000..4733989
--- /dev/null
+++ b/test/integral_image/test.cxx
@@ -0,0 +1,255 @@
+/************************************************************************/
+/*                                                                      */
+/*    Copyright 2012-2013 by Ullrich Koethe and Anna Kreshuk            */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#include <iostream>
+#include <functional>
+#include <cmath>
+#include <stdlib.h>
+#include <time.h>
+
+#include "vigra/unittest.hxx"
+
+#include <vigra/integral_image.hxx>
+
+using namespace vigra;
+
+struct IntegralImageTest
+{
+    typedef MultiArray<2, int>                  Image2;
+    typedef MultiArray<2, TinyVector<int, 2> >  Vector2Image2;
+    typedef MultiArray<3, int>                  Image3;
+    typedef MultiArray<4, int>                  Image4;
+
+    void test_2d()
+    {        
+        int desired[] = {
+            2,  4,  6,  8,
+            4,  8, 12, 16,
+            6, 12, 18, 24,
+            
+            2,  4,  6,  8,
+            4,  8, 12, 16,
+            6, 12, 18, 24
+        };
+        
+        {
+            Image2 in(Shape2(4,3), 2);
+            Image2 result(in.shape());
+            
+            integralMultiArray(in, result);
+            shouldEqualSequence(result.begin(), result.end(), desired);
+        }
+        
+        {
+            Image3 in(Shape3(4,3,2), 2);
+            Image3 result(in.shape());
+            
+            integralMultiArray(in.multiband(), result.multiband());
+            shouldEqualSequence(result.begin(), result.end(), desired);
+        }
+        
+        {
+            Image2 in(Shape2(4,3), 2);
+            Image2 result(in.shape());
+            Image2 desired_squared(in.shape(), desired);
+            desired_squared *= 2;
+            
+            integralMultiArraySquared(in, result);
+            shouldEqualSequence(result.begin(), result.end(), desired_squared.begin());
+        }
+        
+        {
+            Image3 in(Shape3(4,3,2), 2);
+            Image3 result(in.shape());
+            Image3 desired_squared(in.shape(), desired);
+            desired_squared *= 2;
+            
+            integralMultiArraySquared(in.multiband(), result.multiband());
+            shouldEqualSequence(result.begin(), result.end(), desired_squared.begin());
+        }
+    }
+
+    void test_3d()
+    {
+        int desired[] = { 
+             2,  4,  6,
+             4,  8, 12,
+             6, 12, 18,
+             
+             4,  8, 12,
+             8, 16, 24,
+            12, 24, 36,
+             
+             6, 12, 18,
+            12, 24, 36,
+            18, 36, 54,
+            
+             2,  4,  6,
+             4,  8, 12,
+             6, 12, 18,
+             
+             4,  8, 12,
+             8, 16, 24,
+            12, 24, 36,
+             
+             6, 12, 18,
+            12, 24, 36,
+            18, 36, 54
+        };
+        
+        {
+            Image3 in(Shape3(3), 2);
+            Image3 result(in.shape());
+            
+            integralMultiArray(in, result);        
+            shouldEqualSequence(result.begin(), result.end(), desired);
+        }
+        
+        {
+            Image4 in(Shape4(3,3,3,2), 2);
+            Image4 result(in.shape());
+            
+            integralMultiArray(in.multiband(), result.multiband());        
+            shouldEqualSequence(result.begin(), result.end(), desired);
+        }
+        
+        {
+            Image3 in(Shape3(3), 2);
+            Image3 result(in.shape());
+            Image3 desired_squared(in.shape(), desired);
+            desired_squared *= 2;
+                        
+            integralMultiArraySquared(in, result);        
+            shouldEqualSequence(result.begin(), result.end(), desired_squared.begin());
+        }
+        
+        {
+            Image4 in(Shape4(3,3,3,2), 2);
+            Image4 result(in.shape());
+            Image4 desired_squared(in.shape(), desired);
+            desired_squared *= 2;
+            
+            integralMultiArraySquared(in.multiband(), result.multiband());        
+            shouldEqualSequence(result.begin(), result.end(), desired_squared.begin());
+        }
+    }
+
+    void test_4d()
+    {
+        int desired[] = { 
+             2,  4,  6,
+             4,  8, 12,
+             6, 12, 18,
+             
+             4,  8, 12,
+             8, 16, 24,
+            12, 24, 36,
+             
+             6, 12, 18,
+            12, 24, 36,
+            18, 36, 54,
+            
+             4,  8, 12,
+             8, 16, 24,
+            12, 24, 36,
+             
+             8, 16, 24,
+            16, 32, 48,
+            24, 48, 72,
+             
+            12, 24, 36,
+            24, 48, 72,
+            36, 72,108
+        };
+        
+        {
+            Image4 in(Shape4(3,3,3,2), 2);
+            Image4 result(in.shape());
+            
+            integralMultiArray(in, result);        
+            shouldEqualSequence(result.begin(), result.end(), desired);
+        }
+    }
+
+    void test_vector()
+    {        
+        int desired[] = {
+            2,  4,  6,  8,
+            4,  8, 12, 16,
+            6, 12, 18, 24,
+            
+            2,  4,  6,  8,
+            4,  8, 12, 16,
+            6, 12, 18, 24
+        };
+        
+        {
+            Vector2Image2 in(Shape2(4,3), TinyVector<int, 2>(2));
+            Vector2Image2 result(in.shape());
+            
+            integralMultiArray(in, result);
+            for(int c=0; c<2; ++c)
+            {
+                MultiArrayView <2, int> band = result.bindElementChannel(c);
+                shouldEqualSequence(band.begin(), band.end(), desired);
+            }
+        }
+    }
+};
+
+
+struct IntegralImageTestSuite
+: public test_suite
+{
+    IntegralImageTestSuite()
+    : test_suite("IntegralImageTestSuite")
+    {
+        add( testCase( &IntegralImageTest::test_2d));
+        add( testCase( &IntegralImageTest::test_3d));
+        add( testCase( &IntegralImageTest::test_4d));
+        add( testCase( &IntegralImageTest::test_vector));
+    }
+};
+
+int main(int argc, char ** argv)
+{
+    IntegralImageTestSuite test;
+
+    int failed = test.run(testsToBeExecuted(argc, argv));
+
+    std::cout << test.report() << std::endl;
+    return (failed != 0);
+}
+
diff --git a/test/math/test.cxx b/test/math/test.cxx
index 0bd76ca..dcb17b4 100755
--- a/test/math/test.cxx
+++ b/test/math/test.cxx
@@ -8,8 +8,6 @@
 /*    Please direct questions, bug reports, and contributions to        */
 /*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
 /*        vigra at informatik.uni-hamburg.de                               */
-/*                                                                      */
-/*    Permission is hereby granted, free of charge, to any person       */
 /*    obtaining a copy of this software and associated documentation    */
 /*    files (the "Software"), to deal in the Software without           */
 /*    restriction, including without limitation the rights to use,      */
@@ -60,16 +58,19 @@
 #include "vigra/regression.hxx"
 #include "vigra/random.hxx"
 #include "vigra/tinyvector.hxx"
-#include "vigra/polygon.hxx"
 #include "vigra/quaternion.hxx"
 #include "vigra/clebsch-gordan.hxx"
 #include "vigra/bessel.hxx"
 #include "vigra/timing.hxx"
-#include "convex_hull_test.hxx"
 
 #define VIGRA_TOLERANCE_MESSAGE "If this test fails, please adjust the tolerance threshold and report\n" \
                        "your findings (including compiler information etc.) to the VIGRA mailing list:"
 
+
+#define NegativeShift(i, s)\
+(vigra::Int32)((vigra::UInt32) i << s)
+
+
 static double coefficients[][12] =
 {
     { 5.0, -416.0, 720.0, -464.0, 136.0, -18.0, 1.0 },
@@ -542,18 +543,34 @@ struct FunctionsTest
     {
         double a = 0.0, b = vigra::NumericTraits<double>::epsilon(), c = 1000.0, d = 1000.1;
 
-        using vigra::closeAtTolerance;
+        using namespace vigra;
         should(closeAtTolerance(a, b));
         should(closeAtTolerance(c, c + b));
-        should(closeAtTolerance(c, d, 1.0));
+        should(!closeAtTolerance(c, d));
+        should(closeAtTolerance(c, d, 0.01));
         should(closeAtTolerance(-a, -b));
         should(closeAtTolerance(-c, -c + b));
-        should(closeAtTolerance(-c, -d, 1.0));
+        should(!closeAtTolerance(-c, -d));
+        should(closeAtTolerance(-c, -d, 0.01));
         should(!closeAtTolerance(c, -c));
         should(!closeAtTolerance(a, c));
         should(!closeAtTolerance(c, d));
         should(!closeAtTolerance(-a, -c));
         should(!closeAtTolerance(-c, -d));
+
+        should(lessEqualAtTolerance(a, c));
+        should(lessEqualAtTolerance(c, c));
+        should(lessEqualAtTolerance(c, c-b));
+        should(lessEqualAtTolerance(c, d));
+        should(!lessEqualAtTolerance(d, c));
+        should(lessEqualAtTolerance(d, c, 0.01));
+
+        should(greaterEqualAtTolerance(c, a));
+        should(greaterEqualAtTolerance(c, c));
+        should(greaterEqualAtTolerance(c-b, c));
+        should(greaterEqualAtTolerance(d, c));
+        should(!greaterEqualAtTolerance(c, d));
+        should(greaterEqualAtTolerance(c, d, 0.01));
     }
 
     void testArgMinMax()
@@ -1285,8 +1302,8 @@ struct FixedPointTest
         shouldEqual(-vigra::fixedPoint(3).value, -3);
 
         shouldEqual((vigra::FixedPoint<3,4>(3).value), 3 << 4);
-        shouldEqual((vigra::FixedPoint<3,4>(-3).value), -3 << 4);
-        shouldEqual((-vigra::FixedPoint<3,4>(3).value), -3 << 4);
+        shouldEqual((vigra::FixedPoint<3,4>(-3).value), NegativeShift(-3, 4));
+        shouldEqual((-vigra::FixedPoint<3,4>(3).value), NegativeShift(-3, 4));
 
         shouldEqual((vigra::FixedPoint<3,4>(3.5).value), 56);
         shouldEqual((vigra::FixedPoint<3,4>(-3.5).value), -56);
@@ -1305,8 +1322,8 @@ struct FixedPointTest
         shouldEqual((vigra::FixedPoint<2, 2>(v).value), 15);
         shouldEqual((vigra::FixedPoint<2, 0>(v).value), 4);
 
-        shouldEqual((vigra::FixedPoint<2, 8>(-v).value), -15 << 6);
-        shouldEqual((vigra::FixedPoint<3, 10>(-v).value), -15 << 8);
+        shouldEqual((vigra::FixedPoint<2, 8>(-v).value), NegativeShift(-15, 6));
+        shouldEqual((vigra::FixedPoint<3, 10>(-v).value), NegativeShift(-15, 8));
         shouldEqual((vigra::FixedPoint<2, 2>(-v).value), -15);
         shouldEqual((vigra::FixedPoint<2, 0>(-v).value), -4);
 
@@ -1328,7 +1345,7 @@ struct FixedPointTest
 
         vigra::FixedPoint<3, 10> v1;
         shouldEqual((v1 = v).value, 15 << 8);
-        shouldEqual((v1 = -v).value, -15 << 8);
+        shouldEqual((v1 = -v).value, NegativeShift(-15, 8));
 
         vigra::FixedPoint<2, 0> v2;
         shouldEqual((v2 = v).value, 4);
@@ -1386,10 +1403,10 @@ struct FixedPointTest
 
         shouldEqual((t1 * vigra::fixedPoint(v1)).value, 3 << 14);
         shouldEqual((t2 * vigra::fixedPoint(v1)).value, 1 << 14);
-        shouldEqual((-t1 * vigra::fixedPoint(v1)).value, -3 << 14);
-        shouldEqual((-t2 * vigra::fixedPoint(v1)).value, -1 << 14);
-        shouldEqual((t1 * -vigra::fixedPoint(v1)).value, -3 << 14);
-        shouldEqual((t2 * -vigra::fixedPoint(v1)).value, -1 << 14);
+        shouldEqual((-t1 * vigra::fixedPoint(v1)).value, NegativeShift(-3, 14));
+        shouldEqual((-t2 * vigra::fixedPoint(v1)).value, NegativeShift(-1, 14));
+        shouldEqual((t1 * -vigra::fixedPoint(v1)).value, NegativeShift(-3, 14));
+        shouldEqual((t2 * -vigra::fixedPoint(v1)).value, NegativeShift(-1, 14));
 
         shouldEqual((vigra::FixedPoint<8, 2>(t1 * vigra::fixedPoint(v1))).value, 3);
         shouldEqual((vigra::FixedPoint<8, 2>(t2 * vigra::fixedPoint(v1))).value, 1);
@@ -1439,8 +1456,8 @@ struct FixedPoint16Test
     void testConstruction()
     {
         shouldEqual((vigra::FixedPoint16<3>(3).value), 3 << 12);
-        shouldEqual((vigra::FixedPoint16<3>(-3).value), -3 << 12);
-        shouldEqual((-vigra::FixedPoint16<3>(3).value), -3 << 12);
+        shouldEqual((vigra::FixedPoint16<3>(-3).value), NegativeShift(-3, 12));
+        shouldEqual((-vigra::FixedPoint16<3>(3).value), NegativeShift(-3, 12));
 
         shouldEqual((vigra::FixedPoint16<8>(3).value), 3 << 7);
 
@@ -1462,14 +1479,14 @@ struct FixedPoint16Test
 
         vigra::FixedPoint16<4> v(3.75);
         shouldEqual((v.value), 15 << 9);
-        shouldEqual(((-v).value), -15 << 9);
+        shouldEqual(((-v).value), NegativeShift(-15, 9));
         shouldEqual((vigra::FixedPoint16<4>(v).value), 15 << 9);
         shouldEqual((vigra::FixedPoint16<6>(v).value), 15 << 7);
         shouldEqual((vigra::FixedPoint16<13>(v).value), 15);
         shouldEqual((vigra::FixedPoint16<15>(v).value), 4);
 
-        shouldEqual((vigra::FixedPoint16<4>(-v).value), -15 << 9);
-        shouldEqual((vigra::FixedPoint16<6>(-v).value), -15 << 7);
+        shouldEqual((vigra::FixedPoint16<4>(-v).value), NegativeShift(-15, 9));
+        shouldEqual((vigra::FixedPoint16<6>(-v).value), NegativeShift(-15, 7));
         shouldEqual((vigra::FixedPoint16<13>(-v).value), -15);
         shouldEqual((vigra::FixedPoint16<15>(-v).value), -4);
 
@@ -1492,7 +1509,7 @@ struct FixedPoint16Test
 
         vigra::FixedPoint16<2> v1;
         shouldEqual((v1 = v).value, 15 << 11);
-        shouldEqual((v1 = -v).value, -15 << 11);
+        shouldEqual((v1 = -v).value, NegativeShift(-15, 11));
 
         vigra::FixedPoint16<15> v2;
         shouldEqual((v2 = v).value, 4);
@@ -1570,10 +1587,10 @@ struct FixedPoint16Test
 
         shouldEqual((t1 * FP7(v1)).value, 3 << 6);
         shouldEqual((t2 * FP7(v1)).value, 1 << 6);
-        shouldEqual((-t1 * FP7(v1)).value, -3 << 6);
-        shouldEqual((-t2 * FP7(v1)).value, -1 << 6);
-        shouldEqual((t1 * -FP7(v1)).value, -3 << 6);
-        shouldEqual((t2 * -FP7(v1)).value, -1 << 6);
+        shouldEqual((-t1 * FP7(v1)).value, NegativeShift(-3, 6));
+        shouldEqual((-t2 * FP7(v1)).value, NegativeShift(-1, 6));
+        shouldEqual((t1 * -FP7(v1)).value, NegativeShift(-3, 6));
+        shouldEqual((t2 * -FP7(v1)).value, NegativeShift(-1, 6));
 
         shouldEqual((vigra::FixedPoint16<2, vigra::FPOverflowSaturate>(t1*FP7(v8)).value), (1 << 15)-1);
         shouldEqual((vigra::FixedPoint16<2, vigra::FPOverflowSaturate>(t1*FP7(-v8)).value), -(1 << 15));
@@ -2588,15 +2605,21 @@ struct LinalgTest
         int size = 2;
         for(unsigned int i = 0; i < iterations; ++i)
         {
+            using namespace vigra::linalg;
             Matrix a = random_symmetric_matrix (size);
             Matrix ew(size, 1), ewref(size, 1);
-            Matrix ev(size, size);
-            symmetricEigensystem(a, ewref, ev);
+            Matrix ev(size, size), evref(size, size);
+            symmetricEigensystem(a, ewref, evref);
             vigra::symmetric2x2Eigenvalues(
                 a(0,0), a(0,1),
                 a(1,1),
                 &ew(0,0), &ew(1,0));
             shouldEqualSequenceTolerance(ew.data(), ew.data()+size, ewref.data(), epsilon);
+            ew = 0.0;
+            symmetricEigensystemNoniterative(a, ew, ev);
+            shouldEqualSequenceTolerance(ew.data(), ew.data()+size, ewref.data(), epsilon);
+            shouldEqualTolerance(std::fabs(dot(columnVector(ev, 0), columnVector(evref, 0))), 1.0, epsilon);
+            shouldEqualTolerance(std::fabs(dot(columnVector(ev, 1), columnVector(evref, 1))), 1.0, epsilon);
         }
 
         size = 3;
@@ -2604,14 +2627,20 @@ struct LinalgTest
         {
             Matrix a = random_symmetric_matrix (size);
             Matrix ew(size, 1), ewref(size, 1);
-            Matrix ev(size, size);
-            symmetricEigensystem(a, ewref, ev);
+            Matrix ev(size, size), evref(size, size);
+            symmetricEigensystem(a, ewref, evref);
             vigra::symmetric3x3Eigenvalues<double>(
                 a(0,0), a(0,1), a(0,2),
                 a(1,1), a(1,2),
                 a(2,2),
                 &ew(0,0), &ew(1,0), &ew(2,0));
             shouldEqualSequenceTolerance(ew.data(), ew.data()+size, ewref.data(), epsilon);
+            ew = 0.0;
+            symmetricEigensystemNoniterative(a, ew, ev);
+            shouldEqualSequenceTolerance(ew.data(), ew.data()+size, ewref.data(), epsilon);
+            shouldEqualTolerance(std::fabs(dot(columnVector(ev, 0), columnVector(evref, 0))), 1.0, epsilon);
+            shouldEqualTolerance(std::fabs(dot(columnVector(ev, 1), columnVector(evref, 1))), 1.0, epsilon);
+            shouldEqualTolerance(std::fabs(dot(columnVector(ev, 2), columnVector(evref, 2))), 1.0, epsilon);
         }
     }
 
@@ -2860,115 +2889,6 @@ struct RandomTest
     }
 };
 
-struct PolygonTest
-{
-    typedef vigra::TinyVector<double, 2> Point;
-    
-    void testConvexHull()
-    {
-        vigra::ArrayVector<Point> points, reference, hull;
-        points.push_back(Point(0.0, 0.0));
-        points.push_back(Point(2.0, 1.0));
-        points.push_back(Point(2.0, -1.0));
-        points.push_back(Point(0.0, 2.0));
-        points.push_back(Point(-2.0, 1.0));
-        points.push_back(Point(-2.0, -1.0));
-        points.push_back(Point(0.0, -2.0));
-
-        reference.push_back(Point(-2.0, -1.0));
-        reference.push_back(Point(0.0, -2.0));
-        reference.push_back(Point(2.0, -1.0));
-        reference.push_back(Point(2.0, 1.0));
-        reference.push_back(Point(0.0, 2.0));
-        reference.push_back(Point(-2.0, 1.0));
-        reference.push_back(Point(-2.0, -1.0));
-        
-        vigra::convexHull(points, hull);
-
-        shouldEqual(7u, hull.size());
-        shouldEqualSequence(reference.begin(), reference.end(), hull.begin());
-
-        hull.clear();
-
-        vigra::convexHull(reference, hull);
-        
-        shouldEqual(7u, hull.size());
-        shouldEqualSequence(reference.begin(), reference.end(), hull.begin());
-        
-        typedef Point P;
-        P p[200] = { P(0.0, 0.0), P(42.0, 468.0), P(335.0, 501.0), P(170.0, 725.0), P(479.0, 359.0), 
-                  P(963.0, 465.0), P(706.0, 146.0), P(282.0, 828.0), P(962.0, 492.0), 
-                  P(996.0, 943.0), P(828.0, 437.0), P(392.0, 605.0), P(903.0, 154.0), 
-                  P(293.0, 383.0), P(422.0, 717.0), P(719.0, 896.0), P(448.0, 727.0), 
-                  P(772.0, 539.0), P(870.0, 913.0), P(668.0, 300.0), P(36.0, 895.0), 
-                  P(704.0, 812.0), P(323.0, 334.0), P(674.0, 665.0), P(142.0, 712.0), 
-                  P(254.0, 869.0), P(548.0, 645.0), P(663.0, 758.0), P(38.0, 860.0), 
-                  P(724.0, 742.0), P(530.0, 779.0), P(317.0, 36.0), P(191.0, 843.0), 
-                  P(289.0, 107.0), P(41.0, 943.0), P(265.0, 649.0), P(447.0, 806.0), 
-                  P(891.0, 730.0), P(371.0, 351.0), P(7.0, 102.0), P(394.0, 549.0), 
-                  P(630.0, 624.0), P(85.0, 955.0), P(757.0, 841.0), P(967.0, 377.0), 
-                  P(932.0, 309.0), P(945.0, 440.0), P(627.0, 324.0), P(538.0, 539.0), 
-                  P(119.0, 83.0), P(930.0, 542.0), P(834.0, 116.0), P(640.0, 659.0), 
-                  P(705.0, 931.0), P(978.0, 307.0), P(674.0, 387.0), P(22.0, 746.0), 
-                  P(925.0, 73.0), P(271.0, 830.0), P(778.0, 574.0), P(98.0, 513.0), 
-                  P(987.0, 291.0), P(162.0, 637.0), P(356.0, 768.0), P(656.0, 575.0), 
-                  P(32.0, 53.0), P(351.0, 151.0), P(942.0, 725.0), P(967.0, 431.0), 
-                  P(108.0, 192.0), P(8.0, 338.0), P(458.0, 288.0), P(754.0, 384.0), 
-                  P(946.0, 910.0), P(210.0, 759.0), P(222.0, 589.0), P(423.0, 947.0), 
-                  P(507.0, 31.0), P(414.0, 169.0), P(901.0, 592.0), P(763.0, 656.0), 
-                  P(411.0, 360.0), P(625.0, 538.0), P(549.0, 484.0), P(596.0, 42.0), 
-                  P(603.0, 351.0), P(292.0, 837.0), P(375.0, 21.0), P(597.0, 22.0), 
-                  P(349.0, 200.0), P(669.0, 485.0), P(282.0, 735.0), P(54.0, 1000.0), 
-                  P(419.0, 939.0), P(901.0, 789.0), P(128.0, 468.0), P(729.0, 894.0), 
-                  P(649.0, 484.0), P(808.0, 422.0), P(311.0, 618.0), P(814.0, 515.0), 
-                  P(310.0, 617.0), P(936.0, 452.0), P(601.0, 250.0), P(520.0, 557.0), 
-                  P(799.0, 304.0), P(225.0, 9.0), P(845.0, 610.0), P(990.0, 703.0), 
-                  P(196.0, 486.0), P(94.0, 344.0), P(524.0, 588.0), P(315.0, 504.0), 
-                  P(449.0, 201.0), P(459.0, 619.0), P(581.0, 797.0), P(799.0, 282.0), 
-                  P(590.0, 799.0), P(10.0, 158.0), P(473.0, 623.0), P(539.0, 293.0), 
-                  P(39.0, 180.0), P(191.0, 658.0), P(959.0, 192.0), P(816.0, 889.0), 
-                  P(157.0, 512.0), P(203.0, 635.0), P(273.0, 56.0), P(329.0, 647.0), 
-                  P(363.0, 887.0), P(876.0, 434.0), P(870.0, 143.0), P(845.0, 417.0), 
-                  P(882.0, 999.0), P(323.0, 652.0), P(22.0, 700.0), P(558.0, 477.0), 
-                  P(893.0, 390.0), P(76.0, 713.0), P(601.0, 511.0), P(4.0, 870.0), 
-                  P(862.0, 689.0), P(402.0, 790.0), P(256.0, 424.0), P(3.0, 586.0), 
-                  P(183.0, 286.0), P(89.0, 427.0), P(618.0, 758.0), P(833.0, 933.0), 
-                  P(170.0, 155.0), P(722.0, 190.0), P(977.0, 330.0), P(369.0, 693.0), 
-                  P(426.0, 556.0), P(435.0, 550.0), P(442.0, 513.0), P(146.0, 61.0), 
-                  P(719.0, 754.0), P(140.0, 424.0), P(280.0, 997.0), P(688.0, 530.0), 
-                  P(550.0, 438.0), P(867.0, 950.0), P(194.0, 196.0), P(298.0, 417.0), 
-                  P(287.0, 106.0), P(489.0, 283.0), P(456.0, 735.0), P(115.0, 702.0), 
-                  P(317.0, 672.0), P(787.0, 264.0), P(314.0, 356.0), P(186.0, 54.0), 
-                  P(913.0, 809.0), P(833.0, 946.0), P(314.0, 757.0), P(322.0, 559.0), 
-                  P(647.0, 983.0), P(482.0, 145.0), P(197.0, 223.0), P(130.0, 162.0), 
-                  P(536.0, 451.0), P(174.0, 467.0), P(45.0, 660.0), P(293.0, 440.0), 
-                  P(254.0, 25.0), P(155.0, 511.0), P(746.0, 650.0), P(187.0, 314.0), 
-                  P(475.0, 23.0), P(169.0, 19.0), P(788.0, 906.0), P(959.0, 392.0), 
-                  P(203.0, 626.0), P(478.0, 415.0), P(315.0, 825.0), P(335.0, 875.0), 
-                  P(373.0, 160.0), P(834.0, 71.0), P(488.0, 298.0) };
-                  
-        P ref[10] = { P(0.0, 0.0), P(597.0, 22.0), P(925.0, 73.0), P(959.0, 192.0), 
-                    P(987.0, 291.0), P(996.0, 943.0), P(882.0, 999.0), P(54.0, 1000.0),
-                    P(4.0, 870.0), P(0.0, 0.0) };
-        points = vigra::ArrayVector<Point>(p, p+200);
-        hull.clear();
-        
-        vigra::convexHull(points, hull);
-        
-        shouldEqual(10u, hull.size());
-        shouldEqualSequence(ref, ref+10, hull.begin());
-
-        int size = sizeof(convexHullInputs) / sizeof(Point);
-        points = vigra::ArrayVector<Point>(convexHullInputs, convexHullInputs+size);
-        hull.clear();
-        
-        vigra::convexHull(points, hull);
-        
-        shouldEqual(17u, hull.size());
-        shouldEqualSequence(convexHullReference, convexHullReference+17, hull.begin());
-    }
-};
-
 
 struct MathTestSuite
 : public vigra::test_suite
@@ -3078,8 +2998,6 @@ struct MathTestSuite
         add( testCase(&RandomTest::testTT800));
         add( testCase(&RandomTest::testMT19937));
         add( testCase(&RandomTest::testRandomFunctors));
-
-        add( testCase(&PolygonTest::testConvexHull));
     }
 };
 
diff --git a/test/merge_graph_adaptor/CMakeLists.txt b/test/merge_graph_adaptor/CMakeLists.txt
new file mode 100644
index 0000000..bdfdba1
--- /dev/null
+++ b/test/merge_graph_adaptor/CMakeLists.txt
@@ -0,0 +1,2 @@
+VIGRA_ADD_TEST(test_merge_graph_adaptor test.cxx)
+
diff --git a/test/merge_graph_adaptor/test.cxx b/test/merge_graph_adaptor/test.cxx
new file mode 100644
index 0000000..22e355e
--- /dev/null
+++ b/test/merge_graph_adaptor/test.cxx
@@ -0,0 +1,1732 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2004 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*                                                                      */
+/************************************************************************/
+
+
+#include <iostream>
+#include "vigra/unittest.hxx"
+#include "vigra/stdimage.hxx"
+#include "vigra/multi_array.hxx"
+#include "vigra/adjacency_list_graph.hxx"
+#include "vigra/merge_graph_adaptor.hxx"
+using namespace vigra;
+
+template<class ID_TYPE>
+struct IterablePartitonTest
+{
+    typedef ID_TYPE IdType;
+    typedef vigra::merge_graph_detail::IterablePartition<IdType> PartitionType;
+    typedef std::set<IdType> SetType;
+    typedef std::vector<IdType> VecType;
+    IterablePartitonTest()
+    {
+
+    }
+
+    void trueReps(const PartitionType ufd,SetType &set){
+        set.clear();
+        for(IdType i=0;i<ufd.numberOfElements();++i){
+            if(ufd.find(i)==i){
+                set.insert(i);
+            }
+        }
+    }
+
+    void trueReps(const PartitionType ufd,SetType &set,SetType & c){
+        set.clear();
+        for(IdType i=0;i<ufd.numberOfElements();++i){
+            if(ufd.find(i)==i){
+                set.insert(i);
+            }
+        }
+        for(typename  SetType::const_iterator iter=c.begin();iter!=c.end();++iter){
+            const IdType toRemove=*iter;
+            should(set.find(toRemove)!=set.end());
+            set.erase(toRemove);
+        }
+
+    }
+
+
+    void testReps(const PartitionType ufd,VecType & vec){
+        vec.clear();
+        vec.assign(ufd.begin(),ufd.end());
+    }
+
+
+
+
+    void iteratorTest1(){
+        PartitionType ufd(6);
+        SetType trueRep;
+        VecType testRep;
+
+        trueReps(ufd,trueRep);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+
+            
+
+        ufd.merge(0,1);
+        trueReps(ufd,trueRep);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+        
+        ufd.merge(0,2);
+        trueReps(ufd,trueRep);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+        
+        ufd.merge(0,3);
+        trueReps(ufd,trueRep);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+
+        ufd.merge(3,3);
+        trueReps(ufd,trueRep);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+
+        ufd.merge(4,5);
+        trueReps(ufd,trueRep);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+
+        ufd.merge(3,5);
+        trueReps(ufd,trueRep);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+    }
+
+    void iteratorTest2(){
+        PartitionType ufd(6);
+        SetType trueRep;
+        VecType testRep;
+
+        trueReps(ufd,trueRep);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+
+        SetType erased;
+        erased.insert(0);
+        ufd.eraseElement(0);
+
+        trueReps(ufd,trueRep,erased);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+
+        ufd.merge(1,2);
+        trueReps(ufd,trueRep,erased);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+
+        IdType rep12 = ufd.find(1);
+        erased.insert(rep12);
+        ufd.eraseElement(rep12);
+        trueReps(ufd,trueRep,erased);
+        testReps(ufd,testRep);
+        shouldEqualSequence(trueRep.begin(),trueRep.end(),testRep.begin());
+    }
+    
+};
+
+
+
+template<class IN_LABEL_TYPE>
+struct AdjacencyListGraph2MergeGraphTest{
+
+    typedef IN_LABEL_TYPE                        InLabelType;
+    typedef vigra::AdjacencyListGraph            Graph;
+    typedef vigra::MergeGraphAdaptor<Graph>    MergeGraphType;
+    typedef typename MergeGraphType::index_type  index_type;
+    typedef typename MergeGraphType::IdType      IdType;
+    typedef typename Graph::Node               GraphNode;
+    typedef typename Graph::Edge               GraphEdge;
+    typedef typename Graph::Arc                GraphArc;
+    typedef typename Graph::EdgeIt             GraphEdgeIt;
+    typedef typename Graph::NodeIt             GraphNodeIt;
+    typedef typename Graph::ArcIt              GraphArcIt;
+    typedef typename Graph::IncEdgeIt          GraphIncEdgeIt;
+    typedef typename Graph::InArcIt            GraphInArcIt;
+    typedef typename Graph::OutArcIt           GraphOutArcIt;
+
+
+    typedef typename MergeGraphType::Node        Node;
+    typedef typename MergeGraphType::Edge        Edge;
+    typedef typename MergeGraphType::Arc         Arc;
+    typedef typename MergeGraphType::EdgeIt      EdgeIt;
+    typedef typename MergeGraphType::NodeIt      NodeIt;
+    typedef typename MergeGraphType::ArcIt       ArcIt;
+    typedef typename MergeGraphType::IncEdgeIt   IncEdgeIt;
+    typedef typename MergeGraphType::InArcIt     InArcIt;
+    typedef typename MergeGraphType::OutArcIt    OutArcIt;
+
+    typedef typename Graph::NeighborNodeIt     NeighborNodeIt;
+
+
+
+    Graph graph2x2_;
+
+    bool nodeHasEdge(const MergeGraphType & g,const index_type n,const index_type & e)const{
+        const Edge edge  = g.edgeFromId(e);
+        const IdType u   = g.id(g.u(edge));
+        const IdType v   = g.id(g.v(edge));
+        return n==u || n==v;
+    }
+
+    bool nodeHasEdge(const MergeGraphType & g,const Node & node,const index_type & e)const{
+        const Edge edge  = g.edgeFromId(e);
+        const IdType u   = g.id(g.u(edge));
+        const IdType v   = g.id(g.v(edge));
+        const IdType n   = g.id(node);
+        return n==u || n==v;
+    }
+    bool edgeHasNode(const MergeGraphType & g, Edge edge, Node node){
+        if(  g.id(g.u(edge)) == g.id(node) ){
+            return true;
+        }
+        else if(g.id(g.v(edge)) == g.id(node) ){
+            return true;
+        }
+        else{
+            return false;
+        }
+    }
+
+    bool edgeHasNode(const MergeGraphType & g, Edge edge, IdType node){
+        if(  g.id(g.u(edge)) == node ){
+            return true;
+        }
+        else if(g.id(g.v(edge)) == node){
+            return true;
+        }
+        else{
+            return false;
+        }
+    }
+
+
+
+
+    size_t nodeDegree(const MergeGraphType & g ,index_type n)const{
+        return g.degree(g.nodeFromId(n));
+    }
+    size_t nodeDegree(const MergeGraphType & g ,const Node & n)const{
+        return g.degree(n);
+    }
+
+
+    AdjacencyListGraph2MergeGraphTest(){
+        AdjacencyListGraph g;
+        const GraphNode n1=g.addNode(1);
+        const GraphNode n2=g.addNode(2);
+        const GraphNode n3=g.addNode(3);
+        const GraphNode n4=g.addNode(4);
+        g.addEdge(n1,n2);
+        g.addEdge(n1,n3);
+        g.addEdge(n2,n4);
+        g.addEdge(n3,n4);
+        graph2x2_=g;
+    }
+
+
+
+    void GraphTest()
+    {
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);
+
+
+
+        //std::cout<<"basic sizes \n";
+        // assert basic sizes
+
+        shouldEqual(g.edgeNum(),4);
+        shouldEqual(g.nodeNum(),4);
+        shouldEqual(g.arcNum(),8);
+
+        //std::cout<<"max  ids \n";
+
+        shouldEqual(g.maxEdgeId(),3);
+        shouldEqual(g.maxNodeId(),4);
+        shouldEqual(g.maxArcId(),g.maxEdgeId()*2+1);
+
+        //std::cout<<"find edges \n";
+
+        should( g.findEdge(g.nodeFromId(1),g.nodeFromId(3) )!=lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(1),g.nodeFromId(2) )!=lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(2),g.nodeFromId(4) )!=lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(3),g.nodeFromId(4) )!=lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(1),g.nodeFromId(4) )==lemon::INVALID);
+        should( g.findEdge(g.nodeFromId(2),g.nodeFromId(3) )==lemon::INVALID);
+
+
+        NodeIt nbegin(g);
+        NodeIt nend(lemon::INVALID);
+
+        EdgeIt ebegin(g);
+        EdgeIt eend(lemon::INVALID);
+
+
+        ArcIt abegin(g);
+        ArcIt aend(lemon::INVALID);
+
+
+        std::vector<Node> allNodes(nbegin,nend);
+        should(allNodes.size()==4);
+
+
+
+        std::vector<Edge> allEdges(ebegin,eend);
+        should(allEdges.size()==4);
+
+
+        should(0==g.id( allEdges[0] ) );
+        should(1==g.id( allEdges[1] ) );
+        should(2==g.id( allEdges[2] ) );
+        should(3==g.id( allEdges[3] ) );
+        
+     
+        std::vector<Arc>  allArcs( abegin,aend);
+        should(allArcs.size() ==8);
+          
+        should(0==g.id( allArcs[0] ) );
+        should(1==g.id( allArcs[1] ) );
+        should(2==g.id( allArcs[2] ) );
+        should(3==g.id( allArcs[3] ) );
+
+        should(0+g.maxEdgeId()+1==g.id( allArcs[4] ) );
+        should(1+g.maxEdgeId()+1==g.id( allArcs[5] ) );
+        should(2+g.maxEdgeId()+1==g.id( allArcs[6] ) );
+        should(3+g.maxEdgeId()+1==g.id( allArcs[7] ) );
+
+        should( g.id(g.source(allArcs[0]))==g.id(g.u(allEdges[0])));
+        should( g.id(g.source(allArcs[1]))==g.id(g.u(allEdges[1])));
+        should( g.id(g.source(allArcs[2]))==g.id(g.u(allEdges[2])));
+        should( g.id(g.source(allArcs[3]))==g.id(g.u(allEdges[3])));
+
+        should( g.id(g.target(allArcs[0]))==g.id(g.v(allEdges[0])));
+        should( g.id(g.target(allArcs[1]))==g.id(g.v(allEdges[1])));
+        should( g.id(g.target(allArcs[2]))==g.id(g.v(allEdges[2])));
+        should( g.id(g.target(allArcs[3]))==g.id(g.v(allEdges[3])));
+
+
+        should( g.id(g.source(allArcs[0]))==g.id(g.target(allArcs[0+4])));
+        should( g.id(g.source(allArcs[1]))==g.id(g.target(allArcs[1+4])));
+        should( g.id(g.source(allArcs[2]))==g.id(g.target(allArcs[2+4])));
+        should( g.id(g.source(allArcs[3]))==g.id(g.target(allArcs[3+4])));
+
+        should( g.id(g.target(allArcs[0]))==g.id(g.source(allArcs[0+4])));
+        should( g.id(g.target(allArcs[1]))==g.id(g.source(allArcs[1+4])));
+        should( g.id(g.target(allArcs[2]))==g.id(g.source(allArcs[2+4])));
+        should( g.id(g.target(allArcs[3]))==g.id(g.source(allArcs[3+4])));
+
+
+        should( g.id(g.source(allArcs[4]))==g.id(g.v(allEdges[0])));
+        should( g.id(g.source(allArcs[5]))==g.id(g.v(allEdges[1])));
+        should( g.id(g.source(allArcs[6]))==g.id(g.v(allEdges[2])));
+        should( g.id(g.source(allArcs[7]))==g.id(g.v(allEdges[3])));
+
+        should( g.id(g.target(allArcs[4]))==g.id(g.u(allEdges[0])));
+        should( g.id(g.target(allArcs[5]))==g.id(g.u(allEdges[1])));
+        should( g.id(g.target(allArcs[6]))==g.id(g.u(allEdges[2])));
+        should( g.id(g.target(allArcs[7]))==g.id(g.u(allEdges[3])));
+    }
+    void GraphArcTest()
+    {
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);;
+        
+        // check sources and targets of arcs which are just the "natural edges"
+        should(  g.source(g.arcFromId(0)) == g.u(g.edgeFromId(0)) );
+        should(  g.source(g.arcFromId(1)) == g.u(g.edgeFromId(1)) );
+        should(  g.source(g.arcFromId(2)) == g.u(g.edgeFromId(2)) );
+        should(  g.source(g.arcFromId(3)) == g.u(g.edgeFromId(3)) );
+
+        should(  g.target(g.arcFromId(0)) == g.v(g.edgeFromId(0)) );
+        should(  g.target(g.arcFromId(1)) == g.v(g.edgeFromId(1)) );
+        should(  g.target(g.arcFromId(2)) == g.v(g.edgeFromId(2)) );
+        should(  g.target(g.arcFromId(3)) == g.v(g.edgeFromId(3)) );
+
+
+
+
+        // check sources and targets of arcs which are flipped "natural edges"
+        should(  g.source(g.arcFromId(4)) == g.v(g.edgeFromId(0)) );
+        should(  g.source(g.arcFromId(5)) == g.v(g.edgeFromId(1)) );
+        should(  g.source(g.arcFromId(6)) == g.v(g.edgeFromId(2)) );
+        should(  g.source(g.arcFromId(7)) == g.v(g.edgeFromId(3)) );
+
+        should(  g.target(g.arcFromId(4)) == g.u(g.edgeFromId(0)) );
+        should(  g.target(g.arcFromId(5)) == g.u(g.edgeFromId(1)) );
+        should(  g.target(g.arcFromId(6)) == g.u(g.edgeFromId(2)) );
+        should(  g.target(g.arcFromId(7)) == g.u(g.edgeFromId(3)) );
+
+        // check that arcs are convertible to edges
+        should(Edge(g.arcFromId(0))==g.edgeFromId(0));
+        should(Edge(g.arcFromId(1))==g.edgeFromId(1));
+        should(Edge(g.arcFromId(2))==g.edgeFromId(2));
+        should(Edge(g.arcFromId(3))==g.edgeFromId(3));
+        should(Edge(g.arcFromId(4))==g.edgeFromId(0));
+        should(Edge(g.arcFromId(5))==g.edgeFromId(1));
+        should(Edge(g.arcFromId(6))==g.edgeFromId(2));
+        should(Edge(g.arcFromId(7))==g.edgeFromId(3));
+
+    }
+
+    void GraphEdgeItTest()
+    {
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);
+
+        
+
+        {
+            EdgeIt begin(g);
+            EdgeIt invalid(lemon::INVALID);
+
+            should(begin!=lemon::INVALID);
+
+            
+            std::vector<Edge> edgeVec(begin,invalid);
+            shouldEqual(4,edgeVec.size());
+            shouldEqual(0,g.id(edgeVec[0]));
+            shouldEqual(1,g.id(edgeVec[1]));
+            shouldEqual(2,g.id(edgeVec[2]));
+            shouldEqual(3,g.id(edgeVec[3]));
+        }
+        {
+            EdgeIt begin(g);
+            should(begin!=lemon::INVALID);
+
+            EdgeIt empty;
+            std::vector<Edge> edgeVec(begin,empty);
+            shouldEqual(4,edgeVec.size());
+            shouldEqual(0,g.id(edgeVec[0]));
+            shouldEqual(1,g.id(edgeVec[1]));
+            shouldEqual(2,g.id(edgeVec[2]));
+            shouldEqual(3,g.id(edgeVec[3]));
+        }
+        {
+            EdgeIt begin(g,g.edgeFromId(1));
+            should(begin!=lemon::INVALID);
+
+            EdgeIt empty;
+            std::vector<Edge> edgeVec(begin,empty);
+            shouldEqual(3,edgeVec.size());
+            shouldEqual(1,g.id(edgeVec[0]));
+            shouldEqual(2,g.id(edgeVec[1]));
+            shouldEqual(3,g.id(edgeVec[2]));
+        }
+        {
+            EdgeIt begin(g,g.edgeFromId(1));
+            EdgeIt end(g,g.edgeFromId(2));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);    
+            should(begin!=end);
+
+            shouldEqual(std::distance(begin,end),1);
+            std::vector<Edge> edgeVec(begin,end);
+            shouldEqual(1,edgeVec.size());
+            shouldEqual(1,g.id(edgeVec[0]));
+        }
+
+        {
+            EdgeIt begin(g,g.edgeFromId(1));
+            EdgeIt end(g,g.edgeFromId(3));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);
+
+            std::vector<Edge> edgeVec(begin,end);
+            shouldEqual(2,edgeVec.size());
+            shouldEqual(1,g.id(edgeVec[0]));
+            shouldEqual(2,g.id(edgeVec[1]));
+        }
+    }
+    void GraphNodeItTest()
+    {
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);
+        {
+            NodeIt begin(g);
+            NodeIt invalid(lemon::INVALID);
+
+            should(begin!=lemon::INVALID);            
+            std::vector<Node> nodeVec(begin,invalid);
+            shouldEqual(4,nodeVec.size());
+            shouldEqual(1,g.id(nodeVec[0]));
+            shouldEqual(2,g.id(nodeVec[1]));
+            shouldEqual(3,g.id(nodeVec[2]));
+            shouldEqual(4,g.id(nodeVec[3]));
+        }
+        {
+            NodeIt begin(g);
+            should(begin!=lemon::INVALID);
+
+            NodeIt empty;
+            std::vector<Node> nodeVec(begin,empty);
+            shouldEqual(4,nodeVec.size());
+            shouldEqual(1,g.id(nodeVec[0]));
+            shouldEqual(2,g.id(nodeVec[1]));
+            shouldEqual(3,g.id(nodeVec[2]));
+            shouldEqual(4,g.id(nodeVec[3]));
+        }
+        {
+            NodeIt begin(g,g.nodeFromId(2));
+            should(begin!=lemon::INVALID);
+
+            NodeIt empty;
+            std::vector<Node> nodeVec(begin,empty);
+            shouldEqual(3,nodeVec.size());
+            shouldEqual(2,g.id(nodeVec[0]));
+            shouldEqual(3,g.id(nodeVec[1]));
+            shouldEqual(4,g.id(nodeVec[2]));
+        }
+        {
+            NodeIt begin(g,g.nodeFromId(2));
+            NodeIt end(g,g.nodeFromId(3));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);    
+            should(begin!=end);
+
+            shouldEqual(std::distance(begin,end),1);
+            std::vector<Node> nodeVec(begin,end);
+            shouldEqual(1,nodeVec.size());
+            shouldEqual(2,g.id(nodeVec[0]));
+        }
+
+        {
+            NodeIt begin(g,g.nodeFromId(2));
+            NodeIt end(g,g.nodeFromId(4));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);
+
+            std::vector<Node> nodeVec(begin,end);
+            shouldEqual(2,nodeVec.size());
+            shouldEqual(2,g.id(nodeVec[0]));
+            shouldEqual(3,g.id(nodeVec[1]));
+        }
+    }
+    void GraphArcItTest()
+    {
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);
+        {
+            ArcIt begin(g);
+            ArcIt invalid(lemon::INVALID);
+            should(begin!=lemon::INVALID);
+            shouldEqual(std::distance(begin,invalid),8);            
+            std::vector<Arc> arcVec(begin,invalid);
+            shouldEqual(8,arcVec.size());
+            shouldEqual(0,g.id(arcVec[0]));
+            shouldEqual(1,g.id(arcVec[1]));
+            shouldEqual(2,g.id(arcVec[2]));
+            shouldEqual(3,g.id(arcVec[3]));
+
+            shouldEqual(0+g.maxEdgeId()+1,g.id(arcVec[4]));
+            shouldEqual(1+g.maxEdgeId()+1,g.id(arcVec[5]));
+            shouldEqual(2+g.maxEdgeId()+1,g.id(arcVec[6]));
+            shouldEqual(3+g.maxEdgeId()+1,g.id(arcVec[7]));
+        }
+        {
+            ArcIt begin(g);
+            should(begin!=lemon::INVALID);
+
+            ArcIt empty;
+            std::vector<Arc> arcVec(begin,empty);
+            shouldEqual(8,arcVec.size());
+            shouldEqual(0,g.id(arcVec[0]));
+            shouldEqual(1,g.id(arcVec[1]));
+            shouldEqual(2,g.id(arcVec[2]));
+            shouldEqual(3,g.id(arcVec[3]));
+
+            shouldEqual(0+g.maxEdgeId()+1,g.id(arcVec[4]));
+            shouldEqual(1+g.maxEdgeId()+1,g.id(arcVec[5]));
+            shouldEqual(2+g.maxEdgeId()+1,g.id(arcVec[6]));
+            shouldEqual(3+g.maxEdgeId()+1,g.id(arcVec[7]));
+        }
+        {
+            ArcIt begin(g,g.arcFromId(1));
+            should(begin!=lemon::INVALID);
+
+            ArcIt empty;
+            std::vector<Arc> arcVec(begin,empty);
+            shouldEqual(7,arcVec.size());
+
+            shouldEqual(1,g.id(arcVec[0]));
+            shouldEqual(2,g.id(arcVec[1]));
+            shouldEqual(3,g.id(arcVec[2]));
+
+            shouldEqual(0+g.maxEdgeId()+1,g.id(arcVec[3]));
+            shouldEqual(1+g.maxEdgeId()+1,g.id(arcVec[4]));
+            shouldEqual(2+g.maxEdgeId()+1,g.id(arcVec[5]));
+            shouldEqual(3+g.maxEdgeId()+1,g.id(arcVec[6]));
+        }
+        {
+            ArcIt begin(g,g.arcFromId(1));
+            ArcIt end(g,g.arcFromId(2));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);    
+            should(begin!=end);
+
+            shouldEqual(std::distance(begin,end),1);
+            std::vector<Arc> arcVec(begin,end);
+            shouldEqual(1,arcVec.size());
+            shouldEqual(1,g.id(arcVec[0]));
+        }
+
+        {
+            ArcIt begin(g,g.arcFromId(1));
+            ArcIt end(g,g.arcFromId(3));
+
+            should(begin!=lemon::INVALID);
+            should(end!=lemon::INVALID);
+
+            std::vector<Arc> arcVec(begin,end);
+            shouldEqual(2,arcVec.size());
+            shouldEqual(1,g.id(arcVec[0]));
+            shouldEqual(2,g.id(arcVec[1]));
+        }
+    }
+
+    void GraphFindEdgeTest(){
+
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);
+
+        const Node n1=g.nodeFromId(1);
+        const Node n2=g.nodeFromId(2);
+        const Node n3=g.nodeFromId(3);
+        const Node n4=g.nodeFromId(4);
+
+        const Edge e12 = g.findEdge(n1,n2);
+        const Edge e13 = g.findEdge(n1,n3);
+        const Edge e24 = g.findEdge(n2,n4);
+        const Edge e34 = g.findEdge(n3,n4);
+
+
+
+        should(e12!=lemon::INVALID);
+        should(e13!=lemon::INVALID);
+        should(e24!=lemon::INVALID);
+        should(e34!=lemon::INVALID);
+
+
+        should(g.findEdge(n2,n3)==lemon::INVALID);
+        should(g.findEdge(n3,n2)==lemon::INVALID);
+        should(g.findEdge(n1,n4)==lemon::INVALID);
+        should(g.findEdge(n4,n1)==lemon::INVALID);
+
+    }
+
+    void GraphUVOrderTest(){
+
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);
+        const Node n1=g.nodeFromId(1);
+        const Node n2=g.nodeFromId(2);
+        //const Node n3=g.nodeFromId(3);
+        //const Node n4=g.nodeFromId(4);
+
+        const Edge e12 = g.findEdge(n1,n2);
+        //const Edge e13 = g.findEdge(n1,n3);
+        //const Edge e24 = g.findEdge(n2,n4);
+        //const Edge e34 = g.findEdge(n3,n4);
+
+
+        // for Graph id(u(edge)) < id(v(edge));
+        should(g.id(g.u(e12))<g.id(g.v(e12)));
+        should(g.id(g.u(e12))<g.id(g.v(e12)));
+        should(g.id(g.u(e12))<g.id(g.v(e12)));
+        should(g.id(g.u(e12))<g.id(g.v(e12)));
+    }
+
+    void GraphIncEdgeItTest()
+    {
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);
+
+        Node n1=g.nodeFromId(1);
+        Node n2=g.nodeFromId(2);
+        Node n3=g.nodeFromId(3);
+        Node n4=g.nodeFromId(4);
+
+        Edge e12 = g.findEdge(n1,n2);
+        Edge e13 = g.findEdge(n1,n3);
+        Edge e24 = g.findEdge(n2,n4);
+        Edge e34 = g.findEdge(n3,n4);
+
+        // get edges
+
+
+        {
+            IncEdgeIt a(g,n1);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e13)!=eSet.end());
+            should(eSet.find(e12)!=eSet.end());
+            should(eSet.find(e34)==eSet.end());
+            should(eSet.find(e24)==eSet.end());
+        }
+        {
+            IncEdgeIt a(g,n2);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e12)!=eSet.end());
+            should(eSet.find(e24)!=eSet.end());
+            should(eSet.find(e34)==eSet.end());
+            should(eSet.find(e13)==eSet.end());
+        }
+        {
+            IncEdgeIt a(g,n3);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e13)!=eSet.end());
+            should(eSet.find(e34)!=eSet.end());
+            should(eSet.find(e12)==eSet.end());
+            should(eSet.find(e24)==eSet.end());
+        }
+        {
+            IncEdgeIt a(g,n4);
+            IncEdgeIt b(lemon::INVALID);
+            should(a!=b);
+            should(b==lemon::INVALID);
+            should(a!=lemon::INVALID);
+            shouldEqual(std::distance(a,b),2);
+
+            std::set<Edge> eSet(a,b);
+            shouldEqual(eSet.size(),2);
+            should(eSet.find(e24)!=eSet.end());
+            should(eSet.find(e34)!=eSet.end());
+            should(eSet.find(e12)==eSet.end());
+            should(eSet.find(e13)==eSet.end());
+        }
+
+    
+    }
+
+
+    void GraphInArcItTest()
+    {
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);
+
+        Node n1=g.nodeFromId(1);
+        Node n2=g.nodeFromId(2);
+        Node n3=g.nodeFromId(3);
+        Node n4=g.nodeFromId(4);
+
+        Edge e12 = g.findEdge(n1,n2);
+        Edge e13 = g.findEdge(n1,n3);
+        Edge e24 = g.findEdge(n2,n4);
+        Edge e34 = g.findEdge(n3,n4);
+
+        // get incoming arcs
+        {
+            InArcIt a(g,n1);
+            InArcIt b(lemon::INVALID);
+            // this node has NO in arcs !
+            should(a==b);
+            shouldEqual(std::distance(a,b),0);
+        }
+        {
+            InArcIt a(g,n2);
+            InArcIt b(lemon::INVALID);
+            // this node has 1 incoming arc
+            should(a!=b);
+            shouldEqual(std::distance(a,b),1);
+            Arc arc(*a);
+            Node source = g.source(arc);
+            Node target = g.target(arc);
+            shouldEqual(g.id(target),g.id(n2));
+            shouldEqual(g.id(source),g.id(n1));
+        }
+        {
+            InArcIt a(g,n3);
+            InArcIt b(lemon::INVALID);
+            should(a!=b);
+            shouldEqual(std::distance(a,b),1);
+            Arc arc(*a);
+            Node source = g.source(arc);
+            Node target = g.target(arc);
+            shouldEqual(g.id(target),g.id(n3));
+            shouldEqual(g.id(source),g.id(n1));
+        }
+        {
+            InArcIt a(g,n4);
+            InArcIt b(lemon::INVALID);
+            // this node has 1 incoming arc
+            should(a!=b);
+            shouldEqual(std::distance(a,b),2);
+            Arc arc1(*a); ++a;
+            Arc arc2(*a); ++a;
+            should(a==b);
+            should(a==lemon::INVALID);
+            Node source1 = g.source(arc1);
+            Node target1 = g.target(arc1);
+            Node source2 = g.source(arc2);
+            Node target2 = g.target(arc2);
+            shouldEqual(g.id(target1),g.id(n4));
+            shouldEqual(g.id(target2),g.id(n4));
+            should(source1 !=source2 );
+            should(source1==n2 || source2==n2);
+            should(source1==n3 || source2==n3);
+
+        }
+    
+    }
+
+
+    void GraphOutArcItTest()
+    {
+        // create merge graph adpator
+        MergeGraphType g(graph2x2_);
+
+        Node n1=g.nodeFromId(1);
+        Node n2=g.nodeFromId(2);
+        Node n3=g.nodeFromId(3);
+        Node n4=g.nodeFromId(4);
+
+        Edge e12 = g.findEdge(n1,n2);
+        Edge e13 = g.findEdge(n1,n3);
+        Edge e24 = g.findEdge(n2,n4);
+        Edge e34 = g.findEdge(n3,n4);
+
+
+        {
+            OutArcIt a(g,n1);
+            OutArcIt b(lemon::INVALID);
+            should(a!=b);
+            shouldEqual(std::distance(a,b),2);
+            Arc arc1(*a); ++a;
+            Arc arc2(*a); ++a;
+            should(a==b);
+            should(a==lemon::INVALID);
+            Node source1 = g.source(arc1);
+            Node target1 = g.target(arc1);
+            Node source2 = g.source(arc2);
+            Node target2 = g.target(arc2);
+            shouldEqual(g.id(source1),g.id(n1));
+            shouldEqual(g.id(source2),g.id(n1));
+            should(target1 !=target2 );
+            should(target1==n2 || target2==n2);
+            should(target1==n3 || target2==n3);
+        }
+        {
+            OutArcIt a(g,n2);
+            OutArcIt b(lemon::INVALID);
+            should(a!=b);
+            shouldEqual(std::distance(a,b),1);
+            Arc arc(*a);
+            Node source = g.source(arc);
+            Node target = g.target(arc);
+            shouldEqual(g.id(source),g.id(n2));
+            shouldEqual(g.id(target),g.id(n4));
+            
+        }
+        {
+            OutArcIt a(g,n3);
+            OutArcIt b(lemon::INVALID);
+            should(a!=b);
+            shouldEqual(std::distance(a,b),1);
+            Arc arc(*a);
+            Node source = g.source(arc);
+            Node target = g.target(arc);
+            shouldEqual(g.id(target),g.id(n4));
+            shouldEqual(g.id(source),g.id(n3));
+        }
+        {
+            OutArcIt a(g,n4);
+            OutArcIt b(lemon::INVALID);
+            should(a==lemon::INVALID);
+            should(a==b);
+            shouldEqual(std::distance(a,b),0);
+        }
+    
+    }
+
+
+
+
+
+    void GraphMergeGridDegreeTest(){
+        // 1 |2 | 3
+        // __ __  _
+        // 4 |5 | 6
+        // __ __  _
+        // 7 |8 | 9
+        // create Graph
+        Graph graph;
+        {
+            const GraphNode n1 = graph.addNode(1);
+            const GraphNode n2 = graph.addNode(2);
+            const GraphNode n3 = graph.addNode(3);
+            const GraphNode n4 = graph.addNode(4);
+            const GraphNode n5 = graph.addNode(5);
+            const GraphNode n6 = graph.addNode(6);
+            const GraphNode n7 = graph.addNode(7);
+            const GraphNode n8 = graph.addNode(8);
+            const GraphNode n9 = graph.addNode(9);
+
+            graph.addEdge(n1,n2);
+            graph.addEdge(n2,n3);
+            graph.addEdge(n4,n5);
+            graph.addEdge(n5,n6);
+            graph.addEdge(n7,n8);
+            graph.addEdge(n8,n9);
+            graph.addEdge(n1,n4);
+            graph.addEdge(n2,n5);
+            graph.addEdge(n3,n6);
+            graph.addEdge(n4,n7);
+            graph.addEdge(n5,n8);
+            graph.addEdge(n6,n9);
+        }
+        MergeGraphType g(graph);
+
+        const Node n1 = g.nodeFromId(1);
+        const Node n2 = g.nodeFromId(2);
+        const Node n3 = g.nodeFromId(3);
+        const Node n4 = g.nodeFromId(4);
+        const Node n5 = g.nodeFromId(5);
+        const Node n6 = g.nodeFromId(6);
+        const Node n7 = g.nodeFromId(7);
+        const Node n8 = g.nodeFromId(8);
+        const Node n9 = g.nodeFromId(9);
+
+        // "|" edges
+        //const Edge e12 = g.findEdge(n1,n2);
+        const Edge e23 = g.findEdge(n2,n3);
+        const Edge e45 = g.findEdge(n4,n5);
+        const Edge e56 = g.findEdge(n5,n6);
+        const Edge e78 = g.findEdge(n7,n8);
+        const Edge e89 = g.findEdge(n8,n9);
+
+        // "--" edges
+        const Edge e14 = g.findEdge(n1,n4);
+        const Edge e25 = g.findEdge(n2,n5);
+        //const Edge e36 = g.findEdge(n3,n6);
+        //const Edge e47 = g.findEdge(n4,n7);
+        const Edge e58 = g.findEdge(n5,n8);
+        //  const Edge e69 = g.findEdge(n6,n9);
+
+
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2 | 3
+        // __ __  _
+        // 4 |5 | 6
+        // __ __  _
+        // 7 |8 | 9
+        shouldEqual(g.nodeNum(),9);
+        shouldEqual(g.maxNodeId(),graph.maxNodeId());
+        shouldEqual(g.edgeNum(),12);
+        shouldEqual(g.maxEdgeId(),graph.maxEdgeId());
+        shouldEqual(degreeSum(g),g.edgeNum()*2);
+        // check degrees 
+        shouldEqual(g.degree(n1),2);
+        shouldEqual(g.degree(n2),3);
+        shouldEqual(g.degree(n3),2);
+        shouldEqual(g.degree(n4),3);
+        shouldEqual(g.degree(n5),4);
+        shouldEqual(g.degree(n6),3);
+        shouldEqual(g.degree(n7),2);
+        shouldEqual(g.degree(n8),3);
+        shouldEqual(g.degree(n9),2);
+
+
+        /////////////////
+        // merge 4|5 
+        //////////////////
+        g.contractEdge(e45);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2 | 3
+        // __ __  _
+        // 4  5 | 6
+        // __ __  _
+        // 7 |8 | 9
+        shouldEqual(g.nodeNum(),8);
+        shouldEqual(g.edgeNum(),11);
+        
+        // check degrees 
+        shouldEqual(g.degree(n1),2);
+        shouldEqual(g.degree(g.reprNode(n1)),2);
+        shouldEqual(g.degree(g.reprNode(n2)),3);
+        shouldEqual(g.degree(g.reprNode(n3)),2);
+        //std::cout<<"REPR NODE OF 4 is \n"<<g.reprNodeId(g.id(n4))<<"\n";
+        shouldEqual(g.degree(g.reprNode(n4)),5);
+        shouldEqual(g.degree(g.reprNode(n5)),5);
+        shouldEqual(g.degree(g.reprNode(n6)),3);
+        shouldEqual(g.degree(g.reprNode(n7)),2);
+        shouldEqual(g.degree(g.reprNode(n8)),3);
+        shouldEqual(g.degree(g.reprNode(n9)),2);
+        shouldEqual(degreeSum(g),g.edgeNum()*2);
+
+
+        {
+            for(size_t i=0;i<=9;++i)
+            for(IncEdgeIt iter(g,g.reprNodeId(i));iter!=lemon::INVALID;++iter){
+                should(*iter!=lemon::INVALID);
+            }
+        }
+
+
+
+        //std::cout<<"\n   start here \n";
+        /////////////////
+        // merge 1|4
+        //////////////////
+        g.contractEdge(e14);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2 | 3
+        //   __  _
+        // 4  5 | 6
+        // __ __  _
+        // 7 |8 | 9
+
+        // check degrees 
+        shouldEqual(g.degree(g.reprNode(n1)),4);
+        shouldEqual(g.degree(g.reprNode(n2)),2);
+        shouldEqual(g.degree(g.reprNode(n3)),2);
+        shouldEqual(g.degree(g.reprNode(n4)),4);
+        shouldEqual(g.degree(g.reprNode(n5)),4);
+        shouldEqual(g.degree(g.reprNode(n6)),3);
+        shouldEqual(g.degree(g.reprNode(n7)),2);
+        shouldEqual(g.degree(g.reprNode(n8)),3);
+        shouldEqual(g.degree(g.reprNode(n9)),2);
+        shouldEqual(g.nodeNum(),7);
+        shouldEqual(g.edgeNum(),9);
+        shouldEqual(degreeSum(g),g.edgeNum()*2);
+        {
+            for(size_t i=0;i<=9;++i)
+            for(IncEdgeIt iter(g,g.reprNodeId(i));iter!=lemon::INVALID;++iter){
+                if(*iter==lemon::INVALID){
+                    std::cout<<"node id "<<i<<"repr "<<g.reprNodeId(i)<<"\n";
+                }
+                should(*iter!=lemon::INVALID);
+            }
+        }
+
+        //std::cout<<"\n   end here \n";
+        /////////////////
+        // merge 2|3
+        //////////////////
+        g.contractEdge(e23);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2   3
+        //   __  _
+        // 4  5 | 6
+        // __ __  _
+        // 7 |8 | 9
+        shouldEqual(g.nodeNum(),6);
+        shouldEqual(g.edgeNum(),8);
+        shouldEqual(degreeSum(g),g.edgeNum()*2);
+        // check degrees 
+        shouldEqual(g.degree(g.reprNode(n1)),4);
+        shouldEqual(g.degree(g.reprNode(n2)),2);
+        shouldEqual(g.degree(g.reprNode(n3)),2);
+        shouldEqual(g.degree(g.reprNode(n4)),4);
+        shouldEqual(g.degree(g.reprNode(n5)),4);
+        shouldEqual(g.degree(g.reprNode(n6)),3);
+        shouldEqual(g.degree(g.reprNode(n7)),2);
+        shouldEqual(g.degree(g.reprNode(n8)),3);
+        shouldEqual(g.degree(g.reprNode(n9)),2);
+        {
+            for(size_t i=0;i<=9;++i)
+            for(IncEdgeIt iter(g,g.reprNodeId(i));iter!=lemon::INVALID;++iter){
+                if(*iter==lemon::INVALID){
+                    std::cout<<"node id "<<i<<"repr "<<g.reprNodeId(i)<<"\n";
+                }
+                should(*iter!=lemon::INVALID);
+            }
+        }
+
+        /////////////////
+        // merge 8|9
+        //////////////////
+        g.contractEdge(e89);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2   3
+        //   __  _
+        // 4  5 | 6
+        // __ __  _
+        // 7 |8   9
+        shouldEqual(g.nodeNum(),5);
+        shouldEqual(g.edgeNum(),7);
+        shouldEqual(degreeSum(g),g.edgeNum()*2);
+        // check degrees 
+        shouldEqual(g.degree(g.reprNode(n1)),4);
+        shouldEqual(g.degree(g.reprNode(n2)),2);
+        shouldEqual(g.degree(g.reprNode(n3)),2);
+        shouldEqual(g.degree(g.reprNode(n4)),4);
+        shouldEqual(g.degree(g.reprNode(n5)),4);
+        shouldEqual(g.degree(g.reprNode(n6)),3);
+        shouldEqual(g.degree(g.reprNode(n7)),2);
+        shouldEqual(g.degree(g.reprNode(n8)),3);
+        shouldEqual(g.degree(g.reprNode(n9)),3);
+        {
+            for(size_t i=0;i<=9;++i)
+            for(IncEdgeIt iter(g,g.reprNodeId(i));iter!=lemon::INVALID;++iter){
+                should(*iter!=lemon::INVALID);
+            }
+        }
+
+        /////////////////
+        // merge 5|6
+        //////////////////
+        g.contractEdge(e56);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2   3
+        //   __  _
+        // 4  5   6
+        // __ __  _
+        // 7 |8   9
+        shouldEqual(g.nodeNum(),4);
+        shouldEqual(g.edgeNum(),4);
+        shouldEqual(degreeSum(g),g.edgeNum()*2);
+        // check degrees 
+        shouldEqual(g.degree(g.reprNode(n1)),3);
+        shouldEqual(g.degree(g.reprNode(n2)),1);
+        shouldEqual(g.degree(g.reprNode(n3)),1);
+        shouldEqual(g.degree(g.reprNode(n4)),3);
+        shouldEqual(g.degree(g.reprNode(n5)),3);
+        shouldEqual(g.degree(g.reprNode(n6)),3);
+        shouldEqual(g.degree(g.reprNode(n7)),2);
+        shouldEqual(g.degree(g.reprNode(n8)),2);
+        shouldEqual(g.degree(g.reprNode(n9)),2);
+        {
+            for(size_t i=0;i<=9;++i)
+            for(IncEdgeIt iter(g,g.reprNodeId(i));iter!=lemon::INVALID;++iter){
+                should(*iter!=lemon::INVALID);
+            }
+        }
+
+        /////////////////
+        // merge repr(2|5)
+        //////////////////
+        g.contractEdge(g.reprEdge(e25));
+        // CURRENT GRAPH:
+        // --------------
+        // 1  2   3
+        //         
+        // 4  5   6
+        // __ __  _
+        // 7 |8   9
+        shouldEqual(g.nodeNum(),3);
+        shouldEqual(g.edgeNum(),3);
+        shouldEqual(degreeSum(g),g.edgeNum()*2);
+        // check degrees 
+        shouldEqual(g.degree(g.reprNode(n1)),2);
+        shouldEqual(g.degree(g.reprNode(n2)),2);
+        shouldEqual(g.degree(g.reprNode(n3)),2);
+        shouldEqual(g.degree(g.reprNode(n4)),2);
+        shouldEqual(g.degree(g.reprNode(n5)),2);
+        shouldEqual(g.degree(g.reprNode(n6)),2);
+        shouldEqual(g.degree(g.reprNode(n7)),2);
+        shouldEqual(g.degree(g.reprNode(n8)),2);
+        shouldEqual(g.degree(g.reprNode(n9)),2);
+        {
+            for(size_t i=0;i<=9;++i)
+            for(IncEdgeIt iter(g,g.reprNodeId(i));iter!=lemon::INVALID;++iter){
+                should(*iter!=lemon::INVALID);
+            }
+        }
+
+
+        /////////////////
+        // merge repr(5|8)
+        //////////////////
+        g.contractEdge(g.reprEdge(e58));
+        // CURRENT GRAPH:
+        // --------------
+        // 1  2   3
+        //         
+        // 4  5   6
+        // __     
+        // 7 |8   9
+        shouldEqual(g.nodeNum(),2);
+        shouldEqual(g.edgeNum(),1);
+        shouldEqual(degreeSum(g),g.edgeNum()*2);
+        // check degrees 
+        shouldEqual(g.degree(g.reprNode(n1)),1);
+        shouldEqual(g.degree(g.reprNode(n2)),1);
+        shouldEqual(g.degree(g.reprNode(n3)),1);
+        shouldEqual(g.degree(g.reprNode(n4)),1);
+        shouldEqual(g.degree(g.reprNode(n5)),1);
+        shouldEqual(g.degree(g.reprNode(n6)),1);
+        shouldEqual(g.degree(g.reprNode(n7)),1);
+        shouldEqual(g.degree(g.reprNode(n8)),1);
+        shouldEqual(g.degree(g.reprNode(n9)),1);
+        {
+            for(size_t i=0;i<=9;++i)
+            for(IncEdgeIt iter(g,g.reprNodeId(i));iter!=lemon::INVALID;++iter){
+                should(*iter!=lemon::INVALID);
+            }
+        }
+
+        /////////////////
+        // merge repr(7|8)
+        //////////////////
+        g.contractEdge(g.reprEdge(e78));
+        // CURRENT GRAPH:
+        // --------------
+        // 1  2   3
+        //         
+        // 4  5   6
+        // __     
+        // 7 |8   9
+        shouldEqual(g.nodeNum(),1);
+        shouldEqual(g.edgeNum(),0);
+        shouldEqual(degreeSum(g),g.edgeNum()*2);
+        // check degrees 
+        shouldEqual(g.degree(g.reprNode(n1)),0);
+        shouldEqual(g.degree(g.reprNode(n2)),0);
+        shouldEqual(g.degree(g.reprNode(n3)),0);
+        shouldEqual(g.degree(g.reprNode(n4)),0);
+        shouldEqual(g.degree(g.reprNode(n5)),0);
+        shouldEqual(g.degree(g.reprNode(n6)),0);
+        shouldEqual(g.degree(g.reprNode(n7)),0);
+        shouldEqual(g.degree(g.reprNode(n8)),0);
+        shouldEqual(g.degree(g.reprNode(n9)),0);
+        {
+            for(size_t i=0;i<=9;++i)
+            for(IncEdgeIt iter(g,g.reprNodeId(i));iter!=lemon::INVALID;++iter){
+                should(*iter!=lemon::INVALID);
+            }
+        }
+    }
+
+
+    void GraphMergeGridEdgeTest(){
+        // 1 |2 | 3
+        // __ __  _
+        // 4 |5 | 6
+        // __ __  _
+        // 7 |8 | 9
+
+        // create Graph
+        Graph graph;
+        {
+            const GraphNode n1 = graph.addNode(1);
+            const GraphNode n2 = graph.addNode(2);
+            const GraphNode n3 = graph.addNode(3);
+            const GraphNode n4 = graph.addNode(4);
+            const GraphNode n5 = graph.addNode(5);
+            const GraphNode n6 = graph.addNode(6);
+            const GraphNode n7 = graph.addNode(7);
+            const GraphNode n8 = graph.addNode(8);
+            const GraphNode n9 = graph.addNode(9);
+
+
+            graph.addEdge(n1,n2);
+            graph.addEdge(n2,n3);
+            graph.addEdge(n4,n5);
+            graph.addEdge(n5,n6);
+            graph.addEdge(n7,n8);
+            graph.addEdge(n8,n9);
+            graph.addEdge(n1,n4);
+            graph.addEdge(n2,n5);
+            graph.addEdge(n3,n6);
+            graph.addEdge(n4,n7);
+            graph.addEdge(n5,n8);
+            graph.addEdge(n6,n9);
+        }
+        MergeGraphType g(graph);
+
+
+        const Node n1 = g.nodeFromId(1);
+        const Node n2 = g.nodeFromId(2);
+        const Node n3 = g.nodeFromId(3);
+        const Node n4 = g.nodeFromId(4);
+        const Node n5 = g.nodeFromId(5);
+        const Node n6 = g.nodeFromId(6);
+        const Node n7 = g.nodeFromId(7);
+        const Node n8 = g.nodeFromId(8);
+        const Node n9 = g.nodeFromId(9);
+
+        // "|" edges
+        //const Edge e12 = g.findEdge(n1,n2);
+        const Edge e23 = g.findEdge(n2,n3);
+        //const Edge e45 = g.findEdge(n4,n5);
+        const Edge e56 = g.findEdge(n5,n6);
+        //const Edge e78 = g.findEdge(n7,n8);
+        const Edge e89 = g.findEdge(n8,n9);
+
+        // "--" edges
+        //const Edge e14 = g.findEdge(n1,n4);
+        const Edge e25 = g.findEdge(n2,n5);
+        //const Edge e36 = g.findEdge(n3,n6);
+        const Edge e47 = g.findEdge(n4,n7);
+        //const Edge e58 = g.findEdge(n5,n8);
+        //const Edge e69 = g.findEdge(n6,n9);
+
+
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2 |3
+        // __ __ _
+        // 4 |5 |6
+        // __ __ _
+        // 7 |8 |9
+        shouldEqual(g.nodeNum(),9);
+        shouldEqual(g.maxNodeId(),graph.maxNodeId());
+        shouldEqual(g.edgeNum(),12);
+        shouldEqual(g.maxEdgeId(),graph.maxEdgeId());
+
+
+
+        should( g.findEdge(n1,n2)!=lemon::INVALID);
+        should( g.findEdge(n1,n3)==lemon::INVALID);
+        should( g.findEdge(n1,n4)!=lemon::INVALID);
+        should( g.findEdge(n1,n5)==lemon::INVALID);
+        should( g.findEdge(n1,n6)==lemon::INVALID);
+        should( g.findEdge(n1,n7)==lemon::INVALID);
+        should( g.findEdge(n1,n8)==lemon::INVALID);
+        should( g.findEdge(n1,n9)==lemon::INVALID);
+        // 
+        should( g.findEdge(n2,n3)!=lemon::INVALID);
+        should( g.findEdge(n2,n4)==lemon::INVALID);
+        should( g.findEdge(n2,n5)!=lemon::INVALID);
+        should( g.findEdge(n2,n6)==lemon::INVALID);
+        should( g.findEdge(n2,n7)==lemon::INVALID);
+        should( g.findEdge(n2,n8)==lemon::INVALID);
+        should( g.findEdge(n2,n9)==lemon::INVALID);
+
+        should( g.findEdge(n3,n4)==lemon::INVALID);
+        should( g.findEdge(n3,n5)==lemon::INVALID);
+        should( g.findEdge(n3,n6)!=lemon::INVALID);
+        should( g.findEdge(n3,n7)==lemon::INVALID);
+        should( g.findEdge(n3,n8)==lemon::INVALID);
+        should( g.findEdge(n3,n9)==lemon::INVALID);
+        //
+        should( g.findEdge(n4,n5)!=lemon::INVALID);
+        should( g.findEdge(n4,n6)==lemon::INVALID);
+        should( g.findEdge(n4,n7)!=lemon::INVALID);
+        should( g.findEdge(n4,n8)==lemon::INVALID);
+        should( g.findEdge(n4,n9)==lemon::INVALID);
+        //
+        should( g.findEdge(n5,n6)!=lemon::INVALID);
+        should( g.findEdge(n5,n7)==lemon::INVALID);
+        should( g.findEdge(n5,n8)!=lemon::INVALID);
+        should( g.findEdge(n5,n9)==lemon::INVALID);
+        //
+        should( g.findEdge(n6,n7)==lemon::INVALID);
+        should( g.findEdge(n6,n8)==lemon::INVALID);
+        should( g.findEdge(n6,n9)!=lemon::INVALID);
+        //
+        should( g.findEdge(n7,n8)!=lemon::INVALID);
+        should( g.findEdge(n7,n9)==lemon::INVALID);
+        //
+        should( g.findEdge(n8,n9)!=lemon::INVALID);
+
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n2))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n3))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n5))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n6))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n3))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n4))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n6))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n4))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n5))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n6))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n8),g.reprNode(n9))!=lemon::INVALID);
+
+        /////////////////
+        // merge 2|3
+        //////////////////
+        g.contractEdge(e23);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2  3
+        // __ __ _
+        // 4 |5 |6
+        // __ __ _
+        // 7 |8 |9
+        shouldEqual(g.nodeNum(),8);
+        shouldEqual(g.edgeNum(),11);
+
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n2))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n3))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n5))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n6))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n3))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n4))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n4))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n6))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n8),g.reprNode(n9))!=lemon::INVALID);
+
+
+
+
+        /////////////////
+        // merge 2|5
+        //////////////////
+        g.contractEdge(e25);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2  3
+        // __    _
+        // 4 |5 |6
+        // __ __ _
+        // 7 |8 |9
+
+
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n2))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n3))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n6))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n3))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n5))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n5))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n6))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n8),g.reprNode(n9))!=lemon::INVALID);
+        shouldEqual(g.nodeNum(),7);
+        shouldEqual(g.edgeNum(),9);
+
+        /////////////////
+        // merge 5|6
+        //////////////////
+        g.contractEdge(e56);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2  3
+        // __     
+        // 4 |5  6
+        // __ __ _
+        // 7 |8 |9
+        shouldEqual(g.nodeNum(),6);
+        shouldEqual(g.edgeNum(),8);
+
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n2))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n3))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n3))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n5))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n6))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n5))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n6))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n6))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n7))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n8),g.reprNode(n9))!=lemon::INVALID);
+
+
+        /////////////////
+        // merge 4|7
+        //////////////////
+        g.contractEdge(e47);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2  3
+        // __     
+        // 4 |5  6
+        //    __ _
+        // 7 |8 |9
+        shouldEqual(g.nodeNum(),5);
+        shouldEqual(g.edgeNum(),7);
+
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n2))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n3))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n3))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n5))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n6))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n5))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n6))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n7))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n6))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n8),g.reprNode(n9))!=lemon::INVALID);
+
+
+        /////////////////
+        // merge 8|9
+        //////////////////
+        g.contractEdge(e89);
+        // CURRENT GRAPH:
+        // --------------
+        // 1 |2  3
+        // __     
+        // 4 |5  6
+        //    __ _
+        // 7 |8  9
+        shouldEqual(g.nodeNum(),4);
+        shouldEqual(g.edgeNum(),5);
+
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n2))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n3))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n8))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n1),g.reprNode(n9))==lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n3))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n5))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n6))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n2),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n4))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n5))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n6))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n3),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n5))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n6))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n7))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n4),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n6))==lemon::INVALID); // (in same cluster)
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n5),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n7))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n6),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n8))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n7),g.reprNode(n9))!=lemon::INVALID);
+        should( g.findEdge(g.reprNode(n8),g.reprNode(n9))==lemon::INVALID); // (in same cluster)
+
+
+    }
+
+    size_t degreeSum(const MergeGraphType & g){
+        size_t degreeSum=0;
+        for(NodeIt n(g);n!=lemon::INVALID;++n){
+            degreeSum+=g.degree(*n);
+        }
+        return degreeSum;
+    }
+};
+
+
+ 
+struct AdjacencyListGraphMergeGraphAdaptorTestSuite
+: public vigra::test_suite
+{
+    AdjacencyListGraphMergeGraphAdaptorTestSuite()
+    : vigra::test_suite("AdjacencyListGraphMergeGraphAdaptorTestSuite")
+    {   
+        
+        add( testCase( &IterablePartitonTest<UInt32>::iteratorTest1));
+        add( testCase( &IterablePartitonTest<UInt32>::iteratorTest2));
+        add( testCase( &IterablePartitonTest<Int32>::iteratorTest1));
+        add( testCase( &IterablePartitonTest<Int32>::iteratorTest2));
+
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphTest));
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphArcTest));
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphFindEdgeTest));
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphUVOrderTest));
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphEdgeItTest));
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphNodeItTest));
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphArcItTest));
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphIncEdgeItTest));
+        //add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphInArcItTest));
+        //add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphOutArcItTest));
+        
+
+        // test which do some merging
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphMergeGridDegreeTest));
+        add( testCase( &AdjacencyListGraph2MergeGraphTest<vigra::UInt32>::GraphMergeGridEdgeTest));
+    }
+};
+
+int main(int argc, char ** argv)
+{
+    AdjacencyListGraphMergeGraphAdaptorTestSuite test;
+
+    int failed = test.run(vigra::testsToBeExecuted(argc, argv));
+
+    std::cout << test.report() << std::endl;
+
+    return (failed != 0);
+}
+
diff --git a/test/multiarray/CMakeLists.txt b/test/multiarray/CMakeLists.txt
index a30f519..e6f32e9 100644
--- a/test/multiarray/CMakeLists.txt
+++ b/test/multiarray/CMakeLists.txt
@@ -10,6 +10,46 @@ IF(TIFF_FOUND)
   ADD_DEFINITIONS(-DHasTIFF)
 ENDIF(TIFF_FOUND)
 
-VIGRA_ADD_TEST(test_multiarray test.cxx LIBRARIES vigraimpex)
-
 FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/impex)
+
+# Check cpp version
+if(NOT ${VIGRA_CPP_VERSION})
+    message(FATAL_ERROR 
+            "cmake error: VIGRA_CPP_VERSION not defined yet. "
+            "Call VIGRA_DETECT_CPP_VERSION() from the main CMakeLists file." )
+endif()
+
+# multiarray/test.cxx uses 'auto' from c++11.
+string(COMPARE LESS ${VIGRA_CPP_VERSION} "201103" NO_CXX11)
+if(NO_CXX11 AND NOT MSVC) # Visual Studio 2010 and 2012 supports enough c++11 features that we can still use it 
+    MESSAGE(STATUS "** WARNING: You are compiling in C++98 mode.")
+    MESSAGE(STATUS "**          Multiarray tests will be skipped.")
+    MESSAGE(STATUS "**          Add -std=c++11 to CMAKE_CXX_FLAGS to enable multiarray tests.")
+else()
+    VIGRA_ADD_TEST(test_multiarray test.cxx LIBRARIES vigraimpex)
+endif()    
+
+# Even with C++11, a working threading implementation is needed for running multiarray_chunked tests.
+VIGRA_CONFIGURE_THREADING()
+
+if(NOT THREADING_FOUND)
+    MESSAGE(STATUS "** WARNING: Your compiler does not support C++ threading.")
+    MESSAGE(STATUS "**          test_multiarray_chunked will not be executed on this platform.")
+    if(NOT WITH_BOOST_THREAD)
+        MESSAGE(STATUS "**          Try to run cmake with '-DWITH_BOOST_THREAD=1' to use boost threading.")
+    endif()
+else()
+  SET(MULTIARRAY_CHUNKED_LIBRARIES ${THREADING_LIBRARIES})
+
+  IF(HDF5_FOUND)
+    ADD_DEFINITIONS(-DHasHDF5 ${HDF5_CPPFLAGS})
+    INCLUDE_DIRECTORIES(${HDF5_INCLUDE_DIR})
+    SET(MULTIARRAY_CHUNKED_LIBRARIES vigraimpex ${HDF5_LIBRARIES} ${MULTIARRAY_CHUNKED_LIBRARIES})
+  ELSE(TIFF_FOUND)
+    SET(MULTIARRAY_CHUNKED_LIBRARIES vigraimpex ${MULTIARRAY_CHUNKED_LIBRARIES})
+  ENDIF()
+
+  VIGRA_ADD_TEST(test_multiarray_chunked test_chunked.cxx 
+                 LIBRARIES ${MULTIARRAY_CHUNKED_LIBRARIES})
+endif()
+
diff --git a/test/multiarray/compression-ratio-benchmark.xlsx b/test/multiarray/compression-ratio-benchmark.xlsx
new file mode 100644
index 0000000..f893f6e
Binary files /dev/null and b/test/multiarray/compression-ratio-benchmark.xlsx differ
diff --git a/test/multiarray/test.cxx b/test/multiarray/test.cxx
index eb18ec5..ec3d3cf 100644
--- a/test/multiarray/test.cxx
+++ b/test/multiarray/test.cxx
@@ -36,6 +36,7 @@
 #include "vigra/unittest.hxx"
 #include "vigra/multi_array.hxx"
 #include "vigra/multi_iterator_coupled.hxx"
+#include "vigra/multi_hierarchical_iterator.hxx"
 #include "vigra/multi_impex.hxx"
 #include "vigra/basicimageview.hxx"
 #include "vigra/navigator.hxx"
@@ -64,6 +65,7 @@ public:
     typedef typename vigra::detail::ResolveMultiband<T>::type   scalar_type;
     typedef MultiArray <2, scalar_type> array2_type;
     typedef MultiArray <3, T> array3_type;
+    typedef MultiArrayView<3, Multiband<scalar_type> >  MultibandView3;
     typedef typename array3_type::view_type       array3_view_type;
     typedef typename array3_type::actual_stride   array3_stride;
     typedef typename array2_type::difference_type difference2_type;
@@ -103,6 +105,10 @@ public:
         for(unsigned int k=0; k<10; ++k)
             array3(k,0,0) += 10;
         should(array3.subarray(Shape(0,0,0), Shape(10,1,1)) == array3.subarray(Shape(0,1,0), Shape(10,2,1)));
+
+        MultibandView3 channel_view(a.multiband());
+        shouldEqual(a.shape(), channel_view.shape());
+        shouldEqual(a.data(), channel_view.data());
     }
     
     // bindInner tests
@@ -221,7 +227,16 @@ public:
             shouldEqual(array3[k], k+100);
         for(int k=100; k<200; ++k)
             shouldEqual(array3[k], k-100);
-
+            
+        MultiArrayView <3, scalar_type> varray1 = array;
+        MultiArrayView <3, scalar_type> varray2 = array3.subarray (Shape(0,1,0), Shape(3,4,5));
+        shouldEqual (varray1.shape(), Shape(4,4,4));
+        shouldEqual (varray2.shape(), Shape(3,3,5));
+        varray2.swap(varray1);
+        shouldEqual (varray2.shape(), Shape(4,4,4));
+        shouldEqual (varray1.shape(), Shape(3,3,5));
+        shouldEqual (varray2.data(), array.data());
+        shouldEqual (varray1.data(), &array3(0,1,0));
     }
         
     // stridearray tests
@@ -443,7 +458,10 @@ public:
             std::string message(c.what());
             should(0 == expected.compare(message.substr(0,expected.size())));
         }
+	array.reset();
+	array = array3.subarray(Shape(0,0,0), Shape(10,1,1)); // possible after reset.
         MultiArrayView <3, scalar_type, array3_stride> subarray = array3.subarray(Shape(0,0,0), Shape(10,1,1));
+	should(subarray == array);
         subarray = array3.subarray(Shape(0,1,0), Shape(10,2,1)); // should overwrite the data
         for(unsigned int k=0; k<10; ++k)
             shouldEqual(array3(k,0,0), array3(k,1,0));
@@ -552,6 +570,11 @@ public:
         shouldEqual(a(0), 2);
         shouldEqual(a(1), 2);
         should(a == array1_t(shape1_t(2), 4).init(2));
+
+        array1_t b(Shape1(5), LinearSequence);
+        shouldEqual (b.shape (0), 5);
+        int ref[] = { 0, 1, 2, 3, 4 };
+        shouldEqualSequence(b.begin(), b.end(), ref);
     }
 
     void test_assignment ()
@@ -625,6 +648,14 @@ public:
         shouldEqual(&i1[7], &a3(1,0,1));
         shouldEqual(&i1[9], &a3(1,1,1));
 
+        shouldEqual(&i1[Shape3(0,0,0)], &a3(0,0,0));
+        shouldEqual(&i1[Shape3(1,0,0)], &a3(1,0,0));
+        shouldEqual(&i1[Shape3(0,1,0)], &a3(0,1,0));
+        shouldEqual(&i1[Shape3(1,1,0)], &a3(1,1,0));
+        shouldEqual(&i1[Shape3(0,0,1)], &a3(0,0,1));
+        shouldEqual(&i1[Shape3(1,0,1)], &a3(1,0,1));
+        shouldEqual(&i1[Shape3(1,1,1)], &a3(1,1,1));
+
         shouldEqual(&*(i1+0), &a3(0,0,0));
         shouldEqual(&*(i1+1), &a3(1,0,0));
         shouldEqual(&*(i1+2), &a3(0,1,0));
@@ -685,6 +716,14 @@ public:
         shouldEqual(&*(i3-shape3_t(1,0,1)), &a3(0,2,3));
         shouldEqual(&*(i3-shape3_t(1,1,1)), &a3(0,1,3));
 
+        shouldEqual(&i3[-shape3_t(0,0,0)], &a3(1,2,4));
+        shouldEqual(&i3[-shape3_t(1,0,0)], &a3(0,2,4));
+        shouldEqual(&i3[-shape3_t(0,1,0)], &a3(1,1,4));
+        shouldEqual(&i3[-shape3_t(1,1,0)], &a3(0,1,4));
+        shouldEqual(&i3[-shape3_t(0,0,1)], &a3(1,2,3));
+        shouldEqual(&i3[-shape3_t(1,0,1)], &a3(0,2,3));
+        shouldEqual(&i3[-shape3_t(1,1,1)], &a3(0,1,3));
+        
         shouldEqual(&iend[-1], &a3(1,2,4));
         shouldEqual(&iend[-2], &a3(0,2,4));
         shouldEqual(&iend[-3], &a3(1,1,4));
@@ -703,23 +742,47 @@ public:
 
         unsigned int count = 0;
         shape3_t p;
+        i3 = av.begin();
+        iterator3_t i4(av.begin()); 
+        iterator3_t i5(av.begin()); 
+        iterator3_t i6(av.begin()); 
 
         // iterate over the third dimension
-        for (p[2]=0; p[2] != s[2]; ++p[2]) 
+        for (p[2]=0, i3.resetDim(2), i4.setDim(2, 0), i5.dim<2>() = 0, i6.resetDim(2); 
+                i3.point(2) != s[2]; 
+                i3.incDim(2), i4.addDim(2, 1), ++i5.dim<2>(), i6.dim<2>() += 1, ++p[2]) 
         {
-            for (p[1]=0; p[1] != s[1]; ++p[1]) 
+            for (p[1]=0, i3.resetDim(1), i4.setDim(1, 0), i5.dim<1>() = 0, i6.resetDim(1); 
+                    i3.point(1) != s[1]; 
+                    i3.incDim(1), i4.addDim(1, 1), ++i5.dim<1>(), i6.dim<1>() += 1, ++p[1]) 
             {
-                for (p[0]=0; p[0] != s[0]; ++p[0], ++i1, ++c, i2 += 1, ++count)
+                for (p[0]=0, i3.resetDim(0), i4.setDim(0, 0), i5.dim<0>() = 0, i6.resetDim(0); 
+                        i3.point(0) != s[0]; 
+                        i3.incDim(0), i4.addDim(0, 1), ++i5.dim<0>(), i6.dim<0>() += 1, ++p[0], ++i1, ++c, i2 += 1, ++count)
                 {
                     shouldEqual(&*i1, &a3[p]);
                     shouldEqual(&*i2, &a3[p]);
+                    shouldEqual(&*i3, &a3[p]);
+                    shouldEqual(&*i4, &a3[p]);
+                    shouldEqual(&*i5, &a3[p]);
+                    shouldEqual(&*i6, &a3[p]);
                     shouldEqual(i1.operator->(), &a3[p]);
                     shouldEqual(i2.operator->(), &a3[p]);
                     shouldEqual(*c, p);
+
                     shouldEqual(i1.point(), p);
                     shouldEqual(i2.point(), p);
+                    shouldEqual(i3.point(), p);
+                    shouldEqual(i4.point(), p);
+                    shouldEqual(i5.point(), p);
+                    shouldEqual(i6.point(), p);
+
                     shouldEqual(i1.index(), count);
                     shouldEqual(i2.index(), count);
+                    shouldEqual(i3.index(), count);
+                    shouldEqual(i4.index(), count);
+                    shouldEqual(i5.index(), count);
+                    shouldEqual(i6.index(), count);
 
                     should(i1 != iend);
                     should(!(i1 == iend));
@@ -728,6 +791,25 @@ public:
                     should(!(i1 > iend));
                     should(!(i1 >= iend));
 
+                    should(i5.dim<2>() == p[2]);
+                    should(i5.dim<1>() == p[1]);
+                    should(i5.dim<0>() == p[0]);
+                    should(i5.dim<2>() != s[2]);
+                    should(i5.dim<1>() != s[1]);
+                    should(i5.dim<0>() != s[0]);
+                    should(i5.dim<2>() <= p[2]);
+                    should(i5.dim<1>() <= p[1]);
+                    should(i5.dim<0>() <= p[0]);
+                    should(i5.dim<2>() < s[2]);
+                    should(i5.dim<1>() < s[1]);
+                    should(i5.dim<0>() < s[0]);
+                    should(i5.dim<2>() >= 0);
+                    should(i5.dim<1>() >= 0);
+                    should(i5.dim<0>() >= 0);
+                    shouldNot(i5.dim<2>() > s[2]);
+                    shouldNot(i5.dim<1>() > s[1]);
+                    shouldNot(i5.dim<0>() > s[0]);
+
                     shouldEqual(iend - i1, av.size() - count);
 
                     bool atBorder = p[0] == 0 || p[0] == s[0]-1 || p[1] == 0 || p[1] == s[1]-1 ||
@@ -913,6 +995,14 @@ public:
         shouldEqual(&get<1>(*(i1+shape3_t(1,0,1))), &a3(1,0,1));
         shouldEqual(&get<1>(*(i1+shape3_t(1,1,1))), &a3(1,1,1));
 
+        shouldEqual(&get<1>(i1[shape3_t(0,0,0)]), &a3(0,0,0));
+        shouldEqual(&get<1>(i1[shape3_t(1,0,0)]), &a3(1,0,0));
+        shouldEqual(&get<1>(i1[shape3_t(0,1,0)]), &a3(0,1,0));
+        shouldEqual(&get<1>(i1[shape3_t(1,1,0)]), &a3(1,1,0));
+        shouldEqual(&get<1>(i1[shape3_t(0,0,1)]), &a3(0,0,1));
+        shouldEqual(&get<1>(i1[shape3_t(1,0,1)]), &a3(1,0,1));
+        shouldEqual(&get<1>(i1[shape3_t(1,1,1)]), &a3(1,1,1));
+
         shouldEqual(&get<1>(*(iend-1)), &a3(1,2,4));
         shouldEqual(&get<1>(*(iend-2)), &a3(0,2,4));
         shouldEqual(&get<1>(*(iend-3)), &a3(1,1,4));
@@ -920,6 +1010,8 @@ public:
         shouldEqual(&get<1>(*(iend-8)), &a3(0,2,3));
         shouldEqual(&get<1>(*(iend-10)), &a3(0,1,3));
 
+        should(cast<1>(*i1).arrayView() == a3);
+
         i3 = iend-1;
         shouldEqual(&get<1>(*(i3-shape3_t(0,0,0))), &a3(1,2,4));
         shouldEqual(&get<1>(*(i3-shape3_t(1,0,0))), &a3(0,2,4));
@@ -957,6 +1049,8 @@ public:
                 {
                     shouldEqual(&get<1>(*i1), &a3[p]);
                     shouldEqual(&get<1>(*i2), &a3[p]);
+                    shouldEqual(&get<1>(i1), &a3[p]);
+                    shouldEqual(&get<1>(i2), &a3[p]);
                     shouldEqual(&i1.get<1>(), &a3[p]);
                     shouldEqual(&i2.get<1>(), &a3[p]);
                     //shouldEqual(i1.operator->(), &a3[p]);
@@ -965,9 +1059,13 @@ public:
                     shouldEqual(i2.point(), p);
                     shouldEqual(i1.get<0>(), p);
                     shouldEqual(i2.get<0>(), p);
+                    shouldEqual(get<0>(i1), p);
+                    shouldEqual(get<0>(i2), p);
                     shouldEqual(i1.scanOrderIndex(), count);
                     shouldEqual(i2.scanOrderIndex(), count);
 
+                    should(cast<1>(*i1).arrayView() == a3);
+
                     should(i1 != iend);
                     should(!(i1 == iend));
                     should(i1 < iend);
@@ -1027,16 +1125,21 @@ public:
         Iterator0 i0 = createCoupledIterator(Shape1(4));
         Iterator1 it = createCoupledIterator(vi, vd),
                   end = it.getEndIterator();
+        Iterator1 iz = zip(vi.begin(), vd.begin());
 
         count = 0;
-        for(; it < end; ++it, ++i0, ++count)
+        for(; count < 4; ++iz, ++it, ++i0, ++count)
         {
             shouldEqual(i0.get<0>(), Shape1(count));
             shouldEqual(it.get<0>(), Shape1(count));
             shouldEqual(it.get<1>(), count+10);
             shouldEqual(it.get<2>(), count+20.0);
+            shouldEqual(iz.get<0>(), Shape1(count));
+            shouldEqual(iz.get<1>(), count+10);
+            shouldEqual(iz.get<2>(), count+20.0);
         }
-        shouldEqual(count, 4);
+        shouldEqual(it, end);
+        shouldEqual(iz, end);
 
         // test multiband
         MultiArrayView<3, scalar_type, StridedArrayTag> at = a3.transpose();
@@ -1051,6 +1154,7 @@ public:
             shouldEqual(im.get<1>().shape(), Shape1(2));
             shouldEqual(&(im.get<1>()[0]), &(im.get<2>()));
             shouldEqual(&(im.get<1>()[1]), &(im.get<3>()));
+            should(cast<1>(*im).arrayView() == at);
         }
         shouldEqual(count, 15);
     }
@@ -1181,6 +1285,81 @@ public:
         shouldEqual(&*(i3+shape3_t(2,3,4)), &i3[shape3_t(2,3,4)]);
     }
 
+    void test_hierarchical ()
+    {
+        // test hierarchical navigation and 
+        auto i3_f = createHierarchicalIterator(a3),
+             i3_l = i3_f.getEndIterator();
+        auto i3_c = zip(i3_f, i3_f);
+        array3_t::iterator seqi = a3.begin();
+
+        int countx = 0, county = 0, countz = 0;
+
+        // iterate over the third dimension
+        for (int z=0; i3_f != i3_l; ++i3_f, ++i3_c, ++z) 
+        {
+            auto i2_f = i3_f.begin ();
+            auto i2_c = i3_c.begin ();
+            auto i2_l = i3_f.end ();
+            // iterate over the second dimension
+            for (int y=0; i2_f != i2_l; ++i2_f, ++i2_c, ++y) 
+            {
+                auto i1_f = i2_f.begin ();
+                auto i1_c = i2_c.begin ();
+                auto i1_l = i2_f.end ();
+                // iterate over the first dimension
+                for (int x=0; i1_f != i1_l; ++i1_f, ++i1_c, ++x, ++seqi)
+                {
+                    ++countx;
+                    shouldEqual(&*seqi, &a3(x,y,z));
+                    shouldEqual(i1_f.point(), Shape3(x,y,z));
+                    shouldEqual(&*i1_f, &a3(x,y,z));
+                    shouldEqual(i1_c->get<0>(), Shape3(x,y,z));
+                    shouldEqual(&i1_c->get<1>(), &a3(x,y,z));
+                    shouldEqual(&i1_c->get<2>(), &a3(x,y,z));
+                    shouldEqual(&get<1>(*i1_c), &a3(x,y,z));
+                    shouldEqual(&get<2>(*i1_c), &a3(x,y,z));
+                }
+                ++county;
+            }
+            ++countz;
+        }
+
+        shouldEqual (countx, 30);
+        shouldEqual (county, 15);
+        shouldEqual (countz, 5);
+        shouldEqual (seqi, a3.end());
+        //
+        //// test direct navigation
+        //traverser3_t i3 = a3.traverser_begin();
+        //shouldEqual(&*i3, &a3[shape3_t(0,0,0)]);
+
+        //i3.dim<2>()++;
+        //i3.dim<1>()++;
+        //i3.dim<0>()++;        
+        //shouldEqual(&*i3, &a3[shape3_t(1,1,1)]);
+
+        //i3.dim<2>()+= 3;
+        //i3.dim<1>()+= 2;
+        //i3.dim<0>()+= 1;        
+        //shouldEqual(&*i3, &a3[shape3_t(2,3,4)]);
+        //shouldEqual(&i3[shape3_t(-2,-3,-4)], &a3[shape3_t(0,0,0)]);
+        //shouldEqual(&*(i3-shape3_t(2,3,4)), &a3[shape3_t(0,0,0)]);
+
+        //i3.dim<2>()--;
+        //i3.dim<1>()--;
+        //i3.dim<0>()--;        
+        //shouldEqual(&*i3, &a3[shape3_t(1,2,3)]);
+
+        //i3.dim<2>()-= 3;
+        //i3.dim<1>()-= 2;
+        //i3.dim<0>()-= 1;        
+        //shouldEqual(&*i3, &a3[shape3_t(0,0,0)]);
+
+        //shouldEqual(&i3[shape3_t(2,3,4)], &a3[shape3_t(2,3,4)]);
+        //shouldEqual(&*(i3+shape3_t(2,3,4)), &i3[shape3_t(2,3,4)]);
+    }
+
     void test_bindOuter ()
     {
         MultiArrayView <2, unsigned char> ba = a3.bindOuter(TinyVector<int, 1>(2));
@@ -1269,9 +1448,9 @@ public:
         
         strided_array_t st = a3.stridearray (shape3_t(3,4,6));
 
-        shouldEqual (st.shape (0), 6);
-        shouldEqual (st.shape (1), 7);
-        shouldEqual (st.shape (2), 8);
+        shouldEqual (st.shape (0), 7);
+        shouldEqual (st.shape (1), 8);
+        shouldEqual (st.shape (2), 9);
         
         // test hierarchical navigation
         typedef strided_array_t::traverser Traverser3;
@@ -1298,9 +1477,9 @@ public:
             ++countz;
         }
 
-        shouldEqual (countx, 336u);
-        shouldEqual (county, 56u);
-        shouldEqual (countz, 8u);
+        shouldEqual (countx, 504u);
+        shouldEqual (county, 72u);
+        shouldEqual (countz, 9u);
   
         // test direct navigation
         strided_array_t::traverser i = st.traverser_begin();        
@@ -1516,7 +1695,7 @@ struct MultiImpexTest
         shouldEqual(result(0,1,2), 3);
         shouldEqual(result(0,1,3), 4);
 
-#ifdef _WIN32
+#ifdef _MSC_VER
         exportVolume(array, VolumeExportInfo("impex\\test", ext2));
         
         importVolume(result, std::string("impex\\test"), std::string(ext2));
@@ -1526,7 +1705,7 @@ struct MultiImpexTest
         shouldEqual(result(0,1,1), 2);
         shouldEqual(result(0,1,2), 3);
         shouldEqual(result(0,1,3), 4);
-#endif // _WIN32
+#endif // _MSC_VER
     }
 
 #if defined(HasTIFF)
@@ -2191,6 +2370,15 @@ struct MultiArrayPointoperatorsTest
         initMultiArrayBorder(vol2, 9, 0);
         shouldEqualSequence(vol2.begin(), vol2.end(), desired_vol2);
 
+        const int desired_asym_img[] ={  0, 0, 0, 0, 0, 0,
+                                         0, 0, 5, 5, 5, 0,
+                                         0, 0, 5, 5, 5, 0,
+                                         0, 0, 5, 5, 5, 0,
+                                         0, 0, 0, 0, 0, 0,
+                                         0, 0, 0, 0, 0, 0};
+        img = 5;
+        initMultiArrayBorder(img, Shape2(2,1), Shape2(1,2), 0);
+        shouldEqualSequence(img.begin(), img.end(), desired_asym_img);
     }
 
     void testInspect()
@@ -2338,14 +2526,14 @@ public:
         t = TOCS;
         std::cerr << "    marray expression: " << t << "\n";
 #endif
-        TIC;
-        typedef array3_type::view_type View;
-        View::iterator wi = ((View &)w).begin(), wend = wi.getEndIterator(),
-                       ui = ((View &)u).begin(), vi = ((View &)v).begin();
-        for(; wi != wend; ++wi, ++ui, ++vi)
-                    *wi = *ui * *vi;
-        t = TOCS;
-        std::cerr << "    StridedScanOrderIterator: " << t << "\n";
+        //TIC;
+        //typedef array3_type::view_type View;
+        //View::iterator wi = ((View &)w).begin(), wend = wi.getEndIterator(),
+        //               ui = ((View &)u).begin(), vi = ((View &)v).begin();
+        //for(; wi != wend; ++wi, ++ui, ++vi)
+        //            *wi = *ui * *vi;
+        //t = TOCS;
+        //std::cerr << "    StridedScanOrderIterator: " << t << "\n";
         TIC;
         typedef CoupledIteratorType<3, scalar_type, scalar_type, scalar_type>::type CI;
         CI i = createCoupledIterator(w, u, v), end = i.getEndIterator();
@@ -2353,31 +2541,47 @@ public:
                     i.get<1>() = i.get<2>() * i.get<3>();
         t = TOCS;
         std::cerr << "    CoupledScanOrderIterator: " << t << "\n";
+        //TIC;
+        //w = u*v;
+        //t = TOCS;
+        //std::cerr << "    multi_math expression: " << t << "\n";
+        //TIC;
+        //w.transpose() = u.transpose()*v.transpose();
+        //t = TOCS;
+        //std::cerr << "    transposed multi_math expression: " << t << "\n";
+        //TIC;
+        //combineTwoMultiArrays(srcMultiArrayRange(u), srcMultiArray(v), destMultiArray(w),
+        //                      Arg1()*Arg2());
+        //t = TOCS;
+        //std::cerr << "    lambda expression: " << t << "\n";
+        //TIC;
+        //combineTwoMultiArrays(srcMultiArrayRange(u.transpose()), srcMultiArray(v.transpose()), destMultiArray(w),
+        //                      Arg1()*Arg2());
+        //t = TOCS;
+        //std::cerr << "    transposed lambda expression: " << t << "\n";
+        //TIC;
+        //for(int z=0; z<size; ++z)
+        //    for(int y=0; y<size; ++y)
+        //        for(int x=0; x<size; ++x)
+        //            w(x,y,z) = u(x,y,z) * v(x,y,z);
+        //t = TOCS;
+        //std::cerr << "    explicit loops: " << t << "\n";
+        i = createCoupledIterator(w, u, v);
         TIC;
-        w = u*v;
-        t = TOCS;
-        std::cerr << "    multi_math expression: " << t << "\n";
-        TIC;
-        w.transpose() = u.transpose()*v.transpose();
-        t = TOCS;
-        std::cerr << "    transposed multi_math expression: " << t << "\n";
-        TIC;
-        combineTwoMultiArrays(srcMultiArrayRange(u), srcMultiArray(v), destMultiArray(w),
-                              Arg1()*Arg2());
-        t = TOCS;
-        std::cerr << "    lambda expression: " << t << "\n";
-        TIC;
-        combineTwoMultiArrays(srcMultiArrayRange(u.transpose()), srcMultiArray(v.transpose()), destMultiArray(w),
-                              Arg1()*Arg2());
+        for(i.dim<2>() = 0; i.dim<2>() <size; ++i.dim<2>())
+            for(i.dim<1>() = 0; i.dim<1>()<size; ++i.dim<1>())
+                for(i.dim<0>() = 0; i.dim<0>()<size; ++i.dim<0>())
+                    i.get<1>() = i.get<2>() * i.get<3>();
         t = TOCS;
-        std::cerr << "    transposed lambda expression: " << t << "\n";
+        std::cerr << "    coupled iterator explicit template loops: " << t << "\n";
+        i = createCoupledIterator(w, u, v);
         TIC;
-        for(int z=0; z<size; ++z)
-            for(int y=0; y<size; ++y)
-                for(int x=0; x<size; ++x)
-                    w(x,y,z) = u(x,y,z) * v(x,y,z);
+        for(i.resetDim(2); i.coord(2) < size; i.incDim(2))
+            for(i.resetDim(1); i.coord(1) < size; i.incDim(1))
+                for(i.resetDim(0); i.coord(0) < size; i.incDim(0))
+                    i.get<1>() = i.get<2>() * i.get<3>();
         t = TOCS;
-        std::cerr << "    explicit loops: " << t << "\n";
+        std::cerr << "    coupled iterator explicit runtime loops: " << t << "\n";
     }
 
     void testBasicArithmetic()
@@ -2861,6 +3065,7 @@ struct MultiArrayTestSuite
         add( testCase( &MultiArrayTest::test_coupled_iterator ) );
         add( testCase( &MultiArrayTest::test_traverser ) );
         add( testCase( &MultiArrayTest::test_const_traverser ) );
+        add( testCase( &MultiArrayTest::test_hierarchical ) );
         add( testCase( &MultiArrayTest::test_bindOuter ) );
         add( testCase( &MultiArrayTest::test_bindInner ) );
         add( testCase( &MultiArrayTest::test_bindInnerAll ) );
diff --git a/test/multiarray/test_chunked.cxx b/test/multiarray/test_chunked.cxx
new file mode 100644
index 0000000..236b4d2
--- /dev/null
+++ b/test/multiarray/test_chunked.cxx
@@ -0,0 +1,1618 @@
+/************************************************************************/
+/*                                                                      */
+/*     Copyright 2013-2014 by Ullrich Koethe                            */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*                                                                      */
+/************************************************************************/
+
+#include <stdio.h>
+
+#include "vigra/unittest.hxx"
+#include "vigra/multi_array.hxx"
+#include "vigra/multi_array_chunked.hxx"
+#ifdef HasHDF5
+#include "vigra/multi_array_chunked_hdf5.hxx"
+#endif
+#include "vigra/functorexpression.hxx"
+#include "vigra/multi_math.hxx"
+#include "vigra/algorithm.hxx"
+#include "vigra/random.hxx"
+#include "vigra/timing.hxx"
+//#include "marray.hxx"
+
+using namespace vigra;
+using namespace vigra::functor;
+
+#define shouldEqualIndexing(N, a, b) \
+{ \
+    MultiCoordinateIterator<N> cccccccc(a.shape()), ccccccccend(cccccccc.getEndIterator()); \
+    for(; cccccccc != ccccccccend; ++cccccccc) \
+        if(a[*cccccccc] != b[*cccccccc]) \
+            shouldEqual(a[*cccccccc], b[*cccccccc]); \
+}
+
+template <class Array>
+class ChunkedMultiArrayTest
+{
+public:
+
+    // typedef typename vigra::detail::ResolveMultiband<T>::type   scalar_type;
+    typedef typename Array::value_type T;
+    typedef MultiArray <3, T> PlainArray;
+    typedef ChunkedArray<3, T> BaseArray;
+    typedef VIGRA_UNIQUE_PTR<BaseArray> ArrayPtr;
+    typedef typename BaseArray::iterator Iterator;
+    
+    static const int channelCount = NumericTraits<T>::isScalar::value 
+                                       ? 1
+                                       : 3;
+    
+    Shape3 shape, chunk_shape;
+    ArrayPtr empty_array, array;
+    PlainArray ref;
+    
+    static const int fill_value = 42;
+
+    ChunkedMultiArrayTest ()
+        : shape(20,21,22),
+          chunk_shape(8),
+          ref(shape)
+    {
+        linearSequence(ref.begin(), ref.end());
+        empty_array = createArray(shape, chunk_shape, (Array *)0, "empty.h5");
+        empty_array->setCacheMaxSize(27);
+        array = createArray(shape, chunk_shape, (Array *)0);
+        linearSequence(array->begin(), array->end());
+    }
+    
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                Shape3 const & chunk_shape,
+                                ChunkedArrayFull<3, T> *,
+                                std::string const & = "chunked_test.h5")
+    {
+        return ArrayPtr(new ChunkedArrayFull<3, T>(shape, ChunkedArrayOptions().fillValue(fill_value)));
+    }
+    
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                Shape3 const & chunk_shape,
+                                ChunkedArrayLazy<3, T> *,
+                                std::string const & = "chunked_test.h5")
+    {
+        return ArrayPtr(new ChunkedArrayLazy<3, T>(shape, chunk_shape, 
+                                                   ChunkedArrayOptions().fillValue(fill_value)));
+    }
+    
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                Shape3 const & chunk_shape,
+                                ChunkedArrayCompressed<3, T> *,
+                                std::string const & = "chunked_test.h5")
+    {
+        return ArrayPtr(new ChunkedArrayCompressed<3, T>(shape, chunk_shape, 
+                                                         ChunkedArrayOptions().fillValue(fill_value)
+                                                                              .compression(LZ4)));
+    }
+    
+#ifdef HasHDF5
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                Shape3 const & chunk_shape,
+                                ChunkedArrayHDF5<3, T> *,
+                                std::string const & name = "chunked_test.h5")
+    {
+        HDF5File hdf5_file(name, HDF5File::New);
+        return ArrayPtr(new ChunkedArrayHDF5<3, T>(hdf5_file, "test", HDF5File::New, 
+                                                   shape, chunk_shape, 
+                                                   ChunkedArrayOptions().fillValue(fill_value)));
+    }
+#endif
+    
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                Shape3 const & chunk_shape,
+                                ChunkedArrayTmpFile<3, T> *,
+                                std::string const & = "chunked_test.h5")
+    {
+        return ArrayPtr(new ChunkedArrayTmpFile<3, T>(shape, chunk_shape, 
+                                                      ChunkedArrayOptions().fillValue(fill_value), ""));
+    }
+    
+    void test_construction ()
+    {
+        bool isFullArray = IsSameType<Array, ChunkedArrayFull<3, T> >::value;
+        
+        should(array->isInside(Shape3(1,2,3)));
+        should(!array->isInside(Shape3(1,23,3)));
+        should(!array->isInside(Shape3(1,2,-3)));
+        
+        shouldEqual(array->shape(), ref.shape());
+        shouldEqual(array->shape(0), ref.shape(0));
+        shouldEqual(array->shape(1), ref.shape(1));
+        shouldEqual(array->shape(2), ref.shape(2));
+        
+        if(isFullArray)
+            shouldEqual(array->chunkArrayShape(), Shape3(1));
+        else
+            shouldEqual(array->chunkArrayShape(), Shape3(3));
+        
+        shouldEqualSequence(array->begin(), array->end(), ref.begin());
+        shouldEqualSequence(array->cbegin(), array->cend(), ref.begin());
+        
+        should(*array == ref);
+        should(*array != ref.subarray(Shape3(1),ref.shape()));
+        
+        shouldEqual(array->getItem(Shape3(1,8,17)), ref[Shape3(1,8,17)]);
+        
+        ref[ref.size()-1] = ref[ref.size()-1] + T(1);
+        should(*array != ref);
+        array->setItem(ref.shape()-Shape3(1), ref[ref.size()-1]);
+        should(*array == ref);
+        
+        if(isFullArray)
+            shouldEqual(empty_array->dataBytes(), ref.size()*sizeof(T));
+        else
+            shouldEqual(empty_array->dataBytes(), 0);
+            
+        PlainArray empty(shape, T(fill_value));
+        // const_iterator should simply use the fill_value_chunk_
+        shouldEqualSequence(empty_array->cbegin(), empty_array->cend(), empty.begin());
+        if(isFullArray)
+            shouldEqual(empty_array->dataBytes(), ref.size()*sizeof(T));
+        else
+            shouldEqual(empty_array->dataBytes(), 0);
+            
+        // non-const iterator should allocate the array and initialize with fill_value_
+        shouldEqualSequence(empty_array->begin(), empty_array->end(), empty.begin());
+        if(IsSameType<Array, ChunkedArrayTmpFile<3, T> >::value)
+            should(empty_array->dataBytes() >= ref.size()*sizeof(T)); // must pad to a full memory page
+        else
+            shouldEqual(empty_array->dataBytes(), ref.size()*sizeof(T));
+        
+        // make sure the central chunk is loaded, so that releaseChunks() will have an effect
+        array->getItem(Shape3(10,10,10));
+        int dataBytesBefore = array->dataBytes();
+        array->releaseChunks(Shape3(5, 0, 3), Shape3(shape[0], shape[1], shape[2]-3), true);
+        if(!isFullArray)
+            should(array->dataBytes() < dataBytesBefore);
+
+        if(IsSameType<Array, ChunkedArrayLazy<3, T> >::value ||
+           IsSameType<Array, ChunkedArrayCompressed<3, T> >::value)
+        {
+            ref.subarray(Shape3(8, 0, 8), Shape3(shape[0], shape[1], 16)) = T(fill_value);
+        }
+        shouldEqualSequence(array->cbegin(), array->cend(), ref.begin());
+
+        // FIXME: test copy construction?
+        
+        // should(array3 != array3.subarray(Shape(1,1,1), Shape(2,2,2)));
+        // should(array3.subarray(Shape(0,0,0), Shape(10,1,1)) != array3.subarray(Shape(0,1,0), Shape(10,2,1)));
+
+        // array3_type a(array3.shape());
+        // linearSequence(a.begin(), a.end());
+        // should(a == array3);
+
+        // for(unsigned int k=0; k<10; ++k)
+            // array3(k,0,0) += 10;
+        // should(array3.subarray(Shape(0,0,0), Shape(10,1,1)) == array3.subarray(Shape(0,1,0), Shape(10,2,1)));
+
+        // MultibandView3 channel_view(a.multiband());
+        // shouldEqual(a.shape(), channel_view.shape());
+        // shouldEqual(a.data(), channel_view.data());
+    }
+
+    void test_assignment()
+    {
+        MultiArrayView <3, T, ChunkedArrayTag> v;
+        should(!v.hasData());    
+        
+        v = array->subarray(Shape3(), ref.shape());
+        should(v.hasData());        
+        
+        MultiArrayView <3, T, ChunkedArrayTag> vc;
+        should(!vc.hasData());
+        
+        vc = v;
+        should(vc.hasData());
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+        
+        vc = T(7);
+        std::vector<T> v7ref(vc.size(), T(7));
+        should(vc.hasData());
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), v7ref.begin());
+        shouldEqualSequence(v.begin(), v.end(), v7ref.begin());
+        
+        vc = ref;
+        should(vc.hasData());
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+        
+        MultiArrayView <3, T, ChunkedArrayTag> vs(array->subarray(Shape3(), Shape3(4)));
+        should(vs.hasData());
+        
+        try
+        {
+            vc = vs;
+            failTest("shape mismatch in assignment failed to throw exception");
+        }
+        catch(PreconditionViolation & e)
+        {
+            std::string expected("\nPrecondition violation!\nMultiArrayView::operator=(): shape mismatch.\n"),
+                        actual(e.what());
+            shouldEqual(actual.substr(0, expected.size()), expected);
+        }
+        
+        vc += T(1);
+        ref += T(1);
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+        
+        vc += v;
+        ref *= T(2);
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+         
+        vc += T(42);
+        ref += T(42);
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+        
+        vc -= T(42);
+        ref -= T(42);
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+       
+        ref /= T(2);
+        vc -= ref;
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+        
+        vc *= v;
+        ref *= ref;
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+        
+        vc *= T(4);
+        ref *= T(4);
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+         
+        vc /= T(4);
+        ref /= T(4);
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+       
+        vc /= PlainArray(ref.shape(), T(1));
+        shouldEqual(vc.shape(), ref.shape());
+        shouldEqualSequence(vc.begin(), vc.end(), ref.begin());
+    }
+
+    void test_bindAt ()
+    {
+        MultiArrayView <2, T, ChunkedArrayTag> v = array->bindAt (1, 4);
+        MultiArrayView <2, T, ChunkedArrayTag> vv = array->template bind<1>(4);
+        MultiArrayView <2, T, StridedArrayTag> vr = ref.bindAt (1, 4);
+        
+        shouldEqual(v.shape(), vr.shape());
+        shouldEqual(vv.shape(), vr.shape());
+        should(v == vr);
+        should(vv == vr);
+        shouldEqualSequence(v.begin(), v.end(), vr.begin());
+        shouldEqualIndexing(2, v, vr);
+        
+        MultiArrayView <2, T, ChunkedArrayTag> vt = v.transpose();
+        MultiArrayView <2, T, StridedArrayTag> vtr = vr.transpose();
+        
+        shouldEqual(vt.shape(), vtr.shape());
+        should(vt == vtr);
+        shouldEqualSequence(vt.begin(), vt.end(), vtr.begin());
+        shouldEqualIndexing(2, vt, vtr);
+        
+        MultiArrayView <1, T, ChunkedArrayTag> v1 = v.bindAt (0, 11);
+        MultiArrayView <1, T, StridedArrayTag> v1r = vr.bindAt (0, 11);
+        
+        shouldEqual(v1.shape(), v1r.shape());
+        should(v1 == v1r);
+        shouldEqualSequence(v1.begin(), v1.end(), v1r.begin());
+        shouldEqualIndexing(1, v1, v1r);
+        
+        MultiArrayView <1, T, ChunkedArrayTag> v1t = v1.transpose();
+        
+        shouldEqual(v1t.shape(), v1r.shape());
+        should(v1t == v1r);
+        shouldEqualSequence(v1t.begin(), v1t.end(), v1r.begin());
+        shouldEqualIndexing(1, v1t, v1r);
+    }
+    
+    void test_bindInner ()
+    {
+        MultiArrayView <2, T, ChunkedArrayTag> v = array->bindInner(2);
+        MultiArrayView <2, T, StridedArrayTag> vr = ref.bindInner(2);
+        shouldEqual(v.shape(), vr.shape());
+        should(v == vr);
+        
+        TinyVector <int, 2> inner_indices (2, 5);
+        MultiArrayView <1, T, ChunkedArrayTag> v1 = array->bindInner(inner_indices);
+        MultiArrayView <1, T, StridedArrayTag> v1r = ref.bindInner(inner_indices);
+        shouldEqual(v1.shape(), v1r.shape());
+        should(v1 == v1r);
+        
+        MultiArrayView <1, T, ChunkedArrayTag> v21 = v.bindInner(5);
+        shouldEqual(v21.shape(), v1r.shape());
+        should(v21 == v1r);
+    }
+    
+    void test_bindOuter ()
+    {
+        MultiArrayView <2, T, ChunkedArrayTag> v = array->bindOuter(2);
+        MultiArrayView <2, T, StridedArrayTag> vr = ref.bindOuter(2);
+        shouldEqual(v.shape(), vr.shape());
+        should(v == vr);
+        
+        TinyVector <int, 2> inner_indices (5, 2);
+        MultiArrayView <1, T, ChunkedArrayTag> v1 = array->bindOuter(inner_indices);
+        MultiArrayView <1, T, StridedArrayTag> v1r = ref.bindOuter(inner_indices);
+        shouldEqual(v1.shape(), v1r.shape());
+        should(v1 == v1r);
+        
+        MultiArrayView <1, T, ChunkedArrayTag> v21 = v.bindOuter(5);
+        shouldEqual(v21.shape(), v1r.shape());
+        should(v21 == v1r);
+    }
+
+    void test_subarray ()
+    {
+        {
+            Shape3 start, stop(ref.shape());  // empty array
+            bool isFullArray = IsSameType<Array, ChunkedArrayFull<3, T> >::value;
+        
+            MultiArrayView <3, T const, ChunkedArrayTag> vc(empty_array->const_subarray(start, stop));
+
+            MultiArray <3, T> c(stop-start);
+            empty_array->checkoutSubarray(start, c);
+            
+            if(isFullArray)
+                shouldEqual(empty_array->dataBytes(), ref.size()*sizeof(T));
+            else
+                shouldEqual(empty_array->dataBytes(), 0);
+                
+            PlainArray empty(shape, T(fill_value));
+            shouldEqualSequence(vc.begin(), vc.end(), empty.begin());
+            shouldEqualSequence(c.begin(), c.end(), empty.begin());
+            
+            MultiArrayView <3, T, ChunkedArrayTag> v(empty_array->subarray(start, stop));
+            if(IsSameType<Array, ChunkedArrayTmpFile<3, T> >::value)
+                should(empty_array->dataBytes() >= ref.size()*sizeof(T)); // must pad to a full memory page
+            else
+                shouldEqual(empty_array->dataBytes(), ref.size()*sizeof(T));
+            shouldEqualSequence(v.begin(), v.end(), empty.begin());
+        }
+        
+        {
+            Shape3 start, stop(ref.shape());  // whole array
+            MultiArrayView <3, T, ChunkedArrayTag> v(array->subarray(start, stop));
+            MultiArrayView <3, T, ChunkedArrayTag> vt(v.transpose());
+
+            MultiArray <3, T> c(stop-start);
+            array->checkoutSubarray(start, c);
+            
+            MultiArrayView <3, T, StridedArrayTag> vr = ref.subarray(start, stop);
+            MultiArrayView <3, T, StridedArrayTag> vtr = vr.transpose();
+            
+            shouldEqual(v.shape(), vr.shape());
+            should(v == vr);
+            shouldEqualSequence(v.begin(), v.end(), vr.begin());
+            shouldEqualIndexing(3, v, vr);
+            
+            shouldEqual(vt.shape(), vtr.shape());
+            should(vt == vtr);
+            shouldEqualSequence(vt.begin(), vt.end(), vtr.begin());
+            shouldEqualIndexing(3, vt, vtr);
+            
+            shouldEqual(c.shape(), vr.shape());
+            should(c == vr);
+            shouldEqualSequence(c.begin(), c.end(), vr.begin());
+            shouldEqualIndexing(3, c, vr);
+        }
+        
+        {
+            Shape3 start(3,2,1), stop(4,5,6);  // single chunk
+            MultiArrayView <3, T, ChunkedArrayTag> v(array->subarray(start, stop));
+            MultiArrayView <3, T, ChunkedArrayTag> vt(v.transpose());
+
+            MultiArray <3, T> c(stop-start);
+            array->checkoutSubarray(start, c);
+            
+            MultiArrayView <3, T, StridedArrayTag> vr = ref.subarray(start, stop);
+            MultiArrayView <3, T, StridedArrayTag> vtr = vr.transpose();
+            
+            shouldEqual(v.shape(), vr.shape());
+            should(v == vr);
+            shouldEqualSequence(v.begin(), v.end(), vr.begin());
+            shouldEqualIndexing(3, v, vr);
+            
+            shouldEqual(vt.shape(), vtr.shape());
+            should(vt == vtr);
+            shouldEqualSequence(vt.begin(), vt.end(), vtr.begin());
+            shouldEqualIndexing(3, vt, vtr);
+            
+            shouldEqual(c.shape(), vr.shape());
+            should(c == vr);
+            shouldEqualSequence(c.begin(), c.end(), vr.begin());
+            shouldEqualIndexing(3, c, vr);
+        }
+        
+        {
+            Shape3 start(7,6,5), stop(9,10,11); // across chunk borders
+            MultiArrayView <3, T, ChunkedArrayTag> v(array->subarray(start, stop));
+            MultiArrayView <3, T, ChunkedArrayTag> vt(v.transpose());
+            
+            MultiArray <3, T> c(stop-start);
+            array->checkoutSubarray(start, c);
+            
+            MultiArrayView <3, T, StridedArrayTag> vr = ref.subarray(start, stop);
+            
+            shouldEqual(v.shape(), vr.shape());
+            should(v == vr);
+            shouldEqualSequence(v.begin(), v.end(), vr.begin());
+            shouldEqualIndexing(3, v, vr);
+            
+            shouldEqual(c.shape(), vr.shape());
+            should(c == vr);
+            shouldEqualSequence(c.begin(), c.end(), vr.begin());
+            shouldEqualIndexing(3, c, vr);
+        }
+    }
+    
+    void test_iterator ()
+    {
+        Shape3 s(ref.shape());
+        typedef typename ChunkedArray<3, T>::iterator Iterator;
+        MultiArrayView <3, T, ChunkedArrayTag> v(array->subarray(Shape3(), s));
+        Iterator i1 = array->begin();
+        Iterator iend = array->end();
+        MultiCoordinateIterator<3> c(s),
+                                   cend = c.getEndIterator();
+
+        should(i1.isValid() && !i1.atEnd());
+        should(!iend.isValid() && iend.atEnd());
+        should(iend.getEndIterator() == iend);
+        
+        shouldEqual(i1.point(), *c);
+        shouldEqual((i1+0).point(), c[0]);
+        shouldEqual((i1+1).point(), c[1]);
+        shouldEqual((i1+2).point(), c[2]);
+        shouldEqual((i1+3).point(), c[3]);
+        shouldEqual((i1+6).point(), c[6]);
+        shouldEqual((i1+7).point(), c[7]);
+        shouldEqual((i1+9).point(), c[9]);
+
+        shouldEqual((iend-1).point(), *(cend-1));
+        shouldEqual((iend-2).point(), *(cend-2));
+        shouldEqual((iend-3).point(), *(cend-3));
+        shouldEqual((iend-7).point(), *(cend-7));
+        shouldEqual((iend-8).point(), *(cend-8));
+        shouldEqual((iend-10).point(), *(cend-10));
+
+        shouldEqual(&i1[0], &v[Shape3(0,0,0)]);
+        shouldEqual(&i1[1], &v[Shape3(1,0,0)]);
+        shouldEqual(&i1[s[0]], &v[Shape3(0,1,0)]);
+        shouldEqual(&i1[s[0]*9+1], &v[Shape3(1,9,0)]);
+        shouldEqual(&i1[s[0]*s[1]], &v[Shape3(0,0,1)]);
+        shouldEqual(&i1[s[0]*s[1]*9+1], &v[Shape3(1,0,9)]);
+        shouldEqual(&i1[(s[0]+1)*s[1]], &v[Shape3(1,1,1)]);
+
+        shouldEqual(&*(i1+0), &v[Shape3(0,0,0)]);
+        shouldEqual(&*(i1+1), &v[Shape3(1,0,0)]);
+        shouldEqual(&*(i1+s[0]), &v[Shape3(0,1,0)]);
+        shouldEqual(&*(i1+s[0]*9+1), &v[Shape3(1,9,0)]);
+        shouldEqual(&*(i1+s[0]*s[1]), &v[Shape3(0,0,1)]);
+        shouldEqual(&*(i1+s[0]*s[1]*9+1), &v[Shape3(1,0,9)]);
+        shouldEqual(&*(i1+(s[0]+1)*s[1]), &v[Shape3(1,1,1)]);
+
+        shouldEqual(&*(i1+Shape3(0,0,0)), &v[Shape3(0,0,0)]);
+        shouldEqual(&*(i1+Shape3(1,0,0)), &v[Shape3(1,0,0)]);
+        shouldEqual(&*(i1+Shape3(0,1,0)), &v[Shape3(0,1,0)]);
+        shouldEqual(&*(i1+Shape3(1,11,0)), &v[Shape3(1,11,0)]);
+        shouldEqual(&*(i1+Shape3(0,0,1)), &v[Shape3(0,0,1)]);
+        shouldEqual(&*(i1+Shape3(1,0,11)), &v[Shape3(1,0,11)]);
+        shouldEqual(&*(i1+Shape3(1,1,1)), &v[Shape3(1,1,1)]);
+
+        shouldEqual(&*(iend-1),  &v[Shape3(19,20,21)]);
+        shouldEqual(&*(iend-2),  &v[Shape3(18,20,21)]);
+        shouldEqual(&*(iend-10), &v[Shape3(10,20,21)]);
+        shouldEqual(&*(iend-s[0]-1),  &v[Shape3(19,19,21)]);
+
+        shouldEqual(&iend[-1], &v[Shape3(19,20,21)]);
+        shouldEqual(&iend[-2], &v[Shape3(18,20,21)]);
+        shouldEqual(&iend[-10], &v[Shape3(10,20,21)]);
+        shouldEqual(&iend[-s[0]-1], &v[Shape3(19,19,21)]);
+        
+        Iterator i2;
+        i2 = iend;
+        should(i2 == iend);
+        should(!i2.isValid() && i2.atEnd());
+        --i2;
+        should(i2.isValid() && !i2.atEnd());
+        should(i2.getEndIterator() == iend);
+        shouldEqual(i2.point(), Shape3(19,20,21));
+        shouldEqual(&*i2, &v[Shape3(19,20,21)]);
+        for(int k=0; k<20; ++k)
+            --i2;
+        should(i2.isValid() && !i2.atEnd());
+        should(i2.getEndIterator() == iend);
+        shouldEqual(i2.point(), Shape3(19,19,21));
+        shouldEqual(&*i2, &v[Shape3(19,19,21)]);
+        for(int k=0; k<420; ++k)
+            --i2;
+        should(i2.isValid() && !i2.atEnd());
+        should(i2.getEndIterator() == iend);
+        shouldEqual(i2.point(), Shape3(19,19,20));
+        shouldEqual(&*i2, &v[Shape3(19,19,20)]);
+
+        i2 = iend-1;
+        shouldEqual(&*(i2-Shape3(0,0,0)), &v[Shape3(19,20,21)]);
+        shouldEqual(&*(i2-Shape3(1,0,0)), &v[Shape3(18,20,21)]);
+        shouldEqual(&*(i2-Shape3(0,1,0)), &v[Shape3(19,19,21)]);
+        shouldEqual(&*(i2-Shape3(9,1,0)), &v[Shape3(10,19,21)]);
+        shouldEqual(&*(i2-Shape3(0,0,1)), &v[Shape3(19,20,20)]);
+        shouldEqual(&*(i2-Shape3(9,0,1)), &v[Shape3(10,20,20)]);
+        shouldEqual(&*(i2-Shape3(9,9,1)), &v[Shape3(10,11,20)]);
+        shouldEqual(&*(i2-Shape3(9,9,9)), &v[Shape3(10,11,12)]);
+
+        unsigned int count = 0;
+        Shape3 p;
+        i2 = array->begin();
+        Iterator i3 = array->begin();
+        Iterator i4 = array->begin();
+        Iterator i5 = array->begin();
+        Iterator i6 = array->begin();
+
+        for (p[2]=0, i3.resetDim(2), i4.setDim(2, 0), i5.template dim<2>() = 0, i6.resetDim(2); 
+                i3.point(2) != s[2]; 
+                i3.incDim(2), i4.addDim(2, 1), ++i5.template dim<2>(), i6.template dim<2>() += 1, ++p[2]) 
+        {
+            for (p[1]=0, i3.resetDim(1), i4.setDim(1, 0), i5.template dim<1>() = 0, i6.resetDim(1); 
+                    i3.point(1) != s[1]; 
+                    i3.incDim(1), i4.addDim(1, 1), ++i5.template dim<1>(), i6.template dim<1>() += 1, ++p[1]) 
+            {
+                for (p[0]=0, i3.resetDim(0), i4.setDim(0, 0), i5.template dim<0>() = 0, i6.resetDim(0); 
+                        i3.point(0) != s[0]; 
+                        i3.incDim(0), i4.addDim(0, 1), ++i5.template dim<0>(), i6.template dim<0>() += 1, ++p[0], ++i1, ++c, i2 += 1, ++count)
+                {
+                    shouldEqual(&*i1, &v[p]);
+                    shouldEqual(&*i2, &v[p]);
+                    shouldEqual(&*i3, &v[p]);
+                    shouldEqual(&*i4, &v[p]);
+                    shouldEqual(&*i5, &v[p]);
+                    shouldEqual(&*i6, &v[p]);
+                    shouldEqual(i1.operator->(), &v[p]);
+                    shouldEqual(i2.operator->(), &v[p]);
+                    shouldEqual(*c, p);
+
+                    shouldEqual(i1.point(), p);
+                    shouldEqual(i2.point(), p);
+                    shouldEqual(i3.point(), p);
+                    shouldEqual(i4.point(), p);
+                    shouldEqual(i5.point(), p);
+                    shouldEqual(i6.point(), p);
+
+                    shouldEqual(i1.index(), count);
+                    shouldEqual(i2.index(), count);
+                    shouldEqual(i3.index(), count);
+                    shouldEqual(i4.index(), count);
+                    shouldEqual(i5.index(), count);
+                    shouldEqual(i6.index(), count);
+
+                    should(i1 != iend);
+                    should(!(i1 == iend));
+                    should(i1 < iend);
+                    should(i1 <= iend);
+                    should(!(i1 > iend));
+                    should(!(i1 >= iend));
+
+                    should(i5.template dim<2>() == p[2]);
+                    should(i5.template dim<1>() == p[1]);
+                    should(i5.template dim<0>() == p[0]);
+                    should(i5.template dim<2>() != s[2]);
+                    should(i5.template dim<1>() != s[1]);
+                    should(i5.template dim<0>() != s[0]);
+                    should(i5.template dim<2>() <= p[2]);
+                    should(i5.template dim<1>() <= p[1]);
+                    should(i5.template dim<0>() <= p[0]);
+                    should(i5.template dim<2>() < s[2]);
+                    should(i5.template dim<1>() < s[1]);
+                    should(i5.template dim<0>() < s[0]);
+                    should(i5.template dim<2>() >= 0);
+                    should(i5.template dim<1>() >= 0);
+                    should(i5.template dim<0>() >= 0);
+                    shouldNot(i5.template dim<2>() > s[2]);
+                    shouldNot(i5.template dim<1>() > s[1]);
+                    shouldNot(i5.template dim<0>() > s[0]);
+
+                    shouldEqual(iend - i1, v.size() - count);
+
+                    bool atBorder = p[0] == 0 || p[0] == s[0]-1 || p[1] == 0 || p[1] == s[1]-1 ||
+                                    p[2] == 0 || p[2] == s[2]-1;
+                    if(!atBorder)
+                    {
+                        should(!i1.atBorder());
+                        should(!i2.atBorder());
+                    }
+                    else
+                    {
+                        should(i1.atBorder());
+                        should(i2.atBorder());
+                    }
+                }
+            }
+        }
+
+        should(c == cend);
+        should(i1 == iend);
+        should(!(i1 != iend));
+        should(!(i1 < iend));
+        should(i1 <= iend);
+        should(!(i1 > iend));
+        should(i1 >= iend);
+
+        should(i2 == iend);
+        should(!(i2 != iend));
+        should(!(i2 < iend));
+        should(i2 <= iend);
+        should(!(i2 > iend));
+        should(i2 >= iend);
+
+        shouldEqual(iend - i1, 0);
+        shouldEqual(iend - i2, 0);
+        shouldEqual (count, v.size());
+
+        --i1;
+        i2 -= 1;
+        shouldEqual(&*i1, &v[Shape3(19,20,21)]);
+        shouldEqual(&*i2, &v[Shape3(19,20,21)]);
+    }
+    
+    void testChunkIterator()
+    {
+        Shape3 start(5,0,3), stop(shape[0], shape[1], shape[2]-3);
+        MultiArrayView <3, T, ChunkedArrayTag> v(array->subarray(Shape3(), shape));
+        
+        typename Array::chunk_iterator i = array->chunk_begin(start, stop),
+                                       end = array->chunk_end(start, stop);
+        typename MultiArrayView <3, T, ChunkedArrayTag>::chunk_const_iterator 
+                                       vi = v.chunk_cbegin(start, stop),
+                                       vend = v.chunk_cend(start, stop);
+        int count = -1;
+        for(; i != end; ++i, ++vi, --count)
+        {
+            shouldEqual(i->data(), i[0].data());
+            shouldEqual(i->data(), vi->data());
+            
+            *i = T(count);
+            ref.subarray(i.chunkStart(), i.chunkStop()) = T(count);
+            should(*vi == ref.subarray(i.chunkStart(), i.chunkStop()));
+        }
+        should(vi == vend);
+        shouldEqualSequence(array->cbegin(), array->cend(), ref.begin());
+        
+        for(;;)
+        {
+            --i;
+            --vi;
+            ++count;
+            shouldEqual(i->data(), i[0].data());
+            shouldEqual(i->data(), vi->data());
+            shouldEqual((*i)[Shape3()], T(count));
+            *i = T(fill_value);
+            if(i.scanOrderIndex() == 0)
+                break;
+        }
+        ref.subarray(start, stop) = T(fill_value);
+        shouldEqualSequence(array->cbegin(), array->cend(), ref.begin());
+    }
+    
+    static void testMultiThreadedRun(BaseArray * v, int startIndex, int d, int * go)
+    {
+        while(*go == 0)
+            threading::this_thread::yield();
+            
+        Shape3 s = v->shape();
+        int sliceSize = s[0]*s[1];
+        
+        Iterator bi(v->begin());
+        T count(startIndex*sliceSize), start((d-1)*sliceSize), inc(1);
+        for(bi.setDim(2,startIndex); bi.coord(2) < s[2]; bi.addDim(2, d), count += start)
+            for(bi.setDim(1,0); bi.coord(1) < s[1]; bi.incDim(1))
+                for(bi.setDim(0,0); bi.coord(0) < s[0]; bi.incDim(0), count += inc)
+                {
+                    *bi = count;
+                }
+    }
+
+    void testMultiThreaded()
+    {
+        array.reset(0); // close the file if backend is HDF5
+        ArrayPtr a = createArray(Shape3(200, 201, 202), Shape3(), (Array *)0);
+    
+        int go = 0;
+        
+        threading::thread t1(testMultiThreadedRun, a.get(), 0, 4, &go);
+        threading::thread t2(testMultiThreadedRun, a.get(), 1, 4, &go);
+        threading::thread t3(testMultiThreadedRun, a.get(), 2, 4, &go);
+        threading::thread t4(testMultiThreadedRun, a.get(), 3, 4, &go);
+     
+        go = 1;
+     
+        t4.join();
+        t3.join();
+        t2.join();
+        t1.join();
+        
+        PlainArray ref(a->shape());
+        linearSequence(ref.begin(), ref.end());
+        
+        shouldEqualSequence(a->begin(), a->end(), ref.begin());
+    }
+        
+    // void testIsUnstrided()
+    // {
+        // typedef difference3_type Shape;
+
+        // should(array3.isUnstrided());
+        // should(array3.isUnstrided(0));
+        // should(array3.isUnstrided(1));
+        // should(array3.isUnstrided(2));
+        // should(array3.bindOuter(0).isUnstrided());
+        // should(!array3.bindInner(0).isUnstrided());
+        // should(!array3.bindAt(1, 0).isUnstrided());
+        // should(array3.bindAt(1, 0).isUnstrided(0));
+        // should(!array3.subarray(Shape(), array3.shape()-Shape(1)).isUnstrided());
+        // should(!array3.subarray(Shape(), array3.shape()-Shape(1)).isUnstrided(1));
+        // should(array3.subarray(Shape(), array3.shape()-Shape(1)).isUnstrided(0));
+        // should(!array3.subarray(Shape(), array3.shape()-Shape(0,2,2)).isUnstrided());
+        // should(array3.subarray(Shape(), array3.shape()-Shape(0,2,2)).isUnstrided(1));
+        // should(array3.subarray(Shape(), array3.shape()-Shape(0,2,2)).isUnstrided(0));
+    // }
+
+    // void testMethods ()
+    // {
+        // shouldEqual(array3.squaredNorm(), 332833500);
+        
+        // shouldEqual(array3.norm(), std::sqrt(332833500.0));
+        // shouldEqual(array3.norm(0), 999.0);
+        // shouldEqual(array3.norm(1), 499500.0);
+        // shouldEqualTolerance(array3.norm(2, false), std::sqrt(332833500.0), 1e-14);
+        
+        // difference3_type first(0,0,0), last(1,1,1);
+        // shouldEqual(array3.subarray(first, last).norm(), 0.0);
+        // shouldEqual(array3.subarray(first, last).norm(0), 0.0);
+        // shouldEqual(array3.subarray(first, last).norm(1), 0.0);
+        // shouldEqual(array3.subarray(first, last).norm(2, false), 0.0);
+
+        // shouldEqual(array3.squaredNorm(), squaredNorm(array3));
+        // shouldEqual(array3.norm(), vigra::norm(array3));
+
+        // should(array3.any());
+        // should(!array3.subarray(first, last).any());
+        // should(!array3.all());
+        // should(array3.subarray(last, array3.shape()).all());
+
+        // shouldEqual(array3.template sum<int>(), 499500);
+        // shouldEqual(array3.subarray(Shape3(1,1,1),Shape3(3,3,2)).template product<int>(), 183521184);
+
+        // Shape3 reducedShape(1, 1, array3.shape(2));
+        // array3_type reducedSums(reducedShape);
+        // array3.sum(reducedSums);
+        // int res = 4950;
+        // for(int k=0; k<reducedShape[2]; ++k, res += 10000)
+            // shouldEqual(reducedSums(0,0,k), res);
+
+        // scalar_type minimum, maximum;
+        // array3.minmax(&minimum, &maximum);
+        // shouldEqual(minimum, 0);
+        // shouldEqual(maximum, array3.size()-1);
+
+        // double mean, variance;
+        // array3.meanVariance(&mean, &variance);
+        // shouldEqual(mean, 499.5);
+        // shouldEqual(variance, 83333.25);
+    // }
+
+    // void test_expandElements()
+    // {
+        // using namespace multi_math;
+
+        // MultiArray<3, TinyVector<int, 3> > a(Shape3(4,3,2));
+        // a.init(TinyVector<int, 3>(1,2,3));
+
+        // MultiArrayView<4, int, StridedArrayTag> ex = a.expandElements(0);
+        // MultiArrayView<4, int, StridedArrayTag>::iterator i = ex.begin();
+        // while(i != ex.end())
+        // {
+            // shouldEqual(*i, 1); ++i;
+            // shouldEqual(*i, 2); ++i;
+            // shouldEqual(*i, 3); ++i;
+        // }
+
+        // MultiArrayView<4, int, StridedArrayTag> ex2 = a.expandElements(3);
+        // i = ex2.begin();
+        // for(int k=0; k < a.size(); ++i, ++k)
+            // shouldEqual(*i, 1);
+        // for(int k=0; k < a.size(); ++i, ++k)
+            // shouldEqual(*i, 2);
+        // for(int k=0; k < a.size(); ++i, ++k)
+            // shouldEqual(*i, 3);
+
+        // MultiArray<3, bool> b = (a.bindElementChannel(0) == 1);
+        // should(b.all());
+        // b = (a.bindElementChannel(1) == 2);
+        // should(b.all());
+        // b = (a.bindElementChannel(2) == 3);
+        // should(b.all());
+    // }
+};
+
+// struct MultiArrayPointoperatorsTest
+// {
+
+    // typedef float PixelType;
+    // typedef MultiArray<3,PixelType> Image3D;
+    // typedef MultiArrayView<3,PixelType> View3D;
+    // typedef Image3D::difference_type Size3;
+    // typedef MultiArray<1,PixelType> Image1D;
+    // typedef Image1D::difference_type Size1;
+
+    // Image3D img;
+
+    // MultiArrayPointoperatorsTest()
+    // : img(Size3(5,4,3))
+    // {
+        // int i;
+        // PixelType c = 0.1f;
+        // for(i=0; i<img.elementCount(); ++i, ++c)
+            // img.data()[i] = c;
+    // }
+
+    // void testInit()
+    // {
+        // Image3D res(img.shape());
+        // const Image3D::value_type ini = 1.1f;
+        // should(res.shape() == Size3(5,4,3));
+
+        // initMultiArray(destMultiArrayRange(res), ini);
+
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), ini);
+
+        // using namespace multi_math;
+        // should(all(res == ini));
+
+        // initMultiArray(res, 2.2f);
+        // should(all(res == 2.2f));
+
+        // res = 3.3f;
+        // should(all(res == 3.3f));
+
+        // res.init(4.4f);
+        // should(all(res == 4.4f));
+    // }
+
+    // void testCopy()
+    // {
+        // Image3D res(img.shape(), 1.0), res1(img.shape(), 1.0);
+        
+        // copyMultiArray(srcMultiArrayRange(img), destMultiArray(res));
+        // copyMultiArray(img, res1);
+
+        // should(img == res);
+        // should(img == res1);
+    // }
+
+    // void testCopyOuterExpansion()
+    // {
+        // Image3D res(img.shape());
+
+        // copyMultiArray(img.subarray(Size3(0,0,0), Size3(5,1,1)), res);
+        
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), img(x,0,0));
+    // }
+
+    // void testCopyInnerExpansion()
+    // {
+        // Image3D res(img.shape());
+
+        // copyMultiArray(img.subarray(Size3(0,0,0), Size3(1,1,3)), res);
+        
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), img(0,0,z));
+    // }
+
+    // void testTransform()
+    // {
+        // Image3D res(img.shape()), res1(img.shape());
+        // transformMultiArray(srcMultiArrayRange(img), destMultiArray(res),
+                            // Arg1() + Arg1());
+        // transformMultiArray(img, res1, Arg1() + Arg1());
+        
+        // using namespace multi_math;
+        // should(all(2.0*img == res));
+        // should(all(2.0*img == res1));
+    // }
+
+    // void testTransformOuterExpand()
+    // {
+        // Image3D res(img.shape());
+        // transformMultiArray(img.subarray(Size3(0,0,0), Size3(5,1,1)), res,
+                            // Arg1() + Arg1());
+        
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), 2.0*img(x,0,0));
+    // }
+
+    // void testTransformInnerExpand()
+    // {
+        // Image3D res(img.shape());
+
+        // transformMultiArray(img.subarray(Size3(0,0,0), Size3(1,1,3)), res,
+                            // Arg1() + Arg1());
+        
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), 2.0*img(0,0,z));
+    // }
+
+    // void testTransformOuterReduce()
+    // {
+        // Image3D res(Size3(5,1,1));
+
+        // transformMultiArray(img, res, reduceFunctor(Arg1() + Arg2(), 0.0));
+        
+        // int x,y,z;
+        // for(x=0; x<img.shape(0); ++x)
+        // {
+            // double sum = 0.0;
+            // for(y=0; y<img.shape(1); ++y)
+                // for(z=0; z<img.shape(2); ++z)
+                    // sum += img(x,y,z);
+            // shouldEqual(res(x,0,0), sum);
+        // }
+        
+        // Image1D res1(Size1(5));
+        // MultiArrayView<3,PixelType> res3 = res1.insertSingletonDimension(1).insertSingletonDimension(2);
+        // transformMultiArray(img, res3, FindSum<PixelType>());
+        // shouldEqualSequenceTolerance(res1.data(), res1.data()+5, res.data(), 1e-7);       
+    // }
+
+    // void testTransformInnerReduce()
+    // {
+        // Image3D res(Size3(1,1,3));
+        
+        // transformMultiArray(img, res, reduceFunctor(Arg1() + Arg2(), 0.0));
+        
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+        // {
+            // double sum = 0.0;
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // sum += img(x,y,z);
+            // shouldEqual(res(0,0,z), sum);
+        // }
+        
+        // Image1D res1(Size1(3));
+        // MultiArrayView<3,PixelType> res3 = res1.insertSingletonDimension(0).insertSingletonDimension(0);
+        // transformMultiArray(img, res3, FindSum<PixelType>());
+        // shouldEqualSequenceTolerance(res1.data(), res1.data()+3, res.data(), 1e-6);       
+    // }
+
+    // void testCombine2()
+    // {
+        // Image3D res(img.shape()), res1(img.shape());
+        
+        // combineTwoMultiArrays(srcMultiArrayRange(img), srcMultiArray(img), 
+                              // destMultiArray(res),
+                              // Arg1() + Arg2());
+        // combineTwoMultiArrays(img, img, res1, Arg1() + Arg2());
+        
+        // using namespace multi_math;
+        // should(all(2.0*img == res));
+        // should(all(2.0*img == res1));
+    // }
+
+    // void testCombine2OuterExpand()
+    // {
+        // Image3D res(img.shape());
+        
+        // combineTwoMultiArrays(img.subarray(Size3(0,0,0), Size3(5,1,1)), img, res,
+                              // Arg1() + Param(2.0)*Arg2());       
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), 2.0*img(x,y,z) + img(x,0,0));
+
+        // combineTwoMultiArrays(img, img.subarray(Size3(0,0,0), Size3(5,1,1)), res,
+                              // Arg1() + Param(2.0)*Arg2());       
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), img(x,y,z) + 2.0*img(x,0,0));
+
+        // View3D view = img.subarray(Size3(0,0,0), Size3(5,1,1));
+        // combineTwoMultiArrays(srcMultiArrayRange(view), srcMultiArrayRange(view), 
+                              // destMultiArrayRange(res),
+                              // Arg1() + Param(2.0)*Arg2());       
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), 3.0*img(x,0,0));
+    // }
+
+    // void testCombine2InnerExpand()
+    // {
+        // Image3D res(img.shape());
+        
+        // View3D view = img.subarray(Size3(0,0,0), Size3(1,1,3));
+        // combineTwoMultiArrays(view, img, res,
+                              // Arg1() + Param(2.0)*Arg2());       
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), 2.0*img(x,y,z) + img(0,0,z));
+
+        // combineTwoMultiArrays(img, view, res,
+                              // Arg1() + Param(2.0)*Arg2());       
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), img(x,y,z) + 2.0*img(0,0,z));
+
+        // combineTwoMultiArrays(srcMultiArrayRange(view), srcMultiArrayRange(view), 
+                              // destMultiArrayRange(res),
+                              // Arg1() + Param(2.0)*Arg2());       
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // shouldEqual(res(x,y,z), 3.0*img(0,0,z));
+    // }
+
+    // void testCombine2OuterReduce()
+    // {
+        // Image3D res(Size3(5,1,1));
+        
+        // combineTwoMultiArrays(img, img, res,
+                              // reduceFunctor(Arg1() + Arg2() + Arg3(), 0.0));
+        
+        // int x,y,z;
+        // for(x=0; x<img.shape(0); ++x)
+        // {
+            // double sum = 0.0;
+            // for(y=0; y<img.shape(1); ++y)
+                // for(z=0; z<img.shape(2); ++z)
+                    // sum += img(x,y,z);
+            // shouldEqual(res(x,0,0), 2.0*sum);
+        // }
+    // }
+
+    // void testCombine2InnerReduce()
+    // {
+        // Image3D res(Size3(1,1,3));
+        
+        // combineTwoMultiArrays(img, img, res,
+                              // reduceFunctor(Arg1() + Arg2() + Arg3(), 0.0));
+        
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+        // {
+            // double sum = 0.0;
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                    // sum += img(x,y,z);
+            // shouldEqual(res(0,0,z), 2.0*sum);
+        // }
+    // }
+
+    // void testCombine3()
+    // {
+        // Image3D res(img.shape()), res1(img.shape());
+        
+        // combineThreeMultiArrays(srcMultiArrayRange(img), 
+                                // srcMultiArray(img), srcMultiArray(img), 
+                                // destMultiArray(res),
+                                // Arg1() + Arg2() + Arg3());
+        // combineThreeMultiArrays(img, img, img, res1,
+                                // Arg1() + Arg2() + Arg3());
+
+        // int x,y,z;
+        // for(z=0; z<img.shape(2); ++z)
+            // for(y=0; y<img.shape(1); ++y)
+                // for(x=0; x<img.shape(0); ++x)
+                // {
+                    // shouldEqual(res(x,y,z), 3.0*img(x,y,z));
+                    // shouldEqual(res1(x,y,z), 3.0*img(x,y,z));
+                // }
+    // }
+    
+    // void testInitMultiArrayBorder(){
+        // typedef vigra::MultiArray<1,int> IntLine;
+        // typedef vigra::MultiArray<2,int> IntImage;
+        // typedef vigra::MultiArray<3,int> IntVolume;
+        
+        // const int desired_vol[] ={  0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 5, 5, 0, 0,
+                                    // 0, 0, 5, 5, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 5, 5, 0, 0,
+                                    // 0, 0, 5, 5, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0,
+                                    // 0, 0, 0, 0, 0, 0};
+
+        // const int desired_img[] ={  0, 0, 0, 0, 0, 0,
+                                    // 0, 5, 5, 5, 5, 0,
+                                    // 0, 5, 5, 5, 5, 0,
+                                    // 0, 5, 5, 5, 5, 0,
+                                    // 0, 5, 5, 5, 5, 0,
+                                    // 0, 0, 0, 0, 0, 0};
+
+        // const int desired_lin[] ={  0, 0, 0, 5, 0, 0, 0 };
+
+        // const int desired_vol2[] ={  0, 0,
+                                     // 0, 0,
+
+                                     // 0, 0, 
+                                     // 0, 0};
+
+        // IntVolume vol(IntVolume::difference_type(6,6,6));
+        
+        // for(IntVolume::iterator iter=vol.begin(); iter!=vol.end(); ++iter)
+            // *iter=5;
+        // initMultiArrayBorder(destMultiArrayRange(vol),2,0);
+        // shouldEqualSequence(vol.begin(), vol.end(), desired_vol);
+
+        // IntImage img(IntImage::difference_type(6,6));
+        
+        // for(IntImage::iterator iter=img.begin(); iter!=img.end(); ++iter)
+            // *iter=5;
+        // initMultiArrayBorder(destMultiArrayRange(img),1,0);
+        // shouldEqualSequence(img.begin(), img.end(), desired_img);
+
+        // IntLine lin(IntLine::difference_type(7));
+        
+        // for(IntLine::iterator iter=lin.begin(); iter!=lin.end(); ++iter)
+            // *iter=5;
+        // initMultiArrayBorder(destMultiArrayRange(lin),3,0);
+        // shouldEqualSequence(lin.begin(), lin.end(), desired_lin);
+
+        // IntVolume vol2(IntVolume::difference_type(2,2,2));
+        
+        // for(IntVolume::iterator iter=vol2.begin(); iter!=vol2.end(); ++iter)
+            // *iter=5;
+        // initMultiArrayBorder(vol2, 9, 0);
+        // shouldEqualSequence(vol2.begin(), vol2.end(), desired_vol2);
+
+    // }
+
+    // void testInspect()
+    // {
+        // vigra::FindMinMax<PixelType> minmax;
+
+        // inspectMultiArray(img, minmax);
+
+        // shouldEqual(minmax.count, img.size());
+        // shouldEqual(minmax.min, 0.1f);
+        // shouldEqual(minmax.max, 59.1f);
+
+        // vigra::MultiArray<3, unsigned char> labels(img.shape());
+        // labels.subarray(Shape3(1,0,0), img.shape()-Shape3(1,0,0)) = 1;
+
+        // vigra::ArrayOfRegionStatistics<vigra::FindMinMax<PixelType> > stats(1);
+
+        // inspectTwoMultiArrays(img, labels, stats);
+
+        // shouldEqual(stats[0].count, 24);
+        // shouldEqual(stats[0].min, 0.1f);
+        // shouldEqual(stats[0].max, 59.1f);
+        // shouldEqual(stats[1].count, 36);
+        // shouldEqual(stats[1].min, 1.1f);
+        // shouldEqual(stats[1].max, 58.1f);
+    // }
+    
+    // void testTensorUtilities()
+    // {
+        // MultiArrayShape<2>::type shape(3,4);
+        // int size = shape[0]*shape[1];
+        
+        // MultiArray<2, TinyVector<double, 2> > vector(shape), rvector(shape);
+        // MultiArray<2, TinyVector<double, 3> > tensor1(shape), tensor2(shape), rtensor(shape);
+        // MultiArray<2, double > trace(shape), rtrace(shape);
+        // MultiArray<2, double > determinant(shape), rdet(shape);
+        
+        // for(int k=0; k<size; ++k)
+        // {
+            // for(int l=0; l<2; ++l)
+                // vector[k][l] = randomMT19937().uniform();
+            // for(int l=0; l<3; ++l)
+                // tensor1[k][l] = randomMT19937().uniform();
+            // rdet[k] = tensor1[k][0]*tensor1[k][2] - sq(tensor1[k][1]);
+        // }
+        
+        // vectorToTensor(srcImageRange(vector), destImage(rtensor));
+        // vectorToTensorMultiArray(srcMultiArrayRange(vector), destMultiArray(tensor2));
+        // shouldEqualSequence(tensor2.data(), tensor2.data()+size, rtensor.data());
+        // tensor2.init(TinyVector<double, 3>());
+        // vectorToTensorMultiArray(vector, tensor2);
+        // shouldEqualSequence(tensor2.data(), tensor2.data()+size, rtensor.data());
+                
+        // tensorTrace(srcImageRange(tensor1), destImage(rtrace));
+        // tensorTraceMultiArray(srcMultiArrayRange(tensor1), destMultiArray(trace));
+        // shouldEqualSequence(trace.data(), trace.data()+size, rtrace.data());
+        // trace = 0;
+        // tensorTraceMultiArray(tensor1, trace);
+        // shouldEqualSequence(trace.data(), trace.data()+size, rtrace.data());
+                
+        // tensorDeterminantMultiArray(srcMultiArrayRange(tensor1), destMultiArray(determinant));
+        // shouldEqualSequence(determinant.data(), determinant.data()+size, rdet.data());
+        // determinant = 0;
+        // tensorDeterminantMultiArray(tensor1, determinant);
+        // shouldEqualSequence(determinant.data(), determinant.data()+size, rdet.data());
+                
+        // determinant = 1000.0;
+        // tensorDeterminantMultiArray(srcMultiArrayRange(tensor2), destMultiArray(determinant));
+        // shouldEqualTolerance(norm(determinant), 0.0, 1e-14);
+
+        // tensorEigenRepresentation(srcImageRange(tensor1), destImage(rtensor));
+        // tensorEigenvaluesMultiArray(srcMultiArrayRange(tensor1), destMultiArray(vector));
+        // shouldEqualSequenceTolerance(vector.begin(), vector.end(), rtensor.begin(), (TinyVector<double, 2>(1e-14)));
+
+        // vector = TinyVector<double, 2>();
+        // tensorEigenvaluesMultiArray(tensor1, vector);
+        // shouldEqualSequenceTolerance(vector.begin(), vector.end(), rtensor.begin(), (TinyVector<double, 2>(1e-14)));
+    // }
+// };
+
+template <class Array>
+class ChunkedMultiArraySpeedTest
+{
+public:
+
+    typedef typename Array::value_type T;
+    typedef ChunkedArray<3, T> BaseArray;
+    typedef VIGRA_UNIQUE_PTR<BaseArray> ArrayPtr;
+    typedef typename BaseArray::iterator Iterator;
+    
+    Shape3 shape;
+    ArrayPtr array;
+
+    ChunkedMultiArraySpeedTest ()
+        : shape(200, 201, 202)
+    {
+        array = createArray(shape, (Array *)0);
+        linearSequence(array->begin(), array->end());
+        std::cerr << "chunked multi array test for type " << typeid(Array).name() << ": \n";        
+    }
+    
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                ChunkedArrayFull<3, T> *)
+    {
+        return ArrayPtr(new ChunkedArrayFull<3, T>(shape));
+    }
+    
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                ChunkedArrayLazy<3, T> *)
+    {
+        return ArrayPtr(new ChunkedArrayLazy<3, T>(shape));
+    }
+    
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                ChunkedArrayCompressed<3, T> *)
+    {
+        return ArrayPtr(new ChunkedArrayCompressed<3, T>(shape));
+    }
+    
+#ifdef HasHDF5
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                ChunkedArrayHDF5<3, T> *)
+    {
+        HDF5File hdf5_file("chunked_test.h5", HDF5File::New);
+        return ArrayPtr(new ChunkedArrayHDF5<3, T>(hdf5_file, "test", HDF5File::New, 
+                                                   shape, Shape3(), 
+                                                   ChunkedArrayOptions().compression(NO_COMPRESSION)));
+    }
+#endif
+    
+    static ArrayPtr createArray(Shape3 const & shape, 
+                                ChunkedArrayTmpFile<3, T> *)
+    {
+        return ArrayPtr(new ChunkedArrayTmpFile<3, T>(shape));
+    }
+    
+    void testBaselineSpeed()
+    {
+        std::cerr << "############ chunked iterator speed #############\n";
+        ChunkedArrayFull<3, T> a(shape);
+        linearSequence(a.begin(), a.end());
+
+        typename ChunkedArrayFull<3, T>::iterator i   = a.begin(),
+                                                  end = a.end();
+        USETICTOC;
+        T count = 0;
+        TIC;
+        for(; i != end; ++i, ++count)
+            if(count != *i)
+            {
+                shouldEqual(*i, count);
+            }
+        std::string t = TOCS;
+        std::cerr << "    baseline:  " << t << "\n";
+    }
+    
+    void testIteratorSpeed()
+    {
+        Iterator i   = array->begin(),
+                 end = array->end();
+        USETICTOC;
+        T count = 0;
+        TIC;
+        for(; i != end; ++i, ++count)
+        {
+            if(count != *i)
+            {
+                shouldEqual(*i, count);
+            }
+        }
+        std::string t = TOCS;
+        std::cerr << "    read time: " << t << " (cache: " << array->cacheSize() << ")\n";
+    }
+    
+    void testNestedLoopSpeed()
+    {
+        Iterator i   = array->begin(),
+                 end = array->end();
+        USETICTOC;
+        T count = 0;
+        TIC;
+        for(i.setDim(2,0); i.coord(2) < shape[2]; i.incDim(2))
+            for(i.setDim(1,0); i.coord(1) < shape[1]; i.incDim(1))
+                for(i.setDim(0,0); i.coord(0) < shape[0]; i.incDim(0), ++count)
+                {
+                    if(count != *i)
+                    {
+                        shouldEqual(*i, count);
+                    }
+                }
+        std::string t = TOCS;
+        std::cerr << "    loop time: " << t << " (cache: " << array->cacheSize() << ")\n";
+    }
+    
+    void testIteratorSpeed_LargeCache()
+    {
+        array.reset(0);
+        array = createArray(shape, (Array *)0);
+        array->setCacheMaxSize(prod(array->chunkArrayShape()));
+        linearSequence(array->begin(), array->end());
+        testIteratorSpeed();
+    }
+    
+    void testIndexingBaselineSpeed()
+    {
+        std::cerr << "################## indexing speed ####################\n";
+        ChunkedArrayFull<3, T> a(shape);
+        linearSequence(a.begin(), a.end());
+
+        MultiCoordinateIterator<3> i(shape),
+                                   end = i.getEndIterator();
+        USETICTOC;
+        T count = 0;
+        TIC;
+        for(; i != end; ++i, ++count)
+            if(count != a[*i])
+            {
+                shouldEqual(a[*i], count);
+            }
+        std::string t = TOCS;
+        std::cerr << "    baseline:  " << t << "\n";
+    }
+    
+    void testIndexingSpeed()
+    {
+        MultiArrayView<3, T, ChunkedArrayTag> sub(array->subarray(Shape3(), shape));
+        MultiCoordinateIterator<3> i(shape),
+                                   end = i.getEndIterator();
+        USETICTOC;
+        T count = 0;
+        TIC;
+        for(; i != end; ++i, ++count)
+        {
+            if(count != sub[*i])
+            {
+                shouldEqual(sub[*i], count);
+            }
+        }
+        std::string t = TOCS;
+        std::cerr << "    indexing:  " << t << " (cache: " << array->cacheSize() << ")\n";
+    }
+};
+
+struct ChunkedMultiArrayTestSuite
+: public vigra::test_suite
+{
+    template <class Array>
+    void testImpl()
+    {
+        add( testCase( &ChunkedMultiArrayTest<Array>::test_construction ) );
+        add( testCase( &ChunkedMultiArrayTest<Array>::test_assignment ) );
+        add( testCase( &ChunkedMultiArrayTest<Array>::test_bindAt ) );
+        add( testCase( &ChunkedMultiArrayTest<Array>::test_bindInner ) );
+        add( testCase( &ChunkedMultiArrayTest<Array>::test_bindOuter ) );
+        add( testCase( &ChunkedMultiArrayTest<Array>::test_subarray ) );
+        add( testCase( &ChunkedMultiArrayTest<Array>::test_iterator ) );
+        add( testCase( &ChunkedMultiArrayTest<Array>::testChunkIterator ) );
+        add( testCase( &ChunkedMultiArrayTest<Array>::testMultiThreaded ) );
+    }
+    
+    template <class T>
+    void testSpeedImpl()
+    {
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayFull<3, T> >::testBaselineSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayFull<3, T> >::testIteratorSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayLazy<3, T> >::testNestedLoopSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayLazy<3, T> >::testIteratorSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayCompressed<3, T> >::testIteratorSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayTmpFile<3, T> >::testIteratorSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayTmpFile<3, T> >::testIteratorSpeed_LargeCache )));
+#ifdef HasHDF5
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayHDF5<3, T> >::testIteratorSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayHDF5<3, T> >::testIteratorSpeed_LargeCache )));
+#endif
+    }
+    
+    template <class T>
+    void testIndexingSpeedImpl()
+    {
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayFull<3, T> >::testIndexingBaselineSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayFull<3, T> >::testIndexingSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayLazy<3, T> >::testIndexingSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayCompressed<3, T> >::testIndexingSpeed )));
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayTmpFile<3, T> >::testIndexingSpeed )));
+#ifdef HasHDF5
+        add( testCase( (&ChunkedMultiArraySpeedTest<ChunkedArrayHDF5<3, T> >::testIndexingSpeed )));
+#endif
+    }
+    
+    ChunkedMultiArrayTestSuite()
+    : vigra::test_suite("ChunkedMultiArrayTestSuite")
+    {
+        testImpl<ChunkedArrayFull<3, float> >();
+        testImpl<ChunkedArrayLazy<3, float> >();
+        testImpl<ChunkedArrayCompressed<3, float> >();
+        testImpl<ChunkedArrayTmpFile<3, float> >();
+#ifdef HasHDF5
+        testImpl<ChunkedArrayHDF5<3, float> >();
+#endif
+        
+        testImpl<ChunkedArrayFull<3, TinyVector<float, 3> > >();
+        testImpl<ChunkedArrayLazy<3, TinyVector<float, 3> > >();
+        testImpl<ChunkedArrayCompressed<3, TinyVector<float, 3> > >();
+        testImpl<ChunkedArrayTmpFile<3, TinyVector<float, 3> > >();
+#ifdef HasHDF5
+        testImpl<ChunkedArrayHDF5<3, TinyVector<float, 3> > >();
+#endif
+        
+        testSpeedImpl<unsigned char>();
+        testSpeedImpl<float>();
+        testSpeedImpl<double>();
+        
+        testIndexingSpeedImpl<unsigned char>();
+        testIndexingSpeedImpl<float>();
+        testIndexingSpeedImpl<double>();
+        
+        //add( testCase( &MultiArrayPointoperatorsTest::testInit ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testCopy ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testCopyOuterExpansion ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testCopyInnerExpansion ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testTransform ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testTransformOuterExpand ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testTransformInnerExpand ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testTransformOuterReduce ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testTransformInnerReduce ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testCombine2 ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testCombine2OuterExpand ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testCombine2InnerExpand ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testCombine2OuterReduce ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testCombine2InnerReduce ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testCombine3 ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testInitMultiArrayBorder ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testInspect ) );
+        //add( testCase( &MultiArrayPointoperatorsTest::testTensorUtilities ) );
+    }
+};
+
+
+int main(int argc, char ** argv)
+{
+    int failed = 0;
+
+    ChunkedMultiArrayTestSuite test0;
+    failed += test0.run(vigra::testsToBeExecuted(argc, argv));
+    std::cout << test0.report() << std::endl;
+    
+    return (failed != 0);
+}
+
+
diff --git a/test/multidistance/CMakeLists.txt b/test/multidistance/CMakeLists.txt
index 87f0834..0d3aa5c 100644
--- a/test/multidistance/CMakeLists.txt
+++ b/test/multidistance/CMakeLists.txt
@@ -1,9 +1,14 @@
-if(HDF5_FOUND)
-    INCLUDE_DIRECTORIES(${HDF5_INCLUDE_DIR})
-  
-    ADD_DEFINITIONS(${HDF5_CPPFLAGS})
+VIGRA_ADD_TEST(test_multidistance test.cxx LIBRARIES vigraimpex)
 
-    VIGRA_ADD_TEST(test_multidistance test.cxx LIBRARIES vigraimpex ${HDF5_LIBRARIES})
-else()
-    VIGRA_ADD_TEST(test_multidistance test.cxx LIBRARIES vigraimpex)
-endif()
+VIGRA_COPY_TEST_DATA(
+    blatt.xv
+    raw_skeleton.xv
+    skeleton_length.xv
+    skeleton_length_greater_100.xv
+    skeleton_length_greater_50_percent.xv
+    skeleton_salience.xv
+    skeleton_salience_greater_10.xv
+    skeleton_salience_greater_60_percent.xv
+    skeleton_topology.xv
+    skeleton_topology_without_center.xv
+)
diff --git a/test/multidistance/blatt.xv b/test/multidistance/blatt.xv
new file mode 100644
index 0000000..90655ef
Binary files /dev/null and b/test/multidistance/blatt.xv differ
diff --git a/test/multidistance/raw_skeleton.xv b/test/multidistance/raw_skeleton.xv
new file mode 100644
index 0000000..64d5731
Binary files /dev/null and b/test/multidistance/raw_skeleton.xv differ
diff --git a/test/multidistance/skeleton_length.xv b/test/multidistance/skeleton_length.xv
new file mode 100644
index 0000000..55b88dd
Binary files /dev/null and b/test/multidistance/skeleton_length.xv differ
diff --git a/test/multidistance/skeleton_length_greater_100.xv b/test/multidistance/skeleton_length_greater_100.xv
new file mode 100644
index 0000000..c23643f
Binary files /dev/null and b/test/multidistance/skeleton_length_greater_100.xv differ
diff --git a/test/multidistance/skeleton_length_greater_50_percent.xv b/test/multidistance/skeleton_length_greater_50_percent.xv
new file mode 100644
index 0000000..c23643f
Binary files /dev/null and b/test/multidistance/skeleton_length_greater_50_percent.xv differ
diff --git a/test/multidistance/skeleton_salience.xv b/test/multidistance/skeleton_salience.xv
new file mode 100644
index 0000000..c48b20b
Binary files /dev/null and b/test/multidistance/skeleton_salience.xv differ
diff --git a/test/multidistance/skeleton_salience_greater_10.xv b/test/multidistance/skeleton_salience_greater_10.xv
new file mode 100644
index 0000000..c23643f
Binary files /dev/null and b/test/multidistance/skeleton_salience_greater_10.xv differ
diff --git a/test/multidistance/skeleton_salience_greater_60_percent.xv b/test/multidistance/skeleton_salience_greater_60_percent.xv
new file mode 100644
index 0000000..c23643f
Binary files /dev/null and b/test/multidistance/skeleton_salience_greater_60_percent.xv differ
diff --git a/test/multidistance/skeleton_topology.xv b/test/multidistance/skeleton_topology.xv
new file mode 100644
index 0000000..6b76510
Binary files /dev/null and b/test/multidistance/skeleton_topology.xv differ
diff --git a/test/multidistance/skeleton_topology_without_center.xv b/test/multidistance/skeleton_topology_without_center.xv
new file mode 100644
index 0000000..0702f84
Binary files /dev/null and b/test/multidistance/skeleton_topology_without_center.xv differ
diff --git a/test/multidistance/test.cxx b/test/multidistance/test.cxx
index 9942e14..e928772 100644
--- a/test/multidistance/test.cxx
+++ b/test/multidistance/test.cxx
@@ -37,859 +37,20 @@
 #include <functional>
 #include <cmath>
 #include <list>
-#include "vigra/unittest.hxx"
+#include <vigra/unittest.hxx>
 
-#include "vigra/multi_distance.hxx"
-#include "vigra/distancetransform.hxx"
+#include <vigra/multi_distance.hxx>
+#include <vigra/distancetransform.hxx>
+#include <vigra/eccentricitytransform.hxx>
+#include <vigra/impex.hxx>
+#include <vigra/vector_distance.hxx>
+#include <vigra/skeleton.hxx>
+#include <vigra/timing.hxx>
 
-using namespace vigra;
 
-static double volume_data[4200] = {
-255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 0.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 0.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
-255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
-255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
-};
+#include "test_data.hxx"
 
-// reference squred distance for the foreground of above volume
-static double ref_dist2[4200] = {
-5.0, 4.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 4.0, 4.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 4.0, 4.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0,
-1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 2.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 5.0, 6.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 2.0, 3.0, 5.0, 5.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 1.0, 2.0,
-2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0,
-1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 2.0, 3.0, 5.0, 6.0, 9.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 3.0, 5.0, 6.0, 5.0, 4.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 5.0, 4.0, 4.0,
-2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 3.0,
-2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0,
-1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0,
-1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 2.0, 1.0, 2.0, 4.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 2.0, 3.0, 2.0, 3.0, 5.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 2.0, 4.0, 5.0, 5.0, 5.0, 4.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 3.0, 5.0, 5.0, 4.0,
-2.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 5.0, 5.0,
-2.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 3.0,
-2.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0,
-2.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0,
-2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 2.0, 1.0, 2.0, 3.0, 4.0, 4.0,
-0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 3.0, 2.0, 3.0, 2.0,
-2.0, 1.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0, 5.0, 5.0,
-2.0, 1.0, 1.0, 0.0, 0.0, 1.0, 2.0, 3.0, 5.0, 3.0,
-2.0, 2.0, 1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 5.0, 4.0,
-2.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 2.0, 3.0,
-5.0, 4.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0,
-0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 2.0, 1.0,
-1.0, 1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 4.0, 3.0,
-1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 5.0, 6.0, 3.0, 2.0,
-1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 2.0, 3.0, 6.0, 5.0,
-2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 6.0,
-8.0, 4.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 3.0, 2.0, 2.0, 1.0,
-1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 4.0, 5.0, 2.0, 1.0,
-1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 4.0, 5.0, 6.0, 3.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 9.0,
-5.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 3.0, 2.0, 1.0, 0.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 4.0, 4.0, 2.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 4.0,
-4.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 1.0, 1.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 1.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 1.0,
-1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 2.0, 3.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 0.0, 1.0, 1.0, 2.0, 3.0, 2.0, 0.0, 1.0,
-1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 5.0, 5.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 2.0, 2.0, 3.0, 0.0, 1.0, 1.0, 1.0,
-1.0, 1.0, 1.0, 2.0, 2.0, 3.0, 5.0, 5.0, 0.0, 1.0,
-2.0, 2.0, 2.0, 3.0, 2.0, 3.0, 4.0, 5.0, 8.0, 8.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0,
-2.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0,
-1.0, 2.0, 3.0, 5.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0,
-1.0, 2.0, 2.0, 3.0, 5.0, 6.0, 0.0, 0.0, 1.0, 2.0,
-2.0, 2.0, 3.0, 5.0, 5.0, 6.0, 8.0, 9.0, 1.0, 1.0,
-2.0, 5.0, 5.0, 5.0, 5.0, 6.0, 8.0, 9.0, 12.0, 13.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
-3.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
-3.0, 5.0, 6.0, 9.0, 0.0, 1.0, 0.0, 1.0, 1.0, 2.0,
-2.0, 3.0, 5.0, 6.0, 9.0, 11.0, 1.0, 1.0, 1.0, 2.0,
-4.0, 5.0, 5.0, 6.0, 8.0, 9.0, 12.0, 14.0, 2.0, 2.0,
-3.0, 5.0, 8.0, 8.0, 9.0, 11.0, 13.0, 14.0, 16.0, 16.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0,
-5.0, 6.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0,
-5.0, 6.0, 9.0, 10.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0,
-5.0, 6.0, 9.0, 9.0, 9.0, 9.0, 1.0, 2.0, 2.0, 3.0,
-5.0, 6.0, 8.0, 9.0, 10.0, 9.0, 9.0, 9.0, 4.0, 5.0,
-4.0, 4.0, 5.0, 8.0, 10.0, 9.0, 9.0, 9.0, 9.0, 9.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 0.0, 1.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 3.0, 5.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 5.0, 6.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 5.0, 6.0,
-8.0, 8.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 4.0, 5.0,
-6.0, 5.0, 5.0, 5.0, 1.0, 1.0, 1.0, 2.0, 4.0, 5.0,
-8.0, 8.0, 5.0, 4.0, 4.0, 4.0, 2.0, 3.0, 2.0, 2.0,
-3.0, 6.0, 6.0, 5.0, 5.0, 4.0, 4.0, 4.0, 5.0, 2.0,
-1.0, 1.0, 2.0, 5.0, 5.0, 4.0, 4.0, 4.0, 4.0, 4.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
-4.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-1.0, 2.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 1.0, 1.0, 2.0, 5.0, 6.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 6.0, 8.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 5.0, 6.0, 6.0, 5.0,
-0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0, 6.0, 5.0,
-5.0, 4.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0, 5.0, 6.0,
-3.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 5.0, 6.0,
-6.0, 5.0, 2.0, 1.0, 1.0, 1.0, 3.0, 2.0, 1.0, 1.0,
-2.0, 5.0, 3.0, 2.0, 2.0, 1.0, 1.0, 1.0, 2.0, 1.0,
-0.0, 0.0, 1.0, 4.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 4.0, 5.0,
-8.0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-4.0, 5.0, 8.0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 2.0, 4.0, 5.0, 8.0, 9.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 2.0, 5.0, 6.0, 6.0, 5.0, 0.0, 0.0,
-0.0, 1.0, 2.0, 2.0, 2.0, 3.0, 6.0, 6.0, 3.0, 2.0,
-0.0, 1.0, 1.0, 2.0, 3.0, 5.0, 5.0, 6.0, 5.0, 3.0,
-2.0, 1.0, 1.0, 2.0, 4.0, 5.0, 5.0, 6.0, 6.0, 5.0,
-2.0, 1.0, 1.0, 1.0, 4.0, 4.0, 4.0, 4.0, 5.0, 5.0,
-3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 1.0,
-2.0, 2.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0,
-0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 4.0, 6.0,
-5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
-5.0, 5.0, 4.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
-2.0, 3.0, 6.0, 5.0, 4.0, 4.0, 0.0, 0.0, 0.0, 1.0,
-1.0, 2.0, 3.0, 5.0, 8.0, 5.0, 4.0, 4.0, 0.0, 1.0,
-1.0, 2.0, 3.0, 5.0, 5.0, 6.0, 6.0, 3.0, 2.0, 1.0,
-1.0, 2.0, 2.0, 3.0, 6.0, 8.0, 8.0, 6.0, 3.0, 2.0,
-1.0, 0.0, 2.0, 3.0, 5.0, 6.0, 8.0, 6.0, 5.0, 4.0,
-2.0, 1.0, 0.0, 0.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0,
-2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
-1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 5.0, 3.0,
-2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0,
-5.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
-5.0, 6.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0,
-2.0, 3.0, 6.0, 8.0, 5.0, 2.0, 1.0, 1.0, 1.0, 2.0,
-2.0, 3.0, 5.0, 6.0, 9.0, 6.0, 3.0, 2.0, 1.0, 1.0,
-2.0, 3.0, 5.0, 6.0, 6.0, 5.0, 5.0, 5.0, 2.0, 1.0,
-0.0, 0.0, 5.0, 6.0, 8.0, 6.0, 5.0, 3.0, 2.0, 2.0,
-1.0, 0.0, 0.0, 0.0, 4.0, 4.0, 4.0, 3.0, 2.0, 2.0,
-1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
-1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 4.0, 5.0, 2.0, 1.0,
-1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 5.0, 5.0,
-2.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0,
-5.0, 4.0, 2.0, 1.0, 0.0, 0.0, 2.0, 2.0, 2.0, 3.0,
-5.0, 6.0, 5.0, 4.0, 2.0, 1.0, 0.0, 0.0, 4.0, 5.0,
-5.0, 6.0, 6.0, 5.0, 5.0, 3.0, 2.0, 1.0, 0.0, 0.0,
-5.0, 6.0, 8.0, 6.0, 3.0, 2.0, 3.0, 2.0, 1.0, 0.0,
-0.0, 0.0, 6.0, 5.0, 5.0, 5.0, 2.0, 1.0, 1.0, 1.0,
-1.0, 0.0, 0.0, 0.0, 3.0, 2.0, 2.0, 2.0, 1.0, 1.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 2.0, 4.0, 4.0, 5.0, 5.0, 4.0, 1.0, 0.0,
-0.0, 0.0, 1.0, 1.0, 2.0, 4.0, 4.0, 5.0, 3.0, 2.0,
-1.0, 0.0, 0.0, 0.0, 2.0, 2.0, 3.0, 5.0, 5.0, 5.0,
-2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 5.0, 5.0, 5.0, 6.0,
-6.0, 5.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 8.0, 8.0,
-8.0, 6.0, 3.0, 2.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0,
-9.0, 8.0, 6.0, 3.0, 2.0, 1.0, 1.0, 1.0, 0.0, 0.0,
-0.0, 0.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0, 1.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 1.0, 1.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-4.0, 4.0, 5.0, 8.0, 9.0, 5.0, 2.0, 1.0, 1.0, 0.0,
-0.0, 0.0, 4.0, 4.0, 5.0, 8.0, 9.0, 5.0, 2.0, 1.0,
-1.0, 0.0, 0.0, 0.0, 5.0, 5.0, 6.0, 9.0, 6.0, 3.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 8.0, 8.0, 6.0,
-3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.0, 6.0,
-5.0, 3.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-6.0, 5.0, 3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 3.0, 2.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-9.0, 9.0, 10.0, 13.0, 9.0, 4.0, 1.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 9.0, 9.0, 10.0, 9.0, 6.0, 4.0, 1.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 10.0, 10.0, 10.0, 6.0, 3.0, 2.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.0, 6.0, 5.0, 5.0,
-2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 3.0,
-2.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-3.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-16.0, 16.0, 17.0, 13.0, 9.0, 4.0, 1.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 16.0, 16.0, 13.0, 8.0, 5.0, 4.0, 1.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 13.0, 10.0, 9.0, 5.0, 2.0, 1.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 5.0, 4.0, 4.0,
-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 2.0,
-1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
-};
+using namespace vigra;
 
 struct MultiDistanceTest
 {
@@ -899,6 +60,10 @@ struct MultiDistanceTest
     typedef vigra::DImage Image;
     typedef vigra::MultiArrayView<2,Image::value_type> ImageView;
     typedef vigra::TinyVector<int,3> IntVec;
+    typedef vigra::MultiArray<3,vigra::TinyVector<int,3> > IntVecVolume;
+    typedef vigra::MultiArray<3,vigra::TinyVector<double,3> > DoubleVecVolume;
+    typedef vigra::MultiArray<2,vigra::TinyVector<double,2> > DoubleVecImage;
+
 
 #if 1
     enum { WIDTH    =   15,  // 
@@ -910,7 +75,7 @@ struct MultiDistanceTest
            DEPTH    =   1}; //
 #endif
 
-    std::list<std::list<IntVec> > pointslists;
+    std::vector<std::vector<IntVec> > pointslists;
     std::vector<Image> images;
     Double2DArray img2;
     DoubleVolume volume;
@@ -921,7 +86,7 @@ struct MultiDistanceTest
       volume(IntVolume::difference_type(WIDTH,HEIGHT,DEPTH)),
       shouldVol(IntVolume::difference_type(WIDTH,HEIGHT,DEPTH))
     {
-        std::list<IntVec> temp;
+        std::vector<IntVec> temp;
         temp.push_back(IntVec(      0,        0,       0));
         temp.push_back(IntVec(WIDTH-1,        0,       0));
         temp.push_back(IntVec(      0, HEIGHT-1,       0));
@@ -1014,32 +179,46 @@ struct MultiDistanceTest
 
     void testDistanceVolumes()
     {    
-        DoubleVolume desired(volume);
-        for(std::list<std::list<IntVec> >::iterator list_iter=pointslists.begin(); 
-                                          list_iter!=pointslists.end(); ++list_iter)
+        DoubleVolume dt(volume.shape()), desired(volume.shape());
+        DoubleVecVolume vecDesired(volume.shape()); 
+        for(unsigned k = 0; k<pointslists.size(); ++k)
         {
-            IntVec temp;
-            for(int z=0; z<DEPTH; ++z)
-                for(int y=0; y<HEIGHT; ++y)
-                    for(int x=0; x<WIDTH; ++x){
-                        temp = IntVec(x,y,z);
-                        int tempVal=10000000;
-                        for(std::list<IntVec>::iterator iter=(*list_iter).begin(); iter!=(*list_iter).end(); ++iter){
-                            if((temp-*iter).squaredMagnitude()<tempVal){
-                                tempVal = (temp-*iter).squaredMagnitude();
-                            }
-                        }
-                        desired(x,y,z)=tempVal;
+            DoubleVolume::iterator i = desired.begin();
+            for(; i.isValid(); ++i)
+            {
+                UInt64 minDist = NumericTraits<UInt64>::max();
+                int nearest = -1;
+                for(unsigned j=0; j<pointslists[k].size(); ++j)
+                {
+                    UInt64 dist = squaredNorm(pointslists[k][j] - i.point());
+                    if(dist < minDist)
+                    {
+                        minDist = dist;
+                        nearest = j;
                     }
-
-            for(DoubleVolume::iterator vol_iter = volume.begin(); vol_iter != volume.end(); ++vol_iter)
-                *vol_iter=0;
-            for(std::list<IntVec>::iterator iter=(*list_iter).begin(); iter!=(*list_iter).end(); ++iter){
-                *(volume.traverser_begin()+*iter)=1;
+                }
+                *i = minDist;
+                vecDesired[i.point()] = pointslists[k][nearest] - i.point();
             }
 
-            separableMultiDistSquared(volume, volume, true);
-            shouldEqualSequence(volume.begin(),volume.end(),desired.begin());
+            volume = 0.0;
+            for(unsigned j=0; j<pointslists[k].size(); ++j)
+                volume[pointslists[k][j]] = 1;
+
+            separableMultiDistSquared(volume, dt, true);
+            shouldEqualSequence(dt.begin(), dt.end(), desired.begin());
+
+            {
+                //test vectorial distance
+                using functor::Arg1;
+                DoubleVecVolume vecVolume(volume.shape()); 
+                separableVectorDistance(volume, vecVolume, true);
+                DoubleVolume distVolume(volume.shape());
+                transformMultiArray(vecVolume, distVolume, squaredNorm(Arg1()));
+                shouldEqualSequence(distVolume.begin(), distVolume.end(), desired.begin());
+                // FIXME: this test fails because the nearest point may be ambiguous
+                //shouldEqualSequence(vecVolume.begin(), vecVolume.end(), vecDesired.begin());
+            }
         }
 
         typedef MultiArrayShape<3>::type Shape;
@@ -1047,65 +226,109 @@ struct MultiDistanceTest
         
         MultiArray<3, double> res(vol.shape());
 
-        separableMultiDistSquared(srcMultiArrayRange(vol), destMultiArray(res), false);
+        separableMultiDistSquared(vol, res, false);
                 
         shouldEqualSequence(res.data(), res.data()+res.elementCount(), ref_dist2);
+
+        {
+            //test vectorial distance
+            using functor::Arg1;
+            DoubleVecVolume vecVolume(vol.shape()); 
+            separableVectorDistance(vol, vecVolume, false);
+            DoubleVolume distVolume(vol.shape());
+            transformMultiArray(vecVolume, distVolume, squaredNorm(Arg1()));
+            shouldEqualSequence(distVolume.begin(), distVolume.end(), ref_dist2);
+        }
     }
 
     void testDistanceAxesPermutation()
     {
+        using namespace vigra::functor;
         typedef MultiArrayShape<3>::type Shape;
         MultiArrayView<3, double> vol(Shape(12,10,35), volume_data);
         
         MultiArray<3, double> res1(vol.shape()), res2(vol.shape());
-        MultiArrayView<3, double, StridedArrayTag> pvol(vol.transpose()), pres2(res2.transpose());
+        DoubleVecVolume vecVolume(reverse(vol.shape())); 
         
         separableMultiDistSquared(vol, res1, true);
-        separableMultiDistSquared(pvol, pres2, true);
-                
+        separableMultiDistSquared(vol.transpose(), res2.transpose(), true);
         shouldEqualSequence(res1.data(), res1.data()+res1.elementCount(), res2.data());
-        
+
+        res2 = 0.0;
+        separableVectorDistance(vol.transpose(), vecVolume, true);
+        transformMultiArray(vecVolume, res2.transpose(), squaredNorm(Arg1()));
+        shouldEqualSequence(res1.data(), res1.data()+res1.elementCount(), res2.data());
+
         separableMultiDistSquared(vol, res1, false);
-        separableMultiDistSquared(pvol, pres2, false);
-                
+        separableMultiDistSquared(vol.transpose(), res2.transpose(), false);
+        shouldEqualSequence(res1.data(), res1.data()+res1.elementCount(), res2.data());
+
+        res2 = 0.0;
+        separableVectorDistance(vol.transpose(), vecVolume, false);
+        transformMultiArray(vecVolume, res2.transpose(), squaredNorm(Arg1()));
         shouldEqualSequence(res1.data(), res1.data()+res1.elementCount(), res2.data());
     }
 
-    void testDistanceVolumesAnisoptopic()
+    void testVectorDistanceBug()
+    {
+        MultiArray<3, int> data(Shape3(9,10,2));
+        data.subarray(Shape3(5,5,1), Shape3(7,7,2)) = 1;
+        MultiArray<3, TinyVector<int, 3> > res(data.shape());
+
+        separableVectorDistance(data, res);
+
+        int ref[] = { 5, 4, 3, 2, 1, 0, 0, -1, -2, -3 };
+
+        for(MultiCoordinateIterator<3> it(data.shape()); it.isValid(); ++it)
+        {
+            shouldEqual(res[*it][0], ref[(*it)[0]]);
+            shouldEqual(res[*it][1], ref[(*it)[1]]);
+            shouldEqual(res[*it][2], 1-(*it)[2]);
+        }
+    }
+
+    void testDistanceVolumesAnisotropic()
     {    
         double epsilon = 1e-14;
         TinyVector<double, 3> pixelPitch(1.2, 1.0, 2.4);
         
-        DoubleVolume desired(volume);
-        for(std::list<std::list<IntVec> >::iterator list_iter=pointslists.begin(); 
-                                          list_iter!=pointslists.end(); ++list_iter){
-
-            for(DoubleVolume::iterator vol_iter = volume.begin(); vol_iter != volume.end(); ++vol_iter)
-                *vol_iter=0;
-            for(std::list<IntVec>::iterator iter=(*list_iter).begin(); iter!=(*list_iter).end(); ++iter)
-                *(volume.traverser_begin()+*iter)=1;
-
-            IntVec temp;
-            for(int z=0; z<DEPTH; ++z)
-                for(int y=0; y<HEIGHT; ++y)
+        DoubleVolume res(volume.shape()), desired(volume.shape());
+        for(unsigned k = 0; k<pointslists.size(); ++k)
+        {
+            DoubleVolume::iterator i = desired.begin();
+            for(; i.isValid(); ++i)
+            {
+                double minDist = NumericTraits<double>::max();
+                //int nearest = -1;
+                for(unsigned j=0; j<pointslists[k].size(); ++j)
                 {
-                    for(int x=0; x<WIDTH; ++x)
+                    double dist = squaredNorm(pixelPitch*(pointslists[k][j] - i.point()));
+                    if(dist < minDist)
                     {
-                        temp = IntVec(x,y,z);
-                        double tempVal=10000000.0;
-                        for(std::list<IntVec>::iterator iter=(*list_iter).begin(); iter!=(*list_iter).end(); ++iter){
-                            double squaredMag = (pixelPitch*(temp-*iter)).squaredMagnitude();
-                            if(squaredMag<tempVal){
-                                tempVal = squaredMag;
-                            }
-                        }
-                        desired(x,y,z)=tempVal;
+                        minDist = dist;
+                        //nearest = j;
                     }
                 }
+                *i = minDist;
+                //vecDesired[i.point()] = pointslists[k][nearest] - i.point();
+            }
 
+            volume = 0.0;
+            for(unsigned j=0; j<pointslists[k].size(); ++j)
+                volume[pointslists[k][j]] = 1;
 
-            separableMultiDistSquared(volume, volume, true, pixelPitch);
-            shouldEqualSequenceTolerance(volume.begin(),volume.end(),desired.begin(), epsilon);
+            separableMultiDistSquared(volume, res, true, pixelPitch);
+            shouldEqualSequenceTolerance(res.begin(), res.end(), desired.begin(), epsilon);
+
+            {
+                //test vectorial distance
+                using namespace functor;
+                DoubleVecVolume vecVolume(volume.shape()); 
+                separableVectorDistance(volume, vecVolume, true, pixelPitch);
+                DoubleVolume distVolume(volume.shape());
+                transformMultiArray(vecVolume, distVolume, squaredNorm(Param(pixelPitch)*Arg1()));
+                shouldEqualSequenceTolerance(distVolume.begin(), distVolume.end(), desired.begin(), epsilon);
+            }
         }
     }
 
@@ -1113,59 +336,545 @@ struct MultiDistanceTest
     {
         for(unsigned int k=0; k<images.size(); ++k)
         {
-            Image res(images[k]);
-            ImageView img_array(ImageView::difference_type(images[k].width(), images[k].height()), &images[k](0,0));
+            Image res_old(images[k]);
+            ImageView img_array(Shape2(images[k].width(), images[k].height()), &images[k](0,0));
+            MultiArray<2, Image::value_type> res_new(img_array.shape());
+
+            distanceTransform(srcImageRange(images[k]), destImage(res_old), 0.0, 2);
+
+            separableMultiDistance(img_array, res_new, true);
+            shouldEqualSequenceTolerance(res_new.begin(), res_new.end(), res_old.data(), 1e-7);
+
+            DoubleVecImage vec_image(img_array.shape());
+            separableVectorDistance(img_array, vec_image, true);
+            MultiArray<2, double> img_array_dist(img_array.shape());
+            using namespace functor;
+            transformMultiArray(vec_image, img_array_dist, norm(Arg1()));
+            shouldEqualSequenceTolerance(img_array_dist.begin(), img_array_dist.end(), res_old.data(), 1e-7);
+        }
+    }
+
+    void distanceTest1D()
+    {
+        vigra::MultiArray<2,double> res(img2);
+        
+        static const int desired[] = {3, 2, 1, 0, 1, 2, 3};
+        separableMultiDistance(img2, res, true);
+        shouldEqualSequence(res.begin(), res.end(), desired);
+    }
+};
+
+struct BoundaryMultiDistanceTest
+{
+    typedef vigra::MultiArray<3,int> IntVolume;
+    typedef vigra::MultiArray<3,double> DoubleVolume; 
+    typedef vigra::MultiArray<2,double> Double2DArray;
+    typedef vigra::MultiArray<1,double> Double1DArray;
+    typedef vigra::DImage Image;
+    typedef vigra::MultiArrayView<2,Image::value_type> ImageView;
+    typedef vigra::TinyVector<int,3> IntVec;
+
+#if 1
+    enum { WIDTH    =   50,  // 
+           HEIGHT   =   50,  // Volume-Dimensionen
+           DEPTH    =   1}; //
+#else
+    enum { WIDTH    =   4,  // 
+           HEIGHT   =   4,  // Volume-Dimensionen
+           DEPTH    =   1}; //
+#endif
 
-            distanceTransform(srcImageRange(images[k]), destImage(res), 0.0, 2);
+    std::vector<std::vector<IntVec> > pointslists;
+    std::vector<Image> images;
+    Double1DArray img2;
+    DoubleVolume volume;
+    IntVolume shouldVol;
 
-            separableMultiDistance(img_array, img_array, true);
+    BoundaryMultiDistanceTest()
+    : images(3, Image(7,7)), img2(Shape1(7)),
+      volume(IntVolume::difference_type(WIDTH,HEIGHT,DEPTH)),
+      shouldVol(IntVolume::difference_type(WIDTH,HEIGHT,DEPTH))
+    {
+        std::vector<IntVec> temp;
+        temp.push_back(IntVec(      0,        0,       0));
+        temp.push_back(IntVec(WIDTH-1,        0,       0));
+        temp.push_back(IntVec(      0, HEIGHT-1,       0));
+        temp.push_back(IntVec(WIDTH-1, HEIGHT-1,       0));
+        temp.push_back(IntVec(      0,        0, DEPTH-1));
+        temp.push_back(IntVec(WIDTH-1,        0, DEPTH-1));
+        temp.push_back(IntVec(      0, HEIGHT-1, DEPTH-1));
+        temp.push_back(IntVec(WIDTH-1, HEIGHT-1, DEPTH-1));
+        pointslists.push_back(temp);
+
+        temp.clear();
+        temp.push_back(IntVec(      0, HEIGHT/2, DEPTH/2));
+        temp.push_back(IntVec(WIDTH/2, HEIGHT/2,       0));
+        temp.push_back(IntVec(WIDTH/2,        0, DEPTH/2));
+        temp.push_back(IntVec(WIDTH-1, HEIGHT/2, DEPTH/2));
+        temp.push_back(IntVec(WIDTH/2, HEIGHT/2, DEPTH-1));
+        temp.push_back(IntVec(WIDTH/2, HEIGHT-1, DEPTH/2));
+        pointslists.push_back(temp);
+    
 
-            Image::Iterator i = res.upperLeft();
-            Image::Accessor acc = res.accessor();
+        static const double in[] = {
+            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+            0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
+            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+            0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
+            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
 
-            int x,y;
+        {
+            Image::ScanOrderIterator i = images[0].begin();
+            Image::ScanOrderIterator end = images[0].end();
+            Image::Accessor acc = images[0].accessor();
+            const double * p = in;
 
-            for(y=0; y<7; ++y)
+            for(; i != end; ++i, ++p)
             {
-                for(x=0; x<7; ++x)
-                {
-                    double dist_old = acc(i, vigra::Diff2D(x,y));
+                acc.set(*p, i);
+            }
+        }
+        
+        static const unsigned char in2[] = {
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1};
 
-                    shouldEqualTolerance(dist_old, img_array(x,y), 1e-7);
-                }
+        {
+            Image::ScanOrderIterator i = images[1].begin();
+            Image::ScanOrderIterator end = images[1].end();
+            Image::Accessor acc = images[1].accessor();
+            const unsigned char * p = in2;
+
+            for(; i != end; ++i, ++p)
+            {
+                acc.set(*p, i);
             }
         }
+
+        static const unsigned char in3[] = {
+            1, 1, 1, 1, 1, 1, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 0, 0, 0, 0, 0, 1,
+            1, 1, 1, 1, 1, 1, 1};
+
+        {
+            Image::ScanOrderIterator i = images[2].begin();
+            Image::ScanOrderIterator end = images[2].end();
+            Image::Accessor acc = images[2].accessor();
+            const unsigned char * p = in3;
+
+            for(; i != end; ++i, ++p)
+            {
+                acc.set(*p, i);
+            }
+        }
+
+        static const double in2d[] = {0, 0, 0, 1, 0, 0, 0};
+        const double * p=in2d;
+        for(Double1DArray::iterator iter=img2.begin(); iter!=img2.end(); ++iter, ++p){
+            *iter=*p;
+        }
+    }
+
+    void testDistanceVolumes()
+    {    
+        using namespace multi_math;
+        MultiArrayView<2, double> vol(Shape2(50,50), bndMltDst_data);    
+        MultiArray<2, double> res(vol.shape());
+
+        boundaryMultiDistance(vol, res);
+        shouldEqualSequenceTolerance(res.begin(), res.end(), bndMltDst_ref, 1e-6);
+
+        boundaryMultiDistance(vol, res, true);
+        shouldEqualSequenceTolerance(res.begin(), res.end(), bndMltDstArrayBorder_ref, 1e-6);
+
+        
+        MultiArray<2, double> res2(vol.shape());
+        MultiArray<2, TinyVector<double, 2> > res_vec(vol.shape());
+
+        boundaryMultiDistance(vol, res, false, InterpixelBoundary);
+        boundaryVectorDistance(vol, res_vec, false, InterpixelBoundary);
+        res2 = norm(res_vec);
+        shouldEqualSequenceTolerance(res.begin(), res.end(), res2.begin(), 0.25); // FIXME: check this -- 0.25 is a lot
+            
+        boundaryMultiDistance(vol, res, false, OuterBoundary);
+        boundaryVectorDistance(vol, res_vec, false, OuterBoundary);
+        res2 = norm(res_vec);
+        shouldEqualSequenceTolerance(res.begin(), res.end(), res2.begin(), 1e-15);
+            
+        boundaryMultiDistance(vol, res, false, InnerBoundary);
+        boundaryVectorDistance(vol, res_vec, false, InnerBoundary);
+        res2 = norm(res_vec);
+        shouldEqualSequenceTolerance(res.begin(), res.end(), res2.begin(), 1e-15);
+
+        boundaryMultiDistance(vol, res, true, InterpixelBoundary);
+        boundaryVectorDistance(vol, res_vec, true, InterpixelBoundary);
+        res2 = norm(res_vec);
+        shouldEqualSequenceTolerance(res.begin(), res.end(), res2.begin(), 0.25); // FIXME: check this -- 0.25 is a lot
+
+        boundaryMultiDistance(vol, res, true, OuterBoundary);
+        boundaryVectorDistance(vol, res_vec, true, OuterBoundary);
+        res2 = norm(res_vec);
+        shouldEqualSequenceTolerance(res.begin(), res.end(), res2.begin(), 1e-15);
+            
+        boundaryMultiDistance(vol, res, true, InnerBoundary);
+        boundaryVectorDistance(vol, res_vec, true, InnerBoundary);
+        res2 = norm(res_vec);
+        shouldEqualSequenceTolerance(res.begin(), res.end(), res2.begin(), 1e-15);
+            
+            // FIXME: add tests for alternative boundary definitions
     }
 
     void distanceTest1D()
     {
-        vigra::MultiArray<2,double> res(img2);
+        {
+            // OuterBoundary
+            Double1DArray res(img2.shape());
         
-        static const int desired[] = {3, 2, 1, 0, 1, 2, 3};
-        separableMultiDistance(img2, res, true);
-        shouldEqualSequence(res.begin(), res.end(), desired);
+            static const float desired[] = {3, 2, 1, 1, 1, 2, 3};
+            boundaryMultiDistance(img2, res, false, OuterBoundary);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            //InterpixelBoundary
+            Double1DArray res(img2.shape());
+        
+            static const float desired[] = {2.5, 1.5, 0.5, 0.5, 0.5, 1.5, 2.5};
+            boundaryMultiDistance(img2, res);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            // InnerBoundary
+            Double1DArray res(img2.shape());
+        
+            static const float desired[] = {2, 1, 0, 0, 0, 1, 2};
+            boundaryMultiDistance(img2, res, false, InnerBoundary);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            //OuterBoundary and image border
+            Double1DArray res(img2.shape());
+        
+            static const float desired[] = {1, 2, 1, 1, 1, 2, 1};
+            boundaryMultiDistance(img2, res, true, OuterBoundary);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            //InterpixelBoundary and image border
+            Double1DArray res(img2.shape());
+        
+            static const float desired[] = {0.5, 1.5, 0.5, 0.5, 0.5, 1.5, 0.5};
+            boundaryMultiDistance(img2, res, true);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            //InnerBoundary and image border
+            Double1DArray res(img2.shape());
+        
+            static const float desired[] = {0, 1, 0, 0, 0, 1, 0};
+            boundaryMultiDistance(img2, res, true, InnerBoundary);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+    }
+
+    void vectorDistanceTest1D()
+    {
+        typedef TinyVector<double, 1> P;
+        {
+            // OuterBoundary
+            MultiArray<1, P> res(img2.shape());
+        
+            static const P desired[] = {P(3), P(2), P(1), P(1), P(-1), P(-2), P(-3) };
+            boundaryVectorDistance(img2, res, false, OuterBoundary);
+            //for(int k=0; k<7; ++k)
+            //    std::cerr << res[k] << " ";
+            //std::cerr << "\n";
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            //InterpixelBoundary
+            MultiArray<1, P> res(img2.shape());
+        
+            static const P desired[] = {P(2.5), P(1.5), P(0.5), P(-0.5), P(-0.5), P(-1.5), P(-2.5) };
+            boundaryVectorDistance(img2, res, false, InterpixelBoundary);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            // InnerBoundary
+            MultiArray<1, P> res(img2.shape());
+        
+            static const P desired[] = {P(2), P(1), P(0), P(0), P(0), P(-1), P(-2)};
+            boundaryVectorDistance(img2, res, false, InnerBoundary);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            //OuterBoundary and image border
+            MultiArray<1, P> res(img2.shape());
+        
+            static const P desired[] = {P(-1), P(2), P(1), P(1), P(-1), P(2), P(1) };
+            boundaryVectorDistance(img2, res, true, OuterBoundary);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            //InterpixelBoundary and image border
+            MultiArray<1, P> res(img2.shape());
+        
+            static const P desired[] = {P(-0.5), P(1.5), P(0.5), P(-0.5), P(-0.5), P(1.5), P(0.5)};
+            boundaryVectorDistance(img2, res, true, InterpixelBoundary);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+        {
+            //InnerBoundary and image border
+            MultiArray<1, P> res(img2.shape());
+        
+            static const P desired[] = {P(0), P(1), P(0), P(0), P(0), P(1), P(0) };
+            boundaryVectorDistance(img2, res, true, InnerBoundary);
+            shouldEqualSequence(res.begin(), res.end(), desired);
+        }
+    }
+};
+
+struct EccentricityTest
+{
+    void testEccentricityCenters()
+    {
+        typedef Shape2 Point;
+        typedef Shape3 Point3;
+        {
+            MultiArray<2, int> labels(Shape2(4,2), 1);
+            labels.subarray(Shape2(2,0), Shape2(4,2)) = 2;
+
+            ArrayVector<Point> centers;
+            MultiArray<2, float> distances(labels.shape());
+            eccentricityTransformOnLabels(labels, distances, centers);
+
+            shouldEqual(centers.size(), 3);
+            shouldEqual(centers[1], Point(1,1));
+            shouldEqual(centers[2], Point(3,1));
+
+            float ref[] = {1.41421f, 1, 1.41421f, 1, 1, 0, 1, 0 };
+            shouldEqualSequenceTolerance(distances.begin(), distances.end(), ref, 1e-5f);
+        }
+        {
+            int image_data_small[100] = {
+                1, 2, 3, 3, 3, 3, 2, 2, 4, 4,
+                2, 2, 2, 3, 3, 3, 2, 2, 2, 4,
+                5, 2, 2, 2, 2, 2, 2, 6, 2, 2,
+                5, 5, 2, 2, 2, 2, 6, 6, 2, 2,
+                5, 5, 5, 5, 6, 2, 6, 2, 2, 2,
+                5, 5, 5, 5, 6, 6, 6, 2, 2, 7,
+                5, 5, 2, 2, 6, 6, 2, 2, 2, 7,
+                5, 5, 2, 2, 2, 2, 2, 2, 2, 7,
+                5, 5, 2, 2, 2, 2, 2, 7, 7, 7,
+                5, 5, 2, 2, 7, 7, 7, 7, 7, 7
+            };
+            MultiArrayView<2, int> labels(Shape2(10,10), image_data_small);
+
+            ArrayVector<Point> centers;
+            MultiArray<2, float> distances(labels.shape());
+            eccentricityTransformOnLabels(labels, distances, centers);
+
+            shouldEqual(centers.size(), 8);
+
+            Point centers_ref[] = {
+                Point(0, 0),
+                Point(8, 2),
+                Point(3, 1),
+                Point(9, 1),
+                Point(1, 5),
+                Point(6, 4),
+                Point(8, 8)
+            };
+            shouldEqualSequence(centers.begin()+1, centers.end(), centers_ref);
+
+            float dist_ref[] = {
+                0.000000f, 8.656855f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 2.828427f, 2.414214f, 1.414214f, 1.000000f,
+                9.242640f, 8.242640f, 7.242641f, 0.000000f, 1.000000f, 2.000000f, 2.414214f, 1.414214f, 1.000000f, 0.000000f,
+                3.414214f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 0.000000f, 1.000000f,
+                2.414214f, 2.000000f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 1.000000f, 1.414214f, 1.000000f, 1.414214f,
+                1.414214f, 1.000000f, 1.414214f, 2.414214f, 2.828427f, 5.242640f, 0.000000f, 2.414214f, 2.000000f, 2.414214f,
+                1.000000f, 0.000000f, 1.000000f, 2.000000f, 2.414214f, 1.414214f, 1.000000f, 3.414214f, 3.000000f, 3.414214f,
+                1.414214f, 1.000000f, 9.656855f, 8.656855f, 2.828427f, 2.414214f, 4.828427f, 4.414214f, 4.000000f, 2.414214f,
+                2.414214f, 2.000000f, 9.242641f, 8.242641f, 7.242641f, 6.242641f, 5.828427f, 5.414214f, 5.000000f, 1.414214f,
+                3.414214f, 3.000000f, 9.656855f, 8.656855f, 7.656855f, 7.242641f, 6.828427f, 1.000000f, 0.000000f, 1.000000f,
+                4.414214f, 4.000000f, 10.071068f, 9.071068f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f,
+            };
+            shouldEqualSequenceTolerance(distances.begin(), distances.end(), dist_ref, 1e-5f);
+        }
+        {
+            MultiArrayView<2, unsigned int> labels(Shape2(100, 100), eccTrafo_data);
+
+            ArrayVector<Point> centers;
+            MultiArray<2, float> distances(labels.shape());
+            eccentricityTransformOnLabels(labels, distances, centers);
+
+            shouldEqual(centers.size(), 98);
+
+            Point centers_ref[98];
+            for (int i=0; i<98; ++i) {
+                centers_ref[i] = Point(eccTrafo_centers[2*i], eccTrafo_centers[2*i+1]);
+            }
+            shouldEqualSequence(centers.begin(), centers.end(), centers_ref);
+
+            shouldEqualSequenceTolerance(distances.begin(), distances.end(), eccTrafo_ref, 1e-5f);
+        }
+        {
+            MultiArrayView<3, unsigned int> labels(Shape3(40, 40, 40), eccTrafo_volume);
+
+            ArrayVector<Point3> centers;
+            MultiArray<3, float> distances(labels.shape());
+            eccentricityTransformOnLabels(labels, distances, centers);
+
+            shouldEqual(centers.size(), 221);
+
+            Point3 centers_ref[221];
+            for (int i=0; i<221; ++i) {
+                centers_ref[i] = Point3(eccTrafo_volume_centers[3*i], eccTrafo_volume_centers[3*i+1], eccTrafo_volume_centers[3*i+2]);
+            }
+            shouldEqualSequence(centers.begin(), centers.end(), centers_ref);
+
+            shouldEqualSequenceTolerance(distances.begin(), distances.end(), eccTrafo_volume_ref, 1e-5f);
+        }
     }
 };
 
 
+struct SkeletonTest
+{
+    void testSkeleton()
+    {
+        MultiArray<2, UInt8> data;
+        importImage("blatt.xv", data);
+        MultiArray<2, UInt8> skel(data.shape());
+        MultiArray<2, float> desired(data.shape());
+
+        //USETICTOC;
+        {
+            //TIC;
+            skeletonizeImage(data, skel,
+                        SkeletonOptions().dontPrune());
+            //TOC;
+            //exportImage(skel, "raw_skeleton.tif");
+            importImage("raw_skeleton.xv", desired);
+            should(skel == desired);
+        }
+        {
+            MultiArray<2, float> skel(data.shape());
+            skeletonizeImage(data, skel,
+                        SkeletonOptions().returnLength());
+            //exportImage(skel, "skeleton_length.tif");
+            importImage("skeleton_length.xv", desired);
+            should(skel == desired);
+        }
+        {
+            skeletonizeImage(data, skel,
+                        SkeletonOptions().pruneLength(100.0));
+            //exportImage(skel, "skeleton_length_greater_100.tif");
+            importImage("skeleton_length_greater_100.xv", desired);
+            should(skel == desired);
+        }
+        {
+            skeletonizeImage(data, skel,
+                        SkeletonOptions().pruneLengthRelative(0.5));
+            //exportImage(skel, "skeleton_length_greater_50_percent.tif");
+            importImage("skeleton_length_greater_50_percent.xv", desired);
+            should(skel == desired);
+        }
+        {
+            MultiArray<2, float> skel(data.shape());
+            skeletonizeImage(data, skel,
+                        SkeletonOptions().returnSalience());
+            //exportImage(skel, "skeleton_salience.tif");
+            importImage("skeleton_salience.xv", desired);
+            should(skel == desired);
+        }
+        {
+            skeletonizeImage(data, skel,
+                        SkeletonOptions().pruneSalience(10.0));
+            //exportImage(skel, "skeleton_salience_greater_10.tif");
+            importImage("skeleton_salience_greater_10.xv", desired);
+            should(skel == desired);
+        }
+        {
+            skeletonizeImage(data, skel,
+                        SkeletonOptions().pruneSalienceRelative(0.6));
+            //exportImage(skel, "skeleton_salience_greater_60_percent.tif");
+            importImage("skeleton_salience_greater_60_percent.xv", desired);
+            should(skel == desired);
+        }
+        {
+            skeletonizeImage(data, skel,
+                        SkeletonOptions().pruneTopology());
+            //exportImage(skel, "skeleton_topology.tif");
+            importImage("skeleton_topology.xv", desired);
+            should(skel == desired);
+        }
+        {
+            skeletonizeImage(data, skel,
+                        SkeletonOptions().pruneTopology(false));
+            //exportImage(skel, "skeleton_topology_without_center.tif");
+            importImage("skeleton_topology_without_center.xv", desired);
+            should(skel == desired);
+        }
+    }
+
+    void testSkeletonFeatures()
+    {
+        MultiArray<2, UInt8> data;
+        importImage("blatt.xv", data);
+        ArrayVector<SkeletonFeatures> features;
+
+        {
+            extractSkeletonFeatures(data, features);
+            int label=255;
+            shouldEqual(features[label].center, Shape2(255, 255));
+            shouldEqualTolerance(features[label].diameter, 545.4823227814104, 1e-15);
+            shouldEqualTolerance(features[label].euclidean_diameter, 501.86551983574248, 1e-15);
+            shouldEqualTolerance(features[label].total_length, 1650.0012254892786, 1e-15);
+            shouldEqualTolerance(features[label].average_length, 268.45282570696946, 1e-15);
+            shouldEqual(features[label].branch_count, 6);
+            shouldEqual(features[label].hole_count, 1);
+            shouldEqual(features[label].terminal1, Shape2(133, 472));
+            shouldEqual(features[label].terminal2, Shape2(378, 34));
+        }
+    }
+};
+
 
-struct SimpleAnalysisTestSuite
+struct DistanceTransformTestSuite
 : public vigra::test_suite
 {
-    SimpleAnalysisTestSuite()
-    : vigra::test_suite("SimpleAnalysisTestSuite")
+    DistanceTransformTestSuite()
+    : vigra::test_suite("DistanceTransformTestSuite")
     {
         add( testCase( &MultiDistanceTest::testDistanceVolumes));
+        add( testCase( &MultiDistanceTest::testVectorDistanceBug));
         add( testCase( &MultiDistanceTest::testDistanceAxesPermutation));
-        add( testCase( &MultiDistanceTest::testDistanceVolumesAnisoptopic));
+        add( testCase( &MultiDistanceTest::testDistanceVolumesAnisotropic));
         add( testCase( &MultiDistanceTest::distanceTransform2DCompare));
         add( testCase( &MultiDistanceTest::distanceTest1D));
+        add( testCase( &BoundaryMultiDistanceTest::distanceTest1D));
+        add( testCase( &BoundaryMultiDistanceTest::testDistanceVolumes));
+        add( testCase( &BoundaryMultiDistanceTest::vectorDistanceTest1D));
+        add( testCase( &EccentricityTest::testEccentricityCenters));
+        add( testCase( &SkeletonTest::testSkeleton));
+        add( testCase( &SkeletonTest::testSkeletonFeatures));
     }
 };
 
 int main(int argc, char ** argv)
 {
-    SimpleAnalysisTestSuite test;
+    DistanceTransformTestSuite test;
 
     int failed = test.run(vigra::testsToBeExecuted(argc, argv));
 
diff --git a/test/multidistance/test_data.hxx b/test/multidistance/test_data.hxx
new file mode 100644
index 0000000..ed65238
--- /dev/null
+++ b/test/multidistance/test_data.hxx
@@ -0,0 +1,8498 @@
+/************************************************************************/
+/*                                                                      */
+/*                Copyright 2011 by Ullrich Koethe                      */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#ifndef VIGRA_MULTIDISTANCE_TEST_DATA_HXX
+#define VIGRA_MULTIDISTANCE_TEST_DATA_HXX
+
+static double volume_data[4200] = {
+255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 0.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 0.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 255.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 255.0, 255.0,
+255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0,
+255.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+};
+
+// reference squred distance for the foreground of above volume
+static double ref_dist2[4200] = {
+5.0, 4.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 4.0, 4.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 4.0, 4.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0,
+1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 2.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 5.0, 6.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 2.0, 3.0, 5.0, 5.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 1.0, 2.0,
+2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0,
+1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 2.0, 3.0, 5.0, 6.0, 9.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 3.0, 5.0, 6.0, 5.0, 4.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 5.0, 4.0, 4.0,
+2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 3.0,
+2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0,
+1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0,
+1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 1.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 2.0, 1.0, 2.0, 4.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 2.0, 3.0, 2.0, 3.0, 5.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 2.0, 4.0, 5.0, 5.0, 5.0, 4.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 3.0, 5.0, 5.0, 4.0,
+2.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 5.0, 5.0,
+2.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 3.0,
+2.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0,
+2.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0,
+2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 2.0, 1.0, 2.0, 3.0, 4.0, 4.0,
+0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 3.0, 2.0, 3.0, 2.0,
+2.0, 1.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0, 5.0, 5.0,
+2.0, 1.0, 1.0, 0.0, 0.0, 1.0, 2.0, 3.0, 5.0, 3.0,
+2.0, 2.0, 1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 5.0, 4.0,
+2.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 2.0, 3.0,
+5.0, 4.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0,
+0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 1.0, 2.0, 1.0,
+1.0, 1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 4.0, 3.0,
+1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 5.0, 6.0, 3.0, 2.0,
+1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 2.0, 3.0, 6.0, 5.0,
+2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 6.0,
+8.0, 4.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 3.0, 2.0, 2.0, 1.0,
+1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 4.0, 5.0, 2.0, 1.0,
+1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 4.0, 5.0, 6.0, 3.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 9.0,
+5.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 3.0, 2.0, 1.0, 0.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 4.0, 4.0, 2.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 4.0,
+4.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 1.0, 1.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 1.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 1.0,
+1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0,
+1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 2.0, 3.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 0.0, 1.0, 1.0, 2.0, 3.0, 2.0, 0.0, 1.0,
+1.0, 1.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 5.0, 5.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 1.0, 1.0, 2.0, 2.0, 3.0, 0.0, 1.0, 1.0, 1.0,
+1.0, 1.0, 1.0, 2.0, 2.0, 3.0, 5.0, 5.0, 0.0, 1.0,
+2.0, 2.0, 2.0, 3.0, 2.0, 3.0, 4.0, 5.0, 8.0, 8.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0,
+2.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0,
+1.0, 2.0, 3.0, 5.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0,
+1.0, 2.0, 2.0, 3.0, 5.0, 6.0, 0.0, 0.0, 1.0, 2.0,
+2.0, 2.0, 3.0, 5.0, 5.0, 6.0, 8.0, 9.0, 1.0, 1.0,
+2.0, 5.0, 5.0, 5.0, 5.0, 6.0, 8.0, 9.0, 12.0, 13.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
+3.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
+3.0, 5.0, 6.0, 9.0, 0.0, 1.0, 0.0, 1.0, 1.0, 2.0,
+2.0, 3.0, 5.0, 6.0, 9.0, 11.0, 1.0, 1.0, 1.0, 2.0,
+4.0, 5.0, 5.0, 6.0, 8.0, 9.0, 12.0, 14.0, 2.0, 2.0,
+3.0, 5.0, 8.0, 8.0, 9.0, 11.0, 13.0, 14.0, 16.0, 16.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0,
+5.0, 6.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0,
+5.0, 6.0, 9.0, 10.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0,
+5.0, 6.0, 9.0, 9.0, 9.0, 9.0, 1.0, 2.0, 2.0, 3.0,
+5.0, 6.0, 8.0, 9.0, 10.0, 9.0, 9.0, 9.0, 4.0, 5.0,
+4.0, 4.0, 5.0, 8.0, 10.0, 9.0, 9.0, 9.0, 9.0, 9.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 0.0, 1.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 3.0, 5.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 5.0, 6.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 5.0, 6.0,
+8.0, 8.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 4.0, 5.0,
+6.0, 5.0, 5.0, 5.0, 1.0, 1.0, 1.0, 2.0, 4.0, 5.0,
+8.0, 8.0, 5.0, 4.0, 4.0, 4.0, 2.0, 3.0, 2.0, 2.0,
+3.0, 6.0, 6.0, 5.0, 5.0, 4.0, 4.0, 4.0, 5.0, 2.0,
+1.0, 1.0, 2.0, 5.0, 5.0, 4.0, 4.0, 4.0, 4.0, 4.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
+4.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+1.0, 2.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 1.0, 1.0, 2.0, 5.0, 6.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 6.0, 8.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 5.0, 6.0, 6.0, 5.0,
+0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0, 6.0, 5.0,
+5.0, 4.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0, 5.0, 6.0,
+3.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 5.0, 6.0,
+6.0, 5.0, 2.0, 1.0, 1.0, 1.0, 3.0, 2.0, 1.0, 1.0,
+2.0, 5.0, 3.0, 2.0, 2.0, 1.0, 1.0, 1.0, 2.0, 1.0,
+0.0, 0.0, 1.0, 4.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 4.0, 5.0,
+8.0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+4.0, 5.0, 8.0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 2.0, 4.0, 5.0, 8.0, 9.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 1.0, 1.0, 2.0, 5.0, 6.0, 6.0, 5.0, 0.0, 0.0,
+0.0, 1.0, 2.0, 2.0, 2.0, 3.0, 6.0, 6.0, 3.0, 2.0,
+0.0, 1.0, 1.0, 2.0, 3.0, 5.0, 5.0, 6.0, 5.0, 3.0,
+2.0, 1.0, 1.0, 2.0, 4.0, 5.0, 5.0, 6.0, 6.0, 5.0,
+2.0, 1.0, 1.0, 1.0, 4.0, 4.0, 4.0, 4.0, 5.0, 5.0,
+3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 1.0,
+2.0, 2.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0,
+0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 4.0, 6.0,
+5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
+5.0, 5.0, 4.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+2.0, 3.0, 6.0, 5.0, 4.0, 4.0, 0.0, 0.0, 0.0, 1.0,
+1.0, 2.0, 3.0, 5.0, 8.0, 5.0, 4.0, 4.0, 0.0, 1.0,
+1.0, 2.0, 3.0, 5.0, 5.0, 6.0, 6.0, 3.0, 2.0, 1.0,
+1.0, 2.0, 2.0, 3.0, 6.0, 8.0, 8.0, 6.0, 3.0, 2.0,
+1.0, 0.0, 2.0, 3.0, 5.0, 6.0, 8.0, 6.0, 5.0, 4.0,
+2.0, 1.0, 0.0, 0.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0,
+2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
+1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 5.0, 3.0,
+2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0,
+5.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0,
+5.0, 6.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0,
+2.0, 3.0, 6.0, 8.0, 5.0, 2.0, 1.0, 1.0, 1.0, 2.0,
+2.0, 3.0, 5.0, 6.0, 9.0, 6.0, 3.0, 2.0, 1.0, 1.0,
+2.0, 3.0, 5.0, 6.0, 6.0, 5.0, 5.0, 5.0, 2.0, 1.0,
+0.0, 0.0, 5.0, 6.0, 8.0, 6.0, 5.0, 3.0, 2.0, 2.0,
+1.0, 0.0, 0.0, 0.0, 4.0, 4.0, 4.0, 3.0, 2.0, 2.0,
+1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
+1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 4.0, 5.0, 2.0, 1.0,
+1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 5.0, 5.0,
+2.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0,
+5.0, 4.0, 2.0, 1.0, 0.0, 0.0, 2.0, 2.0, 2.0, 3.0,
+5.0, 6.0, 5.0, 4.0, 2.0, 1.0, 0.0, 0.0, 4.0, 5.0,
+5.0, 6.0, 6.0, 5.0, 5.0, 3.0, 2.0, 1.0, 0.0, 0.0,
+5.0, 6.0, 8.0, 6.0, 3.0, 2.0, 3.0, 2.0, 1.0, 0.0,
+0.0, 0.0, 6.0, 5.0, 5.0, 5.0, 2.0, 1.0, 1.0, 1.0,
+1.0, 0.0, 0.0, 0.0, 3.0, 2.0, 2.0, 2.0, 1.0, 1.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+1.0, 1.0, 2.0, 4.0, 4.0, 5.0, 5.0, 4.0, 1.0, 0.0,
+0.0, 0.0, 1.0, 1.0, 2.0, 4.0, 4.0, 5.0, 3.0, 2.0,
+1.0, 0.0, 0.0, 0.0, 2.0, 2.0, 3.0, 5.0, 5.0, 5.0,
+2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 5.0, 5.0, 5.0, 6.0,
+6.0, 5.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 8.0, 8.0,
+8.0, 6.0, 3.0, 2.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0,
+9.0, 8.0, 6.0, 3.0, 2.0, 1.0, 1.0, 1.0, 0.0, 0.0,
+0.0, 0.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0, 1.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 1.0, 1.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+4.0, 4.0, 5.0, 8.0, 9.0, 5.0, 2.0, 1.0, 1.0, 0.0,
+0.0, 0.0, 4.0, 4.0, 5.0, 8.0, 9.0, 5.0, 2.0, 1.0,
+1.0, 0.0, 0.0, 0.0, 5.0, 5.0, 6.0, 9.0, 6.0, 3.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 8.0, 8.0, 6.0,
+3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.0, 6.0,
+5.0, 3.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+6.0, 5.0, 3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 3.0, 2.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+9.0, 9.0, 10.0, 13.0, 9.0, 4.0, 1.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 9.0, 9.0, 10.0, 9.0, 6.0, 4.0, 1.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 10.0, 10.0, 10.0, 6.0, 3.0, 2.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.0, 6.0, 5.0, 5.0,
+2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 3.0,
+2.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+3.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+16.0, 16.0, 17.0, 13.0, 9.0, 4.0, 1.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 16.0, 16.0, 13.0, 8.0, 5.0, 4.0, 1.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 13.0, 10.0, 9.0, 5.0, 2.0, 1.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 5.0, 4.0, 4.0,
+1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 2.0,
+1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+};
+
+
+//data and ref for boundaryMultiDistance
+static double bndMltDst_data[2500] = {
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 0, 201, 201, 201, 0, 0, 201, 201, 201, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 201, 201, 201, 0, 201, 201, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 201, 201, 201, 0, 0, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 201, 201, 0, 0, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 254, 254, 254, 254, 254, 254, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 0, 0, 254, 254, 254, 254, 254, 254, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 0, 254, 254, 254, 254, 254, 254, 254, 254, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 255, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 254, 254, 254, 254, 254, 254, 254, 254, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 225, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 116, 169, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 116, 116, 116, 116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    116, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static double bndMltDst_ref[2500] = {
+    23.500000, 22.500000, 21.500000, 20.500000, 19.500000, 18.500000, 17.500000, 16.500000, 15.500000, 14.500000, 13.500000, 12.500000, 11.500000, 10.500000, 9.500000, 8.500000, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.972136, 4.500000, 4.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.50 [...]
+    23.500000, 22.500000, 21.500000, 20.500000, 19.500000, 18.500000, 17.500000, 16.500000, 15.500000, 14.500000, 13.500000, 12.500000, 11.500000, 10.500000, 9.500000, 8.500000, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 3.500000, 3.500000, 3.623106, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 2.662278, 1.736068, 0.914214, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 4.59 [...]
+    23.520824, 22.521729, 21.522715, 20.523796, 19.524984, 18.526299, 17.527756, 16.529387, 15.531219, 14.533297, 13.535668, 12.538404, 11.541595, 10.545361, 9.549875, 8.555386, 7.562258, 6.571068, 5.582763, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 2.662278, 2.500000, 2.500000, 2.662278, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.105551, 2.328427, 1.736068, 1.500000, 1.736068, 2.328427, 3.105551, 3.972136, 4.88 [...]
+    23.583189, 22.586792, 21.590721, 20.595022, 19.599751, 18.604973, 17.610771, 16.617243, 15.624516, 14.632746, 13.642136, 12.652946, 11.665525, 10.680340, 9.698039, 8.719544, 7.746211, 6.780110, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 1.736068, 1.500000, 1.500000, 1.736068, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 3.105551, 2.662278, 2.500000, 2.662278, 3.105551, 3.742641, 4.500000, 5.33 [...]
+    23.686773, 22.694826, 21.703604, 20.713203, 19.723749, 18.735384, 17.748287, 16.762676, 15.778821, 14.797058, 13.817822, 12.841664, 11.869317, 10.901754, 9.940307, 8.986833, 8.044003, 7.115773, 6.208204, 5.330952, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 3.972136, 3.623106, 3.500000, 3.623106, 3.972136, 4.500000, 5.156854, 5.50 [...]
+    23.831051, 22.845236, 21.860680, 20.877558, 19.896078, 18.916489, 17.939089, 16.964249, 15.992422, 15.024175, 14.060220, 13.101471, 12.149111, 11.204700, 10.270329, 9.348858, 8.444272, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.972136, 4.885165, 4.599020, 4.500000, 4.599020, 4.885165, 4.599020, 4.500000, 4.5 [...]
+    24.015301, 23.037205, 22.061028, 21.087032, 20.115528, 19.146883, 18.181541, 17.220045, 16.263054, 15.311388, 14.366069, 13.428389, 12.500000, 11.541595, 10.545361, 9.549875, 8.555386, 7.562258, 6.571068, 5.582763, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 4.500000, 5.330952, 5.582763, 5.156854, 4.500000, 3.972136, 3.623106, 3.500000, 3.5 [...]
+    24.238634, 23.269728, 22.303509, 21.340330, 20.380613, 19.424858, 18.473665, 17.527756, 16.588007, 15.624516, 14.632746, 13.642136, 12.652946, 11.665525, 10.680340, 9.698039, 8.719544, 7.746211, 6.780110, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 5.156854, 5.156854, 4.500000, 3.742641, 3.105551, 2.662278, 2.500000, 2.5 [...]
+    24.500000, 23.541630, 22.586792, 21.635944, 20.689621, 19.723749, 18.735384, 17.748287, 16.762676, 15.778821, 14.797058, 13.817822, 12.841664, 11.869317, 10.901754, 9.940307, 8.986833, 8.044003, 7.115773, 6.208204, 5.330952, 4.500000, 3.742641, 3.105551, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 4.500000, 3.742641, 3.105551, 2.328427, 1.736068, 1.500000, 1.5 [...]
+    24.798222, 23.831051, 22.845236, 21.860680, 20.877558, 19.896078, 18.916489, 17.939089, 16.964249, 15.992422, 15.024175, 14.060220, 13.101471, 12.149111, 11.204700, 10.270329, 9.348858, 8.444272, 7.562258, 6.711102, 5.903124, 5.156854, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.972136, 3.972136, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0. [...]
+    24.995098, 24.015301, 23.037205, 22.061028, 21.087032, 20.115528, 19.146883, 18.181541, 17.220045, 16.263054, 15.311388, 14.366069, 13.428389, 12.500000, 11.583046, 10.680340, 9.795630, 8.933981, 8.102325, 7.310250, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 1.500000, 1.500000, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.105551, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0. [...]
+    24.955845, 24.238634, 23.269728, 22.303509, 21.340330, 20.380613, 19.424858, 18.473665, 17.527756, 16.588007, 15.655495, 14.731546, 13.817822, 12.916408, 12.029964, 11.161903, 10.316654, 9.500000, 8.555386, 7.562258, 6.571068, 5.582763, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 2.500000, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 1.736068, 2.328427, 3.105551, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0 [...]
+    24.258837, 23.541630, 22.845236, 22.171568, 21.431713, 20.689621, 19.748457, 18.813208, 17.884777, 16.964249, 16.052946, 15.152476, 14.264823, 13.392444, 12.538404, 11.665525, 10.680340, 9.698039, 8.719544, 7.746211, 6.780110, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.500000, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 2.500000, 1.736068, 0.914214, 0.500000, 0.500000, 0 [...]
+    23.541630, 22.845236, 22.127417, 21.431713, 20.760292, 20.018284, 19.298990, 18.604973, 17.939089, 17.304493, 16.500000, 15.624516, 14.764338, 13.817822, 12.841664, 11.869317, 10.901754, 9.940307, 8.986833, 8.044003, 7.115773, 6.208204, 5.330952, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.972136, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 1.736068, 1.500000, 1.736068, 1.736068, 0.914214, 0.500000, 0 [...]
+    22.845236, 22.127417, 21.431713, 20.713203, 20.018284, 19.349434, 18.604973, 17.884777, 17.191807, 16.529387, 15.901219, 15.311388, 14.764338, 13.922205, 13.101471, 12.149111, 11.204700, 10.270329, 9.348858, 8.444272, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 1.500000, 0.914214, 0.500000, 0.914214, 1.736068, 1.736068, 1.500000,  [...]
+    22.171568, 21.431713, 20.713203, 20.018284, 19.298990, 18.604973, 17.939089, 17.191807, 16.470562, 15.778821, 15.120500, 14.500000, 13.922205, 13.392444, 12.538404, 11.706555, 10.901754, 10.130146, 9.348858, 8.444272, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 4.500000, 3.742641, 3.105551, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 2.500000,  [...]
+    21.431713, 20.760292, 20.018284, 19.298990, 18.604973, 17.884777, 17.191807, 16.529387, 15.778821, 15.056349, 14.366069, 13.712670, 13.101471, 12.538404, 12.029964, 11.161903, 10.316654, 9.500000, 8.719544, 7.985281, 7.115773, 6.208204, 5.330952, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.156854, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 3 [...]
+    20.713203, 20.018284, 19.349434, 18.604973, 17.884777, 17.191807, 16.470562, 15.778821, 15.120500, 14.366069, 13.642136, 12.953624, 12.306249, 11.706555, 11.161903, 10.680340, 9.795630, 8.933981, 8.102325, 7.310250, 6.571068, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4. [...]
+    20.018284, 19.298990, 18.604973, 17.939089, 17.191807, 16.470562, 15.778821, 15.056349, 14.366069, 13.712670, 12.953624, 12.227922, 11.541595, 10.901754, 10.316654, 9.795630, 9.348858, 8.444272, 7.562258, 6.711102, 5.903124, 5.156854, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 3.742641, 3.105551, 2.662278, 2.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 3.9 [...]
+    19.349434, 18.604973, 17.884777, 17.191807, 16.529387, 15.778821, 15.056349, 14.366069, 13.642136, 12.953624, 12.306249, 11.541595, 10.813708, 10.130146, 9.500000, 8.933981, 8.444272, 7.985281, 7.115773, 6.208204, 5.330952, 4.500000, 3.742641, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.623106, 3.105551, 2.328427, 1.736068, 1.500000, 1.500000, 1.500000, 0.500000, 0.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.662278, 3.10 [...]
+    18.709373, 17.939089, 17.191807, 16.470562, 15.778821, 15.120500, 14.366069, 13.642136, 12.953624, 12.227922, 11.541595, 10.901754, 10.130146, 9.399495, 8.719544, 8.102325, 7.562258, 7.115773, 6.571068, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328 [...]
+    18.101076, 17.304493, 16.529387, 15.778821, 15.056349, 14.366069, 13.712670, 12.953624, 12.227922, 11.541595, 10.813708, 10.130146, 9.500000, 8.719544, 7.985281, 7.310250, 6.711102, 6.208204, 5.824555, 5.156854, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.7360 [...]
+    17.304493, 16.704651, 15.901219, 15.120500, 14.366069, 13.642136, 12.953624, 12.306249, 11.541595, 10.813708, 10.130146, 9.399495, 8.719544, 8.102325, 7.310250, 6.571068, 5.903124, 5.330952, 4.885165, 4.500000, 3.742641, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 0.914214, 0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.500000, 1.736068, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.50000 [...]
+    16.500000, 15.901219, 15.311388, 14.500000, 13.712670, 12.953624, 12.227922, 11.541595, 10.901754, 10.130146, 9.399495, 8.719544, 7.985281, 7.310250, 6.711102, 5.903124, 5.156854, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.500000, 2.500000, 2.662278, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 1.500000 [...]
+    15.624516, 15.120500, 14.500000, 13.922205, 13.101471, 12.306249, 11.541595, 10.813708, 10.130146, 9.500000, 8.719544, 7.985281, 7.310250, 6.571068, 5.903124, 5.330952, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.500000, 3.500000, 3.623106, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, [...]
+    14.632746, 14.264823, 13.712670, 13.101471, 12.538404, 11.706555, 10.901754, 10.130146, 9.399495, 8.719544, 8.102325, 7.310250, 6.571068, 5.903124, 5.156854, 4.500000, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.736068, 2.328427, 3.105551, 3.972136, 3.972136, 3.623106, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068,  [...]
+    13.642136, 13.392444, 12.916408, 12.306249, 11.706555, 11.161903, 10.316654, 9.500000, 8.719544, 7.985281, 7.310250, 6.711102, 5.903124, 5.156854, 4.500000, 3.742641, 3.105551, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 3 [...]
+    12.652946, 12.538404, 12.029964, 11.541595, 10.901754, 10.316654, 9.795630, 8.933981, 8.102325, 7.310250, 6.571068, 5.903124, 5.330952, 4.500000, 3.742641, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.742641, 3.742641, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3. [...]
+    11.665525, 11.541595, 11.161903, 10.680340, 10.130146, 9.500000, 8.933981, 8.444272, 7.562258, 6.711102, 5.903124, 5.156854, 4.500000, 3.972136, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 4.500000, 3.742641, 3.105551, 2.328427, 1.736068, 1.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.9 [...]
+    10.680340, 10.545361, 10.316654, 9.795630, 9.348858, 8.719544, 8.102325, 7.562258, 7.115773, 6.208204, 5.330952, 4.500000, 3.742641, 3.105551, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.105551, 3.742641, 4.500000, 5.156854, 5.156854, 4.500000, 3.742641, 3.105551, 2.662278, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.742641, 4.500 [...]
+    9.698039, 9.549875, 9.500000, 8.933981, 8.444272, 7.985281, 7.310250, 6.711102, 6.208204, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.972136, 4.500000, 5.156854, 5.903124, 5.903124, 5.156854, 4.500000, 3.972136, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 5.156854 [...]
+    8.719544, 8.555386, 8.500000, 8.102325, 7.562258, 7.115773, 6.571068, 5.903124, 5.330952, 4.885165, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 5.330952, 5.903124, 6.500000, 5.903124, 5.330952, 4.885165, 4.500000, 3.742641, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 5.156854, 5.903124 [...]
+    7.746211, 7.562258, 7.500000, 7.310250, 6.711102, 6.208204, 5.824555, 5.156854, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 3.972136, 4.500000, 5.156854, 5.582763, 5.500000, 5.500000, 5.156854, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.623106, 3.972136, 4.500000, 5.156854, 5.903124, 6.571068 [...]
+    6.780110, 6.571068, 6.500000, 6.500000, 5.903124, 5.330952, 4.885165, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 1.736068, 2.328427, 3.105551, 3.972136, 4.885165, 5.330952, 4.885165, 4.599020, 4.500000, 4.500000, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 4.885165, 5.330952, 5.903124, 6.571068, 7.310250 [...]
+    5.824555, 5.582763, 5.500000, 5.500000, 5.156854, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.105551, 3.742641, 4.500000, 5.156854, 4.500000, 3.972136, 3.623106, 3.500000, 3.500000, 3.500000, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.623106, 3.972136, 4.500000, 5.156854, 5.824555, 6.208204, 6.711102, 7.310250, 7.985281 [...]
+    4.885165, 4.599020, 4.500000, 4.500000, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.972136, 4.500000, 4.885165, 4.500000, 3.742641, 3.105551, 2.662278, 2.500000, 2.500000, 2.500000, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 4.885165, 5.330952, 5.903124, 6.571068, 7.115773, 7.562258, 8.102325, 8.719544 [...]
+    3.972136, 3.623106, 3.500000, 3.500000, 3.500000, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 1.500000, 1.500000, 1.500000, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.623106, 3.972136, 4.500000, 5.156854, 5.824555, 6.208204, 6.711102, 7.310250, 7.985281, 8.444272, 8.933981, 9.500000 [...]
+    3.105551, 2.662278, 2.500000, 2.500000, 2.500000, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 3.972136, 3.623106, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 4.885165, 5.330952, 5.903124, 6.571068, 7.115773, 7.562258, 8.102325, 8.719544, 9.348858, 9.795630, 10.31665 [...]
+    2.328427, 1.736068, 1.500000, 1.500000, 1.500000, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 5.156854, 5.824555, 6.208204, 6.711102, 7.310250, 7.985281, 8.444272, 8.933981, 9.500000, 10.130146, 10.680340, 11.161 [...]
+    1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 3.972136, 4.500000, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 3.972136, 4.500000, 5.156854, 5.903124, 6.571068, 7.115773, 7.562258, 8.102325, 8.719544, 9.348858, 9.795630, 10.316654, 10.901754, 11.541595, 12.02 [...]
+    0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 1.500000, 1.736068, 2.328427, 3.105551, 3.972136, 4.885165, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.330952, 5.903124, 6.571068, 7.310250, 7.985281, 8.444272, 8.933981, 9.500000, 10.130146, 10.680340, 11.161903, 11.706555, 12.306249, 12. [...]
+    0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.500000, 1.500000, 1.736068, 2.328427, 2.500000, 2.662278, 3.105551, 3.742641, 4.500000, 5.330952, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.310250, 7.985281, 8.719544, 9.348858, 9.795630, 10.316654, 10.901754, 11.541595, 12.029964, 12.538404, 13.101471, 13 [...]
+    0.500000, 0.914214, 1.736068, 2.328427, 2.500000, 2.500000, 2.500000, 2.662278, 3.105551, 3.500000, 3.623106, 3.972136, 4.500000, 5.156854, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 4.599020, 5.582763, 6.571068, 7.562258, 8.555386, 9.399495, 10.130146, 10.680340, 11.161903, 11.706555, 12.306249, 12.916408, 13.392444, 13.922205,  [...]
+    1.500000, 1.736068, 2.328427, 3.105551, 3.500000, 3.500000, 3.500000, 3.623106, 3.972136, 4.500000, 4.599020, 4.885165, 5.330952, 5.903124, 5.582763, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.972136, 4.885165, 5.824555, 6.780110, 7.746211, 8.719544, 9.698039, 10.680340, 11.541595, 12.029964, 12.538404, 13.101471, 13.712670, 14.264823, 14.764338,  [...]
+    2.500000, 2.662278, 3.105551, 3.742641, 4.500000, 4.500000, 4.500000, 4.599020, 4.885165, 5.330952, 5.582763, 5.824555, 6.208204, 5.903124, 5.156854, 4.500000, 3.742641, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.742641, 4.500000, 5.330952, 6.208204, 7.115773, 8.044003, 8.986833, 9.940307, 10.901754, 11.869317, 12.841664, 13.392444, 13.922205, 14.500000, 15.120500, 15.624516,  [...]
+    3.500000, 3.623106, 3.972136, 4.500000, 5.156854, 5.500000, 5.500000, 5.582763, 5.824555, 6.208204, 6.571068, 6.780110, 6.208204, 5.330952, 4.500000, 3.742641, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 4.500000, 5.156854, 5.903124, 6.711102, 7.562258, 8.444272, 9.348858, 10.270329, 11.204700, 12.149111, 13.101471, 14.060220, 14.764338, 15.311388, 15.901219, 16.500000, [...]
+    4.500000, 4.599020, 4.885165, 5.330952, 5.903124, 6.500000, 6.500000, 6.571068, 6.780110, 7.115773, 7.562258, 6.780110, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.972136, 4.885165, 5.824555, 6.571068, 7.310250, 8.102325, 8.933981, 9.795630, 10.680340, 11.583046, 12.500000, 13.428389, 14.366069, 15.311388, 16.143316, 16.704651, 17.304493, [...]
+    5.500000, 5.582763, 5.824555, 6.208204, 6.711102, 7.310250, 7.500000, 7.562258, 7.746211, 8.044003, 7.562258, 6.571068, 5.582763, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 4.500000, 5.330952, 6.208204, 7.115773, 7.985281, 8.719544, 9.500000, 10.316654, 11.161903, 12.029964, 12.916408, 13.817822, 14.731546, 15.655495, 16.588007, 17.527756, 18.101076 [...]
+    6.500000, 6.571068, 6.780110, 7.115773, 7.562258, 8.102325, 8.500000, 8.555386, 8.719544, 8.500000, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.972136, 4.885165, 5.824555, 6.711102, 7.562258, 8.444272, 9.348858, 10.130146, 10.901754, 11.706555, 12.538404, 13.392444, 14.264823, 15.152476, 16.052946, 16.964249, 17.884777, 18.81320 [...]
+    7.500000, 7.562258, 7.746211, 8.044003, 8.444272, 8.933981, 9.500000, 9.549875, 9.500000, 8.500000, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.330952, 6.208204, 7.115773, 8.044003, 8.933981, 9.795630, 10.680340, 11.541595, 12.306249, 13.101471, 13.922205, 14.764338, 15.624516, 16.500000, 17.388544, 18.288294, 19.19771 [...]
+};
+
+static double bndMltDstArrayBorder_ref[2500] = {
+    0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000 [...]
+    0.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 0.500000, 0.500000, 1.500000, 1.500000, 1.500000, 1.500000, 0.914214, 0.500000, 0.914214, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 2.500000, 2.328427, 1.736068, 1.500000, 1.736068, 2.328427, 2.500000, 2.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 1.736068, 1.500000, 1.500000, 1.736068, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 3.105551, 2.662278, 2.500000, 2.662278, 3.105551, 3.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 3.972136, 3.623106, 3.500000, 3.623106, 3.972136, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.972136, 4.885165, 4.599020, 4.500000, 4.599020, 4.885165, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 5.582763, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 4.500000, 5.330952, 5.582763, 5.156854, 4.500000, 3.972136, 3.623106, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 7.500000, 7.500000, 7.500000, 7.500000, 7.500000, 7.500000, 7.500000, 7.500000, 7.500000, 7.500000, 6.780110, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 5.156854, 5.156854, 4.500000, 3.742641, 3.105551, 2.662278, 2.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 8.500000, 8.500000, 8.500000, 8.500000, 8.500000, 8.500000, 8.500000, 8.500000, 8.044003, 7.115773, 6.208204, 5.330952, 4.500000, 3.742641, 3.105551, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 4.500000, 3.742641, 3.105551, 2.328427, 1.736068, 1.500000, 1.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 9.500000, 9.500000, 9.500000, 9.500000, 9.500000, 9.500000, 9.348858, 8.444272, 7.562258, 6.711102, 5.903124, 5.156854, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.972136, 3.972136, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 10.500000, 10.500000, 10.500000, 10.500000, 10.500000, 9.795630, 8.933981, 8.102325, 7.310250, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 1.500000, 1.500000, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.105551, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0. [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 11.500000, 11.500000, 11.500000, 11.500000, 11.161903, 10.316654, 9.500000, 8.555386, 7.562258, 6.571068, 5.582763, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 2.500000, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 1.736068, 2.328427, 3.105551, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 11.500000, 12.500000, 12.500000, 12.500000, 11.665525, 10.680340, 9.698039, 8.719544, 7.746211, 6.780110, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.500000, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 2.500000, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 11.500000, 12.500000, 13.500000, 12.841664, 11.869317, 10.901754, 9.940307, 8.986833, 8.044003, 7.115773, 6.208204, 5.330952, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.972136, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 1.736068, 1.500000, 1.736068, 1.736068, 0.914214, 0.500000, 0.914214, 1 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 11.500000, 12.500000, 13.500000, 13.101471, 12.149111, 11.204700, 10.270329, 9.348858, 8.444272, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 1.500000, 0.914214, 0.500000, 0.914214, 1.736068, 1.736068, 1.500000, 1.736068,  [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 11.500000, 12.500000, 13.392444, 12.538404, 11.706555, 10.901754, 10.130146, 9.348858, 8.444272, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 4.500000, 3.742641, 3.105551, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 2.500000, 2.500000,  [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 11.500000, 12.500000, 12.538404, 12.029964, 11.161903, 10.316654, 9.500000, 8.719544, 7.985281, 7.115773, 6.208204, 5.330952, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.156854, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 2.500000, 1 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 11.500000, 12.306249, 11.706555, 11.161903, 10.680340, 9.795630, 8.933981, 8.102325, 7.310250, 6.571068, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 2.500000, 1. [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 11.500000, 11.541595, 10.901754, 10.316654, 9.795630, 9.348858, 8.444272, 7.562258, 6.711102, 5.903124, 5.156854, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 3.742641, 3.105551, 2.662278, 2.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 2.500000, 1.5 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 11.500000, 10.813708, 10.130146, 9.500000, 8.933981, 8.444272, 7.985281, 7.115773, 6.208204, 5.330952, 4.500000, 3.742641, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.623106, 3.105551, 2.328427, 1.736068, 1.500000, 1.500000, 1.500000, 0.500000, 0.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.662278, 2.500000, 1.50 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 10.901754, 10.130146, 9.399495, 8.719544, 8.102325, 7.562258, 7.115773, 6.571068, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 1.500 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.500000, 10.130146, 9.500000, 8.719544, 7.985281, 7.310250, 6.711102, 6.208204, 5.824555, 5.156854, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 1.5000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 10.130146, 9.399495, 8.719544, 8.102325, 7.310250, 6.571068, 5.903124, 5.330952, 4.885165, 4.500000, 3.742641, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 0.914214, 0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.500000, 1.736068, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 1.50000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 9.399495, 8.719544, 7.985281, 7.310250, 6.711102, 5.903124, 5.156854, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.500000, 2.500000, 2.662278, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 1.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 9.500000, 8.719544, 7.985281, 7.310250, 6.571068, 5.903124, 5.330952, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.500000, 3.500000, 3.623106, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 8.719544, 8.102325, 7.310250, 6.571068, 5.903124, 5.156854, 4.500000, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.736068, 2.328427, 3.105551, 3.972136, 3.972136, 3.623106, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.500000, 7.985281, 7.310250, 6.711102, 5.903124, 5.156854, 4.500000, 3.742641, 3.105551, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 8.102325, 7.310250, 6.571068, 5.903124, 5.330952, 4.500000, 3.742641, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.742641, 3.742641, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 7.562258, 6.711102, 5.903124, 5.156854, 4.500000, 3.972136, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 4.500000, 3.742641, 3.105551, 2.328427, 1.736068, 1.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.500000, 7.115773, 6.208204, 5.330952, 4.500000, 3.742641, 3.105551, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.105551, 3.742641, 4.500000, 5.156854, 5.156854, 4.500000, 3.742641, 3.105551, 2.662278, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 6.711102, 6.208204, 5.824555, 4.885165, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.972136, 4.500000, 5.156854, 5.903124, 5.903124, 5.156854, 4.500000, 3.972136, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 5.903124, 5.330952, 4.885165, 4.500000, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 5.330952, 5.903124, 6.500000, 5.903124, 5.330952, 4.885165, 4.500000, 3.742641, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 3.105551, 3.742641, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 5.824555, 5.156854, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 3.972136, 4.500000, 5.156854, 5.582763, 5.500000, 5.500000, 5.156854, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.623106, 3.972136, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.330952, 4.885165, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 1.736068, 2.328427, 3.105551, 3.972136, 4.885165, 5.330952, 4.885165, 4.599020, 4.500000, 4.500000, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 4.885165, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.105551, 3.742641, 4.500000, 5.156854, 4.500000, 3.972136, 3.623106, 3.500000, 3.500000, 3.500000, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.623106, 3.972136, 4.500000, 5.156854, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.972136, 4.500000, 4.885165, 4.500000, 3.742641, 3.105551, 2.662278, 2.500000, 2.500000, 2.500000, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 4.885165, 5.330952, 5.903124, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 3.500000, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 4.500000, 3.972136, 3.623106, 3.105551, 2.328427, 1.736068, 1.500000, 1.500000, 1.500000, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.623106, 3.972136, 4.500000, 5.156854, 5.824555, 6.208204, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 2.500000, 2.500000, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 3.972136, 3.623106, 3.105551, 2.662278, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 3.105551, 3.742641, 4.500000, 4.885165, 5.330952, 5.903124, 6.571068, 7.115773, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 3.742641, 3.105551, 2.662278, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 1.500000, 2.328427, 2.662278, 3.105551, 3.742641, 4.500000, 5.156854, 5.824555, 6.208204, 6.711102, 7.310250, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 3.972136, 4.500000, 3.972136, 3.105551, 2.328427, 1.736068, 1.500000, 0.914214, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 3.972136, 4.500000, 5.156854, 5.903124, 6.571068, 7.115773, 7.562258, 8.102325, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 1.500000, 1.736068, 2.328427, 3.105551, 3.972136, 4.885165, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.330952, 5.903124, 6.571068, 7.310250, 7.985281, 8.444272, 8.500000, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.500000, 1.500000, 1.736068, 2.328427, 2.500000, 2.662278, 3.105551, 3.742641, 4.500000, 5.330952, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.736068, 2.328427, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 5.500000, 6.500000, 7.310250, 7.985281, 8.500000, 8.500000, 8.500000, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 0.914214, 1.736068, 2.328427, 2.500000, 2.500000, 2.500000, 2.662278, 3.105551, 3.500000, 3.623106, 3.972136, 4.500000, 5.156854, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.662278, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 4.599020, 5.582763, 6.571068, 7.500000, 7.500000, 7.500000, 7.500000, 7.500000, 7.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.328427, 3.105551, 3.500000, 3.500000, 3.500000, 3.623106, 3.972136, 4.500000, 4.599020, 4.885165, 5.330952, 5.903124, 5.582763, 4.599020, 3.623106, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 3.105551, 3.972136, 4.885165, 5.824555, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 6.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 4.500000, 4.500000, 4.599020, 4.885165, 5.330952, 5.500000, 5.500000, 5.500000, 5.500000, 5.156854, 4.500000, 3.742641, 3.105551, 2.328427, 1.500000, 0.500000, 0.500000, 1.500000, 2.500000, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.742641, 4.500000, 5.330952, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 5.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 3.742641, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.500000, 2.328427, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 3.623106, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 4.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.105551, 2.328427, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.662278, 1.736068, 0.914214, 0.500000, 0.500000, 1.500000, 2.328427, 3.105551, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 3.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 1.736068, 0.914214, 0.500000, 0.500000, 0.914214, 1.736068, 2.328427, 2.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.736068, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 2.500000, 1.500000 [...]
+    0.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 0.500000, 0.500000, 0.914214, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 0.500000, 0.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000, 1.500000 [...]
+    0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000, 0.500000 [...]
+};
+
+static unsigned int eccTrafo_data[10000] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 4, 4, 5, 4, 4, 6, 6, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8,
+    8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 4, 4, 4, 4, 4, 6, 6, 6, 6, 4, 4, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 6, 6, 4, 4, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, 10, 10, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, 10, 10, 10, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 8, 8, 8, 8, 8,
+    8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, 10, 10, 10, 11, 11,
+    11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 13, 13, 13,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, 10, 10, 10, 11, 11,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 13, 13, 13,
+    9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 1, 14, 1, 1, 1, 1, 10, 10, 10, 10, 10, 11, 11,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 12, 12, 13,
+    13, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 1, 1, 1, 14, 14, 1, 1, 1, 1, 10, 10, 10, 10, 10, 11, 11,
+    11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 12, 12, 12,
+    13, 13, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 1, 15, 15, 15, 14, 1, 1, 1, 1, 10, 10, 10, 10, 10, 11, 11, 11,
+    11, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 12, 12,
+    16, 16, 13, 16, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    1, 1, 1, 15, 15, 15, 15, 15, 15, 15, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 2, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    17, 17, 1, 15, 15, 15, 15, 15, 15, 15, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 2, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    18, 18, 18, 15, 15, 15, 15, 15, 15, 15, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 2, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    18, 18, 18, 18, 18, 15, 15, 15, 15, 15, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    18, 18, 18, 18, 18, 18, 15, 15, 15, 15, 15, 10, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    18, 18, 18, 18, 18, 18, 19, 15, 15, 15, 15, 19, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 9, 9, 9, 9, 9, 9, 9, 9,
+    18, 18, 18, 18, 18, 19, 19, 15, 15, 15, 19, 19, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 9, 9, 9, 20, 9, 9, 9,
+    18, 18, 18, 18, 18, 19, 21, 19, 19, 19, 19, 19, 19, 19, 11, 11, 11, 11, 11, 11,
+    2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 9,
+    18, 18, 21, 21, 21, 21, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 2, 2,
+    2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 2, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20,
+    18, 21, 21, 21, 21, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2,
+    2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20,
+    21, 21, 21, 21, 21, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 11, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    21, 21, 21, 21, 21, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 19, 19, 19, 19, 19, 19, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 19, 19, 19, 19, 19, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 19, 19, 19, 19, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 23,
+    24, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 19, 19, 19, 19,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 23, 23, 23, 24,
+    24, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 19, 19, 19,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 23, 23, 24, 24,
+    24, 24, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 19, 19,
+    19, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 23, 23, 23, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 25, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    19, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 23, 23, 23, 3, 3, 3,
+    3, 27, 27, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 25, 25, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    28, 28, 19, 28, 29, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26, 3, 3, 3, 3,
+    3, 27, 27, 27, 27, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 25, 25, 25, 25, 25, 25, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 30,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 26, 26, 26, 26, 26, 3, 3, 3,
+    3, 27, 27, 27, 27, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 25, 25, 25, 25, 25, 25, 25, 25, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 31, 30, 30, 30, 30, 30,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 2, 26, 26, 26, 26, 26, 26, 32, 32, 3,
+    32, 27, 27, 27, 27, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 33, 33, 33,
+    33, 33, 33, 33, 33, 33, 33, 3, 3, 25, 25, 25, 25, 25, 25, 25, 25, 25, 34, 34,
+    16, 16, 16, 16, 16, 16, 16, 16, 35, 35, 31, 36, 31, 31, 31, 30, 30, 30, 30, 30,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 26, 26, 26, 32, 32, 32,
+    32, 32, 32, 32, 27, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 33, 33, 33, 33, 33,
+    33, 33, 33, 33, 33, 33, 33, 33, 33, 25, 25, 25, 25, 34, 34, 34, 34, 34, 34, 34,
+    34, 35, 35, 35, 35, 35, 35, 35, 35, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 37,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 26, 32, 32, 32, 32,
+    32, 32, 32, 32, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 33, 33, 33, 33, 33,
+    33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 38, 25, 34, 34, 34, 34, 34, 34, 34, 34,
+    35, 35, 35, 35, 35, 35, 35, 35, 35, 31, 31, 31, 31, 31, 31, 30, 37, 37, 37, 37,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 26, 26, 32, 32, 32,
+    32, 32, 32, 32, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 33, 33, 33, 33, 33,
+    33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 35,
+    35, 35, 35, 35, 35, 35, 35, 35, 31, 31, 31, 31, 31, 30, 30, 37, 37, 37, 37, 37,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 26, 39, 32, 32, 32,
+    32, 32, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 33, 33, 33, 33, 33,
+    33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 33, 34, 33, 33, 33,
+    33, 33, 35, 35, 35, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 37, 37, 37, 37, 37,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 39, 39, 39, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 40, 40, 41, 33, 33, 33, 33,
+    33, 33, 42, 42, 42, 42, 42, 42, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+    33, 33, 33, 31, 31, 31, 31, 31, 31, 31, 31, 30, 30, 30, 37, 37, 37, 37, 37, 37,
+    43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 39, 39, 39, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 40, 40, 40, 41, 41, 41, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+    33, 31, 31, 31, 31, 31, 31, 31, 31, 31, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 39, 39, 39, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 44, 33, 33, 33, 33, 33, 33, 33, 33,
+    31, 31, 31, 31, 31, 31, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 43, 43, 43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 39, 39, 39, 39, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 44, 33, 33, 33, 33, 33, 33, 33,
+    31, 31, 31, 31, 31, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 43, 43, 43, 43, 45, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 46, 46, 39, 39, 39, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 33, 33, 33, 33, 33, 33, 33,
+    33, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 41, 41, 41, 41, 47, 41, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 33, 33, 33, 33, 33, 33, 33,
+    33, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 22, 22, 22, 22, 22, 22, 28, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 41, 41, 41, 41, 41, 41, 41, 41, 3,
+    3, 3, 3, 3, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 33, 33, 33, 33, 33,
+    33, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 48, 48, 48, 48, 48, 43, 43, 43, 43, 22, 22, 22, 22, 22, 28, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+    41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 49, 41, 41, 41, 42, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 50, 50, 50, 50, 50,
+    37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 48, 43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 22, 22, 22, 48, 48, 28, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+    41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 49, 49, 49, 49, 51, 51, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 50, 50, 50, 50, 50, 50,
+    52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 22, 48, 48, 28, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+    41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 49, 49, 49, 49, 49, 49, 51, 51, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 50, 50, 50, 50, 50, 50, 52,
+    52, 52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 41, 53, 53, 53, 53, 53, 53, 41, 41, 41, 41, 41, 41,
+    41, 41, 41, 54, 41, 41, 41, 41, 41, 41, 49, 49, 49, 49, 49, 49, 51, 51, 51, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 50, 50, 50, 50, 50, 50, 52,
+    52, 52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 28, 28,
+    28, 28, 28, 28, 28, 28, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 41, 41, 41, 41,
+    41, 54, 41, 54, 54, 54, 41, 41, 53, 53, 49, 49, 49, 49, 49, 49, 51, 51, 51, 51,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 50, 50, 50, 50, 50, 52,
+    52, 52, 52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 28,
+    28, 28, 28, 28, 28, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 41, 41, 41,
+    54, 54, 54, 54, 54, 54, 54, 53, 53, 53, 53, 49, 49, 49, 49, 51, 51, 51, 51, 51,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 50, 50, 50, 52,
+    52, 52, 52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+    48, 48, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 54, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 51, 51, 51, 55, 55,
+    55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 52,
+    52, 52, 52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 55, 55,
+    55, 55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+    52, 52, 52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    55, 55, 55, 55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+    52, 52, 52, 52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 55, 55, 55, 55, 55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+    42, 42, 52, 52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 43, 43, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 55, 55, 55, 55, 55, 55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+    42, 42, 42, 52, 52, 52, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    43, 43, 43, 56, 43, 43, 48, 48, 48, 48, 48, 48, 48, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57,
+    57, 57, 57, 55, 55, 55, 55, 55, 55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    58, 58, 56, 56, 43, 43, 43, 48, 48, 48, 48, 48, 43, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 55, 55, 55, 55, 55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    58, 58, 43, 56, 43, 43, 43, 48, 48, 48, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 55, 55, 55, 55, 55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    58, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 59, 42, 42, 42, 42, 42, 42, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 37, 37, 37, 37, 37, 60, 60,
+    58, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 59, 42, 42, 42, 42, 42, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 61, 61, 61, 60, 60, 60,
+    58, 58, 43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 59, 42, 42, 42, 42, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 62, 62, 42, 61, 61, 61, 61, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 59, 59, 42, 42, 42, 42, 42,
+    42, 42, 42, 42, 42, 42, 42, 42, 62, 62, 62, 62, 62, 61, 61, 61, 61, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 59, 59, 42, 42, 63, 42, 42,
+    42, 42, 64, 64, 42, 42, 42, 42, 62, 62, 62, 62, 62, 61, 61, 61, 61, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 65,
+    53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 59, 59, 59, 42, 42, 42, 42,
+    42, 42, 64, 64, 64, 42, 42, 42, 42, 62, 62, 62, 62, 62, 61, 61, 61, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    66, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 59, 59, 67, 67, 67, 42,
+    42, 64, 64, 64, 64, 42, 42, 42, 62, 62, 62, 62, 62, 62, 62, 61, 60, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    66, 66, 66, 66, 66, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 67, 67, 67, 67,
+    42, 64, 64, 64, 64, 64, 42, 42, 62, 62, 62, 62, 62, 62, 62, 62, 60, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 67, 67, 67, 67,
+    67, 64, 64, 64, 64, 64, 64, 68, 42, 62, 62, 62, 62, 62, 62, 62, 60, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 67, 67, 67, 67,
+    67, 67, 64, 64, 64, 64, 64, 68, 68, 68, 62, 62, 62, 62, 62, 62, 60, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 57, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 67, 67, 67,
+    67, 67, 64, 64, 64, 64, 64, 68, 68, 68, 68, 62, 62, 62, 62, 62, 60, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 57, 57, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 69, 69, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 67, 67, 67,
+    67, 67, 64, 64, 64, 64, 64, 68, 68, 68, 68, 68, 62, 62, 62, 62, 60, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 57, 57, 57, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 69, 69, 69, 69, 69, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 67, 67, 67,
+    67, 67, 64, 64, 64, 64, 68, 68, 68, 68, 68, 68, 68, 62, 62, 62, 60, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57,
+    57, 57, 57, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 69, 69, 69, 69, 69, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+    67, 67, 64, 64, 64, 68, 68, 68, 68, 68, 68, 68, 68, 68, 60, 60, 60, 60, 60, 60,
+    43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57,
+    57, 57, 57, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 69, 69, 69, 69, 69, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+    67, 67, 64, 64, 64, 68, 68, 68, 68, 68, 68, 68, 68, 68, 60, 60, 60, 60, 60, 60,
+    70, 70, 43, 43, 43, 43, 43, 53, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57,
+    57, 57, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 69, 69, 69, 69, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 67, 67, 67,
+    71, 71, 64, 64, 64, 68, 68, 68, 68, 68, 68, 68, 68, 68, 60, 60, 60, 60, 60, 60,
+    70, 70, 43, 43, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 72, 72, 72, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57,
+    57, 57, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 69, 69, 69, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 67, 67, 67,
+    71, 71, 71, 64, 64, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 60, 60, 60, 60, 60,
+    53, 53, 53, 43, 43, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 72, 72, 72, 72, 72, 72, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57,
+    57, 57, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 67, 67, 67,
+    71, 71, 71, 64, 64, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 60, 60, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    72, 72, 72, 72, 72, 72, 72, 72, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57,
+    57, 57, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 67, 71, 71,
+    71, 71, 71, 64, 64, 68, 68, 68, 68, 68, 68, 68, 68, 68, 73, 60, 60, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    72, 72, 72, 72, 72, 72, 72, 72, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 57,
+    57, 57, 53, 53, 53, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 67, 67, 67, 67, 67, 71, 71, 71,
+    71, 71, 71, 71, 64, 68, 68, 68, 68, 68, 68, 68, 68, 60, 60, 60, 60, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    72, 72, 72, 72, 72, 72, 72, 72, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    57, 57, 57, 53, 53, 53, 53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 74, 67, 67, 67, 67, 71, 71, 71,
+    71, 71, 71, 71, 71, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 60, 60, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    75, 72, 72, 72, 72, 72, 72, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 74, 74, 74, 74, 71, 71, 71, 71, 71,
+    71, 71, 71, 71, 71, 68, 68, 68, 68, 68, 68, 68, 71, 68, 68, 60, 60, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 72, 72, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 74, 74, 74, 74, 74, 74, 71, 71, 71,
+    71, 71, 71, 71, 71, 71, 68, 68, 68, 68, 68, 68, 71, 71, 71, 60, 60, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 76, 76, 76, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 74, 74, 74, 74, 74, 74, 74, 71, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 68, 71, 71, 71, 71, 71, 60, 60, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 53, 53, 53,
+    53, 53, 53, 57, 57, 57, 57, 57, 77, 78, 78, 78, 79, 57, 57, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 57, 57, 57, 57, 74, 74, 74, 74, 74, 74, 74, 74, 74, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 80, 80,
+    53, 53, 53, 53, 53, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 53, 53,
+    53, 53, 53, 53, 81, 81, 81, 81, 77, 77, 78, 79, 79, 79, 79, 57, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 82, 57, 57, 74, 74, 74, 74, 74, 74, 74, 74, 74, 71, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 53, 53,
+    53, 53, 53, 53, 81, 81, 81, 81, 77, 77, 79, 79, 79, 79, 79, 79, 57, 57, 57, 57,
+    57, 57, 57, 57, 57, 82, 82, 83, 74, 74, 74, 74, 74, 74, 74, 74, 74, 71, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 84, 53, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 53, 53,
+    81, 81, 81, 81, 81, 81, 81, 81, 79, 79, 79, 79, 79, 79, 79, 79, 79, 57, 85, 85,
+    85, 85, 57, 57, 57, 82, 82, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 71, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 84, 84, 84, 84, 84, 84, 84, 76, 53, 53, 76, 76, 76, 76, 86, 86, 86, 86, 81,
+    81, 81, 81, 81, 81, 81, 81, 81, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 85, 85,
+    85, 85, 85, 57, 57, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 71, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 84, 84, 84, 84, 84, 84, 84, 53, 53, 53, 53, 53, 86, 86, 86, 86, 86, 81,
+    81, 81, 81, 81, 81, 81, 81, 81, 87, 79, 79, 79, 79, 79, 79, 88, 88, 88, 89, 85,
+    85, 85, 85, 85, 85, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 84, 84, 84, 84, 84, 53, 53, 53, 53, 53, 53, 53, 86, 86, 86, 81, 81,
+    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 79, 79, 79, 88, 88, 88, 88, 88, 89, 89,
+    89, 85, 85, 85, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 84, 84, 84, 84, 53, 53, 53, 53, 53, 53, 53, 53, 53, 86, 81, 81,
+    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 88, 79, 88, 88, 88, 88, 88, 88, 89, 89,
+    89, 89, 85, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 81, 81,
+    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 88, 88, 88, 88, 88, 88, 88, 88, 89, 89,
+    89, 89, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 81, 81,
+    81, 81, 81, 81, 81, 81, 81, 81, 81, 88, 88, 88, 88, 88, 88, 88, 88, 88, 89, 89,
+    89, 89, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 90, 53, 53, 53, 53, 53, 53, 53, 81, 81,
+    81, 81, 81, 81, 81, 81, 81, 81, 81, 88, 88, 88, 88, 88, 88, 88, 88, 88, 89, 89,
+    89, 89, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 90, 90, 53, 53, 53, 81, 81, 81, 81, 81, 81,
+    81, 81, 81, 81, 81, 81, 81, 81, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 91, 91,
+    89, 89, 89, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 90, 53, 53, 81, 81, 81, 81, 81, 81, 81,
+    81, 81, 81, 81, 81, 81, 81, 81, 88, 88, 88, 88, 88, 88, 88, 88, 88, 91, 91, 91,
+    89, 89, 89, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 92,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 81, 81, 81, 81, 81, 81, 81, 81,
+    81, 93, 81, 81, 81, 81, 81, 94, 94, 94, 88, 88, 88, 88, 88, 88, 91, 91, 91, 91,
+    95, 95, 95, 95, 95, 95, 95, 95, 95, 83, 83, 83, 83, 83, 83, 83, 83, 83, 71, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 60, 60,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 81, 81, 81, 81, 81, 81, 81, 81,
+    93, 93, 81, 81, 81, 81, 81, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95,
+    95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, 96, 96, 71,
+    71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 97, 97,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 81, 81, 81, 81, 81, 81, 81, 81,
+    93, 93, 81, 81, 81, 81, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95,
+    95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, 96, 96, 96, 96,
+    96, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 97, 97
+};
+
+static float eccTrafo_ref[10000] = {
+    10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f,
+    26.213198f, 25.798985f, 25.384771f, 24.970558f, 24.556345f, 24.142132f, 23.727919f, 23.313705f, 22.899492f, 22.485279f, 22.071066f, 21.656853f, 21.242640f, 20.828426f, 20.414213f, 20.000000f, 20.414213f, 20.828426f, 21.242640f, 21.656853f,
+    22.071066f, 22.485279f, 22.899492f, 23.313705f, 23.727919f, 25.313705f, 24.899492f, 24.485279f, 24.071066f, 23.656853f, 23.242640f, 22.828426f, 22.414213f, 22.000000f, 22.414213f, 22.828426f, 23.242640f, 23.656853f, 24.071066f, 24.485279f,
+    24.899492f, 25.313705f, 5.828427f, 4.828427f, 0.000000f, 2.828427f, 2.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 1.414214f, 1.000000f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f,
+    3.414214f, 3.828427f, 4.242640f, 13.727921f, 13.313707f, 12.899493f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f, 11.242640f, 11.656854f, 12.071067f, 12.485280f, 12.899493f,
+    9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656854f,
+    25.213200f, 24.798985f, 24.384771f, 23.970558f, 23.556345f, 23.142132f, 22.727919f, 22.313705f, 21.899492f, 21.485279f, 21.071066f, 20.656853f, 20.242640f, 19.828426f, 19.414213f, 19.000000f, 19.414213f, 19.828426f, 20.242640f, 20.656853f,
+    21.071066f, 21.485279f, 21.899492f, 22.313705f, 24.727919f, 24.313705f, 23.899492f, 23.485279f, 23.071066f, 22.656853f, 22.242640f, 21.828426f, 21.414213f, 21.000000f, 21.414213f, 21.828426f, 22.242640f, 22.656853f, 23.071066f, 23.485279f,
+    23.899492f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 1.000000f, 0.000000f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f,
+    2.414214f, 2.828427f, 3.828427f, 4.828427f, 12.313707f, 11.899494f, 11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 11.071067f, 11.485280f, 11.899494f,
+    9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 26.798985f, 25.798985f,
+    24.798985f, 23.798986f, 23.384771f, 22.970558f, 22.556345f, 22.142132f, 21.727919f, 21.313705f, 20.899492f, 20.485279f, 20.071066f, 19.656853f, 19.242640f, 18.828426f, 18.414213f, 18.000000f, 18.414213f, 18.828426f, 19.242640f, 19.656853f,
+    20.071066f, 20.485279f, 20.899492f, 24.142132f, 23.727919f, 23.313705f, 22.899492f, 22.485279f, 22.071066f, 21.656853f, 21.242640f, 20.828426f, 20.414213f, 20.000000f, 20.414213f, 20.828426f, 21.242640f, 21.656853f, 22.071066f, 22.485279f,
+    22.899492f, 23.313705f, 23.727919f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 7.242641f, 7.656855f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f,
+    1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 10.899494f, 10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f, 10.899494f,
+    8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 26.384771f, 25.384771f,
+    24.384771f, 23.384771f, 22.384773f, 21.970558f, 21.556345f, 21.142132f, 20.727919f, 20.313705f, 19.899492f, 19.485279f, 19.071066f, 18.656853f, 18.242640f, 17.828426f, 17.414213f, 17.000000f, 17.414213f, 17.828426f, 18.242640f, 18.656853f,
+    19.071066f, 19.485279f, 19.899492f, 23.142132f, 22.727919f, 22.313705f, 21.899492f, 21.485279f, 21.071066f, 20.656853f, 20.242640f, 19.828426f, 19.414213f, 19.000000f, 19.414213f, 19.828426f, 20.242640f, 20.656853f, 21.071066f, 21.485279f,
+    21.899492f, 22.313705f, 22.727919f, 23.142132f, 23.556345f, 23.970558f, 24.384771f, 24.798985f, 1.414214f, 2.414214f, 2.000000f, 2.414214f, 6.242641f, 7.242641f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f,
+    1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 9.899494f, 9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f,
+    8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f, 25.970558f, 24.970558f,
+    23.970558f, 22.970558f, 21.970558f, 20.970560f, 20.556345f, 20.142132f, 19.727919f, 19.313705f, 18.899492f, 18.485279f, 18.071066f, 17.656853f, 17.242640f, 16.828426f, 16.414213f, 16.000000f, 16.414213f, 16.828426f, 17.242640f, 17.656853f,
+    18.071066f, 18.485279f, 22.556345f, 22.142132f, 21.727919f, 21.313705f, 20.899492f, 20.485279f, 20.071066f, 19.656853f, 19.242640f, 18.828426f, 18.414213f, 18.000000f, 18.414213f, 18.828426f, 19.242640f, 19.656853f, 20.071066f, 20.485279f,
+    20.899492f, 21.313705f, 21.727919f, 22.142132f, 22.556345f, 22.970558f, 23.384771f, 23.798986f, 24.213200f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f,
+    1.414214f, 2.414214f, 3.414214f, 4.414214f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f,
+    8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 8.000000f, 9.000000f, 25.556345f, 24.556345f,
+    23.556345f, 22.556345f, 21.556345f, 20.556345f, 19.556347f, 19.142132f, 18.727919f, 18.313705f, 17.899492f, 17.485279f, 17.071066f, 16.656853f, 16.242640f, 15.828426f, 15.414213f, 15.000000f, 15.414213f, 15.828426f, 16.242640f, 16.656853f,
+    17.071066f, 17.485279f, 21.556345f, 21.142132f, 20.727919f, 20.313705f, 19.899492f, 19.485279f, 19.071066f, 18.656853f, 18.242640f, 17.828426f, 17.414213f, 17.000000f, 17.414213f, 17.828426f, 18.242640f, 18.656853f, 19.071066f, 19.485279f,
+    19.899492f, 20.313705f, 20.727919f, 21.142132f, 21.556345f, 21.970558f, 22.384773f, 22.798986f, 23.213200f, 23.627413f, 24.041626f, 25.041626f, 6.242641f, 7.242641f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f,
+    2.414214f, 2.828427f, 3.828427f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f,
+    8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 5.414214f, 5.828427f, 6.242640f, 25.142132f, 24.142132f,
+    23.142132f, 22.142132f, 21.142132f, 20.142132f, 19.142132f, 18.142134f, 17.727919f, 17.313705f, 16.899492f, 16.485279f, 16.071066f, 15.656853f, 15.242640f, 14.828426f, 14.414213f, 14.000000f, 14.414213f, 14.828426f, 15.242640f, 15.656853f,
+    16.071066f, 16.485279f, 20.556345f, 20.142132f, 19.727919f, 19.313705f, 18.899492f, 18.485279f, 18.071066f, 17.656853f, 17.242640f, 16.828426f, 16.414213f, 16.000000f, 16.414213f, 16.828426f, 17.242640f, 17.656853f, 18.071066f, 18.485279f,
+    18.899492f, 19.313705f, 19.727919f, 20.142132f, 20.556345f, 20.970560f, 21.384773f, 21.798986f, 22.213200f, 22.627413f, 23.627413f, 24.627413f, 25.627413f, 26.627413f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f,
+    3.414214f, 3.828427f, 4.242640f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f,
+    8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 24.727919f, 23.727919f,
+    22.727919f, 21.727919f, 20.727919f, 19.727919f, 18.727919f, 17.727919f, 16.727921f, 16.313705f, 15.899493f, 15.485279f, 15.071066f, 14.656853f, 14.242640f, 13.828426f, 13.414213f, 13.000000f, 13.414213f, 13.828426f, 14.242640f, 14.656853f,
+    15.071066f, 15.485279f, 19.556347f, 19.142132f, 18.727919f, 18.313705f, 17.899492f, 17.485279f, 17.071066f, 16.656853f, 16.242640f, 15.828426f, 15.414213f, 15.000000f, 15.414213f, 15.828426f, 16.242640f, 16.656853f, 17.071066f, 17.485279f,
+    17.899492f, 18.313705f, 18.727919f, 19.142132f, 19.556347f, 19.970560f, 20.384773f, 20.798986f, 21.213200f, 22.213200f, 23.213200f, 24.213200f, 25.213200f, 26.213198f, 27.213198f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f,
+    4.414214f, 4.828427f, 11.242640f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f,
+    9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 10.071068f, 9.656855f,
+    10.071068f, 21.313705f, 20.313705f, 19.313705f, 18.313705f, 17.313705f, 16.313705f, 15.313706f, 14.899493f, 14.485280f, 14.071066f, 13.656853f, 13.242640f, 12.828426f, 12.414213f, 12.000000f, 12.414213f, 12.828426f, 13.242640f, 13.656853f,
+    14.071066f, 18.970560f, 18.556347f, 18.142134f, 17.727919f, 17.313705f, 16.899492f, 16.485279f, 16.071066f, 15.656853f, 15.242640f, 14.828426f, 14.414213f, 14.000000f, 14.414213f, 14.828426f, 15.242640f, 15.656853f, 16.071066f, 16.485279f,
+    16.899492f, 17.313705f, 17.727919f, 18.142134f, 18.556347f, 18.970560f, 19.384773f, 19.798986f, 20.798986f, 21.798986f, 22.798986f, 23.798986f, 24.798985f, 25.798985f, 26.798985f, 27.798985f, 2.414214f, 3.828427f, 2.828427f, 2.414214f,
+    12.828426f, 11.828426f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f,
+    9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 9.071068f, 8.656855f,
+    21.899492f, 20.899492f, 19.899492f, 18.899492f, 17.899492f, 16.899494f, 15.899493f, 14.899493f, 13.899493f, 13.485280f, 13.071067f, 12.656853f, 12.242640f, 11.828426f, 11.414213f, 11.000000f, 11.414213f, 11.828426f, 12.242640f, 12.656853f,
+    18.384773f, 17.970560f, 17.556347f, 17.142134f, 16.727921f, 16.313705f, 15.899493f, 15.485279f, 15.071066f, 14.656853f, 14.242640f, 13.828426f, 13.414213f, 13.000000f, 13.414213f, 13.828426f, 14.242640f, 14.656853f, 15.071066f, 15.485279f,
+    15.899493f, 16.313705f, 16.727921f, 17.142134f, 17.556347f, 17.970560f, 18.384773f, 19.384773f, 20.384773f, 21.384773f, 22.384773f, 23.384771f, 24.384771f, 25.384771f, 26.384771f, 27.384771f, 1.414214f, 3.414214f, 2.414214f, 1.414214f,
+    12.414213f, 11.414213f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f,
+    10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 1.414214f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 8.071068f, 7.656854f,
+    21.485279f, 20.485279f, 19.485279f, 18.485279f, 17.485279f, 16.485279f, 15.485280f, 14.485280f, 13.485280f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f, 11.242640f, 11.656854f,
+    17.970560f, 16.970560f, 16.556347f, 16.142134f, 15.727920f, 15.313706f, 14.899493f, 14.485280f, 14.071066f, 13.656853f, 13.242640f, 12.828426f, 12.414213f, 12.000000f, 12.414213f, 12.828426f, 13.242640f, 13.656853f, 14.071066f, 14.485280f,
+    14.899493f, 15.313706f, 15.727920f, 16.142134f, 16.556347f, 16.970560f, 17.970560f, 18.970560f, 19.970560f, 20.970560f, 21.970558f, 22.970558f, 23.970558f, 24.970558f, 25.970558f, 26.970558f, 1.000000f, 0.000000f, 1.000000f, 1.000000f,
+    0.000000f, 11.000000f, 10.000000f, 9.000000f, 8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f,
+    10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 0.000000f, 1.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 7.071068f, 6.656854f,
+    6.242640f, 20.071066f, 19.071066f, 18.071066f, 17.071068f, 16.071068f, 15.071067f, 14.071067f, 13.071067f, 12.071067f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f,
+    17.556347f, 16.556347f, 15.556347f, 15.142134f, 14.727921f, 14.313706f, 13.899493f, 13.485280f, 13.071067f, 12.656853f, 12.242640f, 11.828426f, 11.414213f, 11.000000f, 11.414213f, 11.828426f, 12.242640f, 12.656853f, 13.071067f, 13.485280f,
+    13.899493f, 14.313706f, 14.727921f, 15.142134f, 15.556347f, 16.556347f, 17.556347f, 18.556347f, 19.556347f, 20.556345f, 21.556345f, 22.556345f, 23.556345f, 24.556345f, 25.556345f, 26.556345f, 1.414214f, 1.000000f, 1.414214f, 2.414214f,
+    1.000000f, 1.414214f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f,
+    10.899494f, 9.899494f, 9.485281f, 9.071068f, 4.242640f, 3.828427f, 3.414214f, 1.000000f, 7.828427f, 7.414214f, 7.828427f, 8.242640f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 7.656854f, 6.656854f, 5.656854f,
+    5.242640f, 4.828427f, 18.656853f, 17.656853f, 16.656853f, 15.656854f, 14.656854f, 13.656854f, 12.656854f, 11.656854f, 10.656854f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 18.142134f,
+    17.142134f, 16.142134f, 15.142134f, 14.142134f, 13.727921f, 13.313707f, 12.899493f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f, 11.242640f, 11.656854f, 12.071067f, 12.485280f,
+    12.899493f, 13.313707f, 13.727921f, 14.142134f, 15.142134f, 16.142134f, 17.142134f, 18.142134f, 19.142132f, 20.142132f, 21.142132f, 22.142132f, 23.142132f, 24.142132f, 25.142132f, 26.142132f, 27.142132f, 2.000000f, 2.414214f, 2.828427f,
+    14.485280f, 14.071066f, 2.828427f, 13.242640f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f,
+    11.313707f, 10.899494f, 10.485281f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f,
+    4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 17.727919f,
+    16.727921f, 15.727920f, 14.727921f, 13.727921f, 12.727921f, 12.313707f, 11.899494f, 11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 11.071067f, 11.485280f,
+    11.899494f, 12.313707f, 12.727921f, 13.727921f, 14.727921f, 15.727920f, 16.727921f, 17.727919f, 18.727919f, 19.727919f, 20.727919f, 21.727919f, 22.727919f, 23.727919f, 24.727919f, 25.727919f, 26.727919f, 14.727921f, 14.313706f, 13.899493f,
+    13.485280f, 13.071067f, 12.656853f, 12.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f,
+    1.000000f, 0.000000f, 11.485281f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f,
+    3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242641f, 17.313705f,
+    16.313705f, 15.313706f, 14.313706f, 13.313707f, 12.313707f, 11.313707f, 10.899494f, 10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f,
+    10.899494f, 11.313707f, 12.313707f, 13.313707f, 14.313706f, 15.313706f, 16.313705f, 17.313705f, 18.313705f, 19.313705f, 20.313705f, 21.313705f, 22.313705f, 23.313705f, 24.313705f, 25.313705f, 14.142134f, 13.727921f, 13.313707f, 12.899493f,
+    12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f,
+    4.414214f, 4.000000f, 4.414214f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 5.656854f, 5.242640f, 11.414213f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f,
+    3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242641f, 16.899492f,
+    15.899493f, 14.899493f, 13.899493f, 12.899493f, 11.899494f, 10.899494f, 9.899494f, 9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f,
+    9.899494f, 10.899494f, 11.899494f, 12.899493f, 13.899493f, 14.899493f, 15.899493f, 16.899492f, 17.899492f, 18.899492f, 19.899492f, 20.899492f, 21.899492f, 22.899492f, 23.899492f, 24.899492f, 13.727921f, 12.727921f, 12.313707f, 11.899494f,
+    11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f,
+    3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 6.656854f, 6.242640f, 6.656854f, 10.000000f, 9.000000f, 8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f,
+    3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 8.000000f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 17.485279f, 16.485279f,
+    15.485279f, 14.485280f, 13.485280f, 12.485280f, 11.485280f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f,
+    9.485281f, 10.485281f, 11.485280f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 16.485279f, 17.485279f, 18.485279f, 19.485279f, 20.485279f, 21.485279f, 22.485279f, 23.485279f, 24.485279f, 25.485279f, 12.313707f, 11.313707f, 10.899494f,
+    10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f,
+    2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 7.242640f, 11.414213f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f,
+    3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 17.071066f, 16.071066f,
+    15.071066f, 14.071066f, 13.071067f, 12.071067f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f,
+    9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f, 17.071066f, 18.071066f, 19.071066f, 20.071066f, 21.071066f, 22.071066f, 23.071066f, 24.071066f, 25.071066f, 11.899494f, 10.899494f, 9.899494f,
+    9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f,
+    1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 11.485281f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 8.242640f, 11.828426f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f,
+    3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 16.656853f, 15.656853f,
+    14.656853f, 13.656853f, 12.656853f, 11.656854f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f,
+    8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 15.656853f, 16.656853f, 17.656853f, 18.656853f, 19.656853f, 20.656853f, 21.656853f, 22.656853f, 23.656853f, 24.656853f, 11.485280f, 10.485281f, 9.485281f,
+    8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f, 10.899494f,
+    1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 11.485281f, 10.485281f, 4.000000f, 4.414214f, 4.828427f, 7.656854f, 7.242640f, 12.242640f, 11.242640f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f,
+    4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 16.242640f, 15.242640f,
+    14.242640f, 13.242640f, 12.242640f, 11.242640f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f,
+    8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 15.242640f, 16.242640f, 17.242640f, 18.242640f, 19.242640f, 20.242640f, 21.242640f, 22.242640f, 23.242640f, 24.242640f, 25.242640f, 10.071067f, 9.071068f,
+    8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.414213f, 9.828426f, 10.242640f, 2.828427f, 11.071067f, 11.485280f, 11.899494f,
+    1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 11.071067f, 3.828427f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f,
+    18.313707f, 17.899492f, 17.485279f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 15.828426f, 14.828426f,
+    13.828426f, 12.828426f, 11.828426f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f,
+    7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f, 14.828426f, 15.828426f, 16.828426f, 17.828426f, 18.828426f, 19.828426f, 20.828426f, 21.828426f, 22.828426f, 23.828426f, 24.828426f, 9.656854f, 8.656854f,
+    7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f, 2.414214f, 1.414214f, 1.000000f, 12.899493f,
+    2.414214f, 2.000000f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 8.071068f, 19.899492f, 18.899492f,
+    17.899492f, 16.899494f, 16.485279f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 14.414213f,
+    13.414213f, 12.414213f, 11.414213f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f,
+    7.414214f, 8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f, 14.414213f, 15.414213f, 16.414213f, 17.414213f, 18.414213f, 19.414213f, 20.414213f, 21.414213f, 22.414213f, 23.414213f, 24.414213f, 9.242640f, 8.242640f,
+    7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 0.000000f, 1.000000f,
+    3.414214f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 20.485279f, 19.485279f, 18.485279f,
+    17.485279f, 16.485279f, 15.485280f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f,
+    13.000000f, 12.000000f, 11.000000f, 10.000000f, 9.000000f, 8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f,
+    7.000000f, 8.000000f, 9.000000f, 10.000000f, 11.000000f, 12.000000f, 13.000000f, 14.000000f, 15.000000f, 16.000000f, 17.000000f, 18.000000f, 19.000000f, 20.000000f, 21.000000f, 22.000000f, 23.000000f, 24.000000f, 8.828427f, 7.828427f,
+    6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 1.414214f,
+    3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 21.071066f, 20.071066f, 19.071066f, 18.071066f,
+    17.071068f, 16.071068f, 15.071067f, 14.071067f, 13.071067f, 7.828427f, 11.071067f, 10.071067f, 9.071068f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f,
+    6.242640f, 12.414213f, 11.414213f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f,
+    7.414214f, 8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f, 14.414213f, 15.414213f, 16.414213f, 17.414213f, 18.414213f, 19.414213f, 20.414213f, 21.414213f, 22.414213f, 23.414213f, 24.414213f, 8.414213f, 7.414214f,
+    6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f,
+    3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 21.656853f, 20.656853f, 19.656853f, 18.656853f, 17.656853f,
+    16.656853f, 15.656854f, 14.656854f, 13.656854f, 12.656854f, 11.656854f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f,
+    6.656854f, 12.828426f, 11.828426f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f,
+    7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f, 14.828426f, 15.828426f, 16.828426f, 17.828426f, 18.828426f, 19.828426f, 20.828426f, 21.828426f, 22.828426f, 23.828426f, 9.000000f, 8.000000f, 7.000000f,
+    6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 8.000000f, 9.000000f, 10.000000f, 11.000000f, 12.000000f, 13.000000f,
+    4.242640f, 3.828427f, 3.414214f, 12.899493f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 20.071066f, 19.071066f, 18.071066f,
+    17.071068f, 16.071068f, 15.071067f, 14.071067f, 13.071067f, 12.071067f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f,
+    7.071068f, 13.242640f, 12.242640f, 11.242640f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f,
+    8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 15.242640f, 16.242640f, 17.242640f, 18.242640f, 19.242640f, 20.242640f, 21.242640f, 22.242640f, 23.242640f, 24.242640f, 9.414213f, 8.414213f, 7.414214f,
+    6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f,
+    13.727921f, 12.727921f, 12.313707f, 11.899494f, 11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 19.485279f, 18.485279f,
+    17.485279f, 16.485279f, 15.485280f, 14.485280f, 13.485280f, 12.485280f, 11.485280f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f,
+    14.656853f, 13.656853f, 12.656853f, 11.656854f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f,
+    8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 15.656853f, 16.656853f, 17.656853f, 18.656853f, 19.656853f, 20.656853f, 21.656853f, 22.656853f, 23.656853f, 24.656853f, 9.828426f, 8.828427f, 7.828427f,
+    6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f,
+    13.313707f, 12.313707f, 11.313707f, 10.899494f, 10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 19.899492f, 18.899492f,
+    17.899492f, 16.899494f, 15.899493f, 14.899493f, 13.899493f, 12.899493f, 11.899494f, 10.899494f, 9.899494f, 9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 2.828427f, 3.828427f,
+    2.414214f, 14.071066f, 13.071067f, 12.071067f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f,
+    9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f, 17.071066f, 18.071066f, 19.071066f, 20.071066f, 21.071066f, 22.071066f, 23.071066f, 24.071066f, 25.071066f, 10.242640f, 9.242640f, 8.242640f,
+    7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f,
+    12.899493f, 11.899494f, 10.899494f, 9.899494f, 9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 3.828427f, 4.242640f, 5.242640f, 6.242640f,
+    18.313705f, 17.313705f, 16.313705f, 15.313706f, 14.313706f, 13.313707f, 12.313707f, 11.313707f, 10.899494f, 10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 1.000000f,
+    1.414214f, 14.485280f, 13.485280f, 12.485280f, 11.485280f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f,
+    9.485281f, 10.485281f, 11.485280f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 16.485279f, 17.485279f, 18.485279f, 19.485279f, 20.485279f, 21.485279f, 22.485279f, 23.485279f, 24.485279f, 25.485279f, 10.656854f, 9.656854f, 8.656854f,
+    7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f,
+    12.485280f, 11.485280f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 5.242640f, 5.656854f, 6.656854f,
+    18.727919f, 17.727919f, 16.727921f, 15.727920f, 14.727921f, 13.727921f, 12.727921f, 12.313707f, 11.899494f, 11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 1.000000f, 0.000000f, 1.000000f, 1.000000f, 0.000000f,
+    1.000000f, 2.000000f, 13.899493f, 12.899493f, 11.899494f, 10.899494f, 9.899494f, 9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f,
+    9.899494f, 10.899494f, 11.899494f, 12.899493f, 13.899493f, 14.899493f, 15.899493f, 16.899492f, 17.899492f, 18.899492f, 19.899492f, 20.899492f, 21.899492f, 22.899492f, 23.899492f, 24.899492f, 25.899492f, 11.071067f, 10.071067f, 9.071068f,
+    8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f,
+    12.071067f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 6.656854f, 7.071068f,
+    8.071068f, 9.071068f, 17.142134f, 16.142134f, 15.142134f, 14.142134f, 13.727921f, 13.313707f, 12.899493f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 18.313705f, 17.313705f,
+    16.313705f, 15.313706f, 14.313706f, 13.313707f, 12.313707f, 11.313707f, 10.899494f, 10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f,
+    10.899494f, 11.313707f, 12.313707f, 13.313707f, 14.313706f, 15.313706f, 16.313705f, 17.313705f, 18.313705f, 19.313705f, 20.313705f, 21.313705f, 22.313705f, 23.313705f, 24.313705f, 25.313705f, 4.242640f, 11.485280f, 10.485281f, 9.485281f,
+    8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f, 10.485281f, 11.485280f, 12.485280f, 13.485280f, 14.485280f, 15.485279f,
+    11.656854f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f,
+    8.485281f, 9.485281f, 10.485281f, 16.556347f, 15.556347f, 15.142134f, 14.727921f, 14.313706f, 13.899493f, 13.485280f, 13.071067f, 12.656853f, 12.242640f, 4.414214f, 2.828427f, 2.414214f, 2.000000f, 19.727919f, 18.727919f, 17.727919f,
+    16.727921f, 2.828427f, 2.414214f, 13.727921f, 12.727921f, 12.313707f, 11.899494f, 11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 11.071067f, 11.485280f,
+    11.899494f, 12.313707f, 12.727921f, 13.727921f, 14.727921f, 15.727920f, 16.727921f, 17.727919f, 18.727919f, 19.727919f, 20.727919f, 21.727919f, 22.727919f, 23.727919f, 24.727919f, 2.828427f, 3.828427f, 11.899494f, 10.899494f, 9.899494f,
+    9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f, 10.899494f, 11.899494f, 12.899493f, 13.899493f, 14.899493f, 15.899493f,
+    11.242640f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f,
+    11.656854f, 11.242640f, 10.899494f, 10.414213f, 0.000000f, 16.142134f, 15.727920f, 15.313706f, 14.899493f, 14.485280f, 14.071066f, 13.656853f, 13.242640f, 3.414214f, 3.000000f, 3.414214f, 21.142132f, 20.142132f, 19.142132f, 18.142134f,
+    17.727921f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 13.313707f, 12.899493f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f, 11.242640f, 11.656854f, 12.071067f, 12.485280f,
+    12.899493f, 13.313707f, 13.727921f, 14.142134f, 15.142134f, 16.142134f, 17.142134f, 18.142134f, 19.142132f, 20.142132f, 21.142132f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 12.313707f, 11.313707f, 10.899494f,
+    10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f, 10.899494f, 11.313707f, 12.313707f, 13.313707f, 14.313706f, 15.313706f, 5.656854f,
+    10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f,
+    10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 11.071067f, 15.071066f, 14.656853f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 20.556345f, 19.556347f, 19.142134f,
+    18.727921f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 14.313706f, 13.899493f, 13.485280f, 13.071067f, 12.656853f, 12.242640f, 11.828426f, 11.414213f, 11.000000f, 11.414213f, 11.828426f, 12.242640f, 12.656853f, 13.071067f, 13.485280f,
+    13.899493f, 14.313706f, 14.727921f, 15.142134f, 15.556347f, 16.556347f, 17.556347f, 18.556347f, 19.556347f, 20.556345f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 12.313707f, 11.899494f,
+    11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 11.071067f, 11.485280f, 11.899494f, 8.485281f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f,
+    10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f,
+    9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 16.071066f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.828427f, 2.828427f, 20.142134f,
+    2.000000f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 15.313706f, 14.899493f, 14.485280f, 14.071066f, 13.656853f, 13.242640f, 12.828426f, 12.414213f, 12.000000f, 12.414213f, 12.828426f, 13.242640f, 13.656853f, 12.656853f, 11.656854f,
+    10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 18.970560f, 19.970560f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 2.828427f, 3.828427f,
+    12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 4.828427f, 5.828427f, 5.828427f, 0.000000f, 6.656854f, 7.071068f, 8.071068f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f,
+    10.000000f, 9.000000f, 8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 8.000000f, 9.000000f,
+    8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f, 10.899494f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.414214f, 2.414214f, 1.414214f,
+    1.000000f, 1.414214f, 2.414214f, 3.414214f, 2.414214f, 16.313705f, 15.899493f, 15.485279f, 15.071066f, 14.656853f, 14.242640f, 13.828426f, 13.414213f, 13.000000f, 13.414213f, 15.242640f, 14.242640f, 13.242640f, 12.242640f, 11.242640f,
+    10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f,
+    4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 14.899493f,
+    10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f,
+    7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f, 10.485281f, 11.485280f, 1.000000f, 1.414214f, 4.000000f, 3.000000f, 2.000000f, 1.000000f,
+    0.000000f, 1.000000f, 2.000000f, 3.000000f, 17.727919f, 17.313705f, 16.899492f, 16.485279f, 16.071066f, 15.656853f, 15.242640f, 14.828426f, 14.414213f, 14.000000f, 14.414213f, 14.828426f, 13.828426f, 12.828426f, 11.828426f, 10.828426f,
+    9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 0.000000f, 3.828427f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f,
+    4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 0.000000f, 12.656854f, 13.071067f, 13.485280f, 13.899493f,
+    10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f,
+    6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 11.071067f, 2.000000f, 2.414214f, 2.828427f, 3.414214f, 2.414214f, 1.414214f,
+    1.000000f, 1.414214f, 2.414214f, 3.414214f, 18.727919f, 18.313705f, 17.899492f, 17.485279f, 17.071066f, 16.656853f, 16.242640f, 15.828426f, 15.414213f, 15.000000f, 15.414213f, 14.414213f, 13.414213f, 12.414213f, 11.414213f, 10.414213f,
+    9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 5.414214f,
+    4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 2.414214f, 1.414214f, 11.242640f, 11.656854f, 12.071067f, 12.485280f, 12.899493f,
+    11.242640f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 6.656854f,
+    5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f, 3.000000f, 3.414214f, 3.000000f, 3.828427f, 2.828427f, 2.414214f,
+    2.000000f, 2.414214f, 21.142132f, 20.142132f, 19.727919f, 19.313705f, 18.899492f, 18.485279f, 18.071066f, 17.656853f, 17.242640f, 16.828426f, 16.414213f, 16.000000f, 16.414213f, 14.000000f, 13.000000f, 12.000000f, 11.000000f, 10.000000f,
+    9.000000f, 8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 2.828427f, 6.828427f, 2.000000f, 8.828427f, 9.828426f, 10.828426f,
+    11.828426f, 12.828426f, 2.828427f, 2.414214f, 2.000000f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 10.242640f, 10.656854f, 11.071067f, 11.485280f, 11.899494f,
+    11.656854f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 6.242640f,
+    5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 4.000000f, 2.414214f, 2.000000f, 2.414214f, 25.556345f, 24.556345f,
+    23.556345f, 22.556345f, 21.556345f, 21.142132f, 20.727919f, 20.313705f, 19.899492f, 19.485279f, 19.071066f, 18.656853f, 18.242640f, 17.828426f, 17.414213f, 1.000000f, 1.414214f, 14.899493f, 13.414213f, 12.414213f, 11.414213f, 10.414213f,
+    9.414213f, 8.414213f, 20.556345f, 20.142132f, 19.727919f, 19.313705f, 18.899492f, 18.485279f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f, 10.414213f,
+    11.414213f, 12.414213f, 13.414213f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 5.242640f, 4.242640f, 3.828427f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f, 10.899494f,
+    18.656855f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 5.828427f,
+    4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 2.414214f, 1.414214f, 1.000000f, 26.970558f, 25.970558f, 24.970558f,
+    23.970558f, 22.970558f, 22.556345f, 22.142132f, 21.727919f, 21.313705f, 20.899492f, 20.485279f, 20.071066f, 19.656853f, 19.242640f, 18.828426f, 1.000000f, 0.000000f, 1.000000f, 13.899493f, 14.899493f, 15.899493f, 21.213200f, 20.798986f,
+    20.384773f, 19.970560f, 19.556347f, 19.142132f, 18.727919f, 18.313705f, 17.899492f, 17.485279f, 17.071066f, 16.656853f, 16.242640f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 10.828426f,
+    11.828426f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f,
+    17.656855f, 18.071068f, 18.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f, 6.414214f, 5.414214f,
+    4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f, 2.000000f, 1.000000f, 0.000000f, 27.384771f, 26.384771f, 25.384771f,
+    24.384771f, 23.970558f, 23.556345f, 23.142132f, 22.727919f, 22.313705f, 21.899492f, 21.485279f, 21.071066f, 20.656853f, 8.485281f, 9.485281f, 10.485281f, 11.485280f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 20.798986f, 19.798986f,
+    19.384773f, 18.970560f, 18.556347f, 18.142134f, 17.727919f, 17.313705f, 16.899492f, 16.485279f, 16.071066f, 15.656853f, 15.242640f, 1.414214f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 11.242640f,
+    8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f,
+    16.656855f, 17.071068f, 17.485281f, 17.899494f, 18.313707f, 18.727921f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f, 6.000000f, 5.000000f,
+    4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 8.000000f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 27.798985f, 26.798985f, 25.798985f,
+    25.384771f, 24.970558f, 24.556345f, 24.142132f, 23.727919f, 23.313705f, 22.899492f, 22.485279f, 22.071066f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f, 17.071066f,
+    18.384773f, 17.970560f, 17.556347f, 17.142134f, 16.727921f, 16.313705f, 15.899493f, 15.485279f, 15.071066f, 14.656853f, 14.242640f, 13.828426f, 0.000000f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f, 11.656854f,
+    9.242640f, 8.242640f, 7.242641f, 6.242641f, 5.242641f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f,
+    15.656855f, 16.071068f, 16.485281f, 16.899494f, 17.313707f, 17.727921f, 18.727921f, 0.000000f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f, 10.899494f, 6.414214f, 5.414214f,
+    4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 1.000000f, 0.000000f, 2.414214f, 2.000000f, 2.414214f, 27.213198f, 26.798985f,
+    26.384771f, 25.970558f, 25.556345f, 25.142132f, 24.727919f, 24.313705f, 23.899492f, 23.485279f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 15.656853f, 18.970560f,
+    17.970560f, 16.970560f, 16.556347f, 16.142134f, 15.727920f, 15.313706f, 14.899493f, 14.485280f, 14.071066f, 13.656853f, 13.242640f, 12.828426f, 12.414213f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 11.071067f, 12.071067f,
+    13.071067f, 12.656853f, 11.656854f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f,
+    14.656855f, 15.071068f, 15.485281f, 15.899494f, 16.313707f, 17.313707f, 18.313707f, 19.313707f, 20.313707f, 21.313707f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 11.071067f, 11.485280f, 7.828427f, 6.828427f, 5.828427f,
+    4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 13.242640f, 12.242640f, 11.242640f, 10.242640f, 0.000000f, 8.242640f, 28.213198f, 27.798985f,
+    27.384771f, 26.970558f, 26.556345f, 26.142132f, 25.727919f, 25.313705f, 24.899492f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 15.242640f, 18.556347f,
+    17.556347f, 16.556347f, 15.556347f, 15.142134f, 14.727921f, 14.313706f, 13.899493f, 13.485280f, 13.071067f, 12.656853f, 12.242640f, 11.828426f, 11.414213f, 7.656854f, 8.071068f, 8.485281f, 9.485281f, 10.485281f, 11.485280f, 12.485280f,
+    13.485280f, 12.242640f, 11.242640f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f,
+    13.656855f, 14.071068f, 14.485281f, 14.899494f, 15.899494f, 16.899494f, 17.899494f, 18.899494f, 19.899494f, 20.899494f, 21.899494f, 10.414213f, 10.828426f, 11.242640f, 11.656854f, 12.071067f, 12.485280f, 8.242640f, 7.242640f, 6.242640f,
+    5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 13.828426f, 12.828426f, 11.828426f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 28.798985f,
+    28.384771f, 27.970558f, 27.556345f, 27.142132f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f, 14.828426f, 18.142134f,
+    17.142134f, 16.142134f, 15.142134f, 14.142134f, 13.727921f, 13.313707f, 12.899493f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.828426f, 11.242640f, 9.485281f, 9.899494f, 10.899494f, 11.899494f, 12.899493f,
+    13.899493f, 11.828426f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f,
+    12.656855f, 13.071068f, 13.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 20.313707f, 21.313707f, 22.313707f, 23.313707f, 11.828426f, 12.242640f, 12.656853f, 13.071067f, 13.485280f, 8.656854f, 7.656854f, 6.656854f,
+    5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 14.414213f, 13.414213f, 12.414213f, 11.414213f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f,
+    4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 3.000000f, 11.242640f, 12.242640f, 13.242640f, 19.727919f, 18.727919f, 17.727919f,
+    16.727921f, 15.727920f, 14.727921f, 13.727921f, 12.727921f, 12.313707f, 11.899494f, 11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.828426f, 10.242640f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f,
+    12.414213f, 11.414213f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f,
+    11.656855f, 11.071067f, 12.485281f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 12.828426f, 13.242640f, 13.656853f, 7.656854f, 8.071068f, 9.071068f, 8.071068f, 7.071068f,
+    6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 14.000000f, 13.000000f, 12.000000f, 11.000000f, 10.000000f, 9.000000f, 8.000000f, 7.000000f, 6.000000f, 5.000000f,
+    4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.000000f, 3.414214f, 18.313705f, 17.313705f,
+    16.313705f, 15.313706f, 14.313706f, 13.313707f, 12.313707f, 11.313707f, 10.899494f, 10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.828427f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f,
+    5.414214f, 11.000000f, 10.000000f, 9.000000f, 8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f,
+    10.656855f, 11.071068f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 14.656853f, 6.656854f, 7.656854f, 9.485281f, 8.485281f, 8.071068f,
+    7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 17.414213f, 16.414213f, 15.414213f, 14.414213f, 13.414213f, 12.414213f, 11.414213f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f,
+    4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 2.000000f, 2.414214f, 17.899492f, 16.899492f,
+    15.899493f, 14.899493f, 13.899493f, 12.899493f, 11.899494f, 10.899494f, 9.899494f, 9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 4.828427f,
+    4.414214f, 4.000000f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f,
+    9.656855f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.485281f, 9.071068f,
+    8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 17.828426f, 25.556345f, 25.970558f, 26.384771f, 26.798985f, 27.213198f, 27.627411f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f,
+    4.828427f, 3.828427f, 2.828427f, 2.000000f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 1.000000f, 1.414214f, 2.414214f, 16.485279f,
+    15.485279f, 14.485280f, 13.485280f, 12.485280f, 11.485280f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.828427f,
+    3.414214f, 3.000000f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f,
+    8.656855f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 10.485281f, 10.071067f,
+    9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 23.727919f, 24.142132f, 24.556345f, 24.970558f, 25.384771f, 25.798985f, 26.213198f, 26.627413f, 27.041626f, 27.455839f, 9.242640f, 8.242640f, 7.242640f, 6.242640f,
+    5.242640f, 2.414214f, 3.828427f, 1.000000f, 1.414214f, 2.414214f, 3.828427f, 4.242640f, 39.284271f, 40.284271f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 0.000000f, 1.000000f, 2.000000f, 3.000000f,
+    15.071066f, 14.071066f, 13.071067f, 12.071067f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 2.828427f,
+    2.414214f, 2.000000f, 2.414214f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f,
+    7.656854f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 11.071067f,
+    10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 22.313705f, 22.727919f, 23.142132f, 23.556345f, 23.970558f, 24.384771f, 24.798985f, 25.213200f, 25.627413f, 26.041626f, 26.455839f, 26.870052f, 8.656854f, 7.656854f, 6.656854f,
+    3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 37.870056f, 38.870056f, 39.870056f, 40.870056f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f,
+    14.656853f, 13.656853f, 12.656853f, 11.656854f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 3.000000f, 3.414214f, 3.828427f, 2.414214f,
+    1.414214f, 1.000000f, 1.414214f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f,
+    6.656854f, 6.242640f, 8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 8.000000f, 9.000000f,
+    10.000000f, 11.000000f, 20.071066f, 20.485279f, 20.899492f, 21.313705f, 21.727919f, 22.142132f, 22.556345f, 22.970558f, 23.384771f, 23.798986f, 24.213200f, 24.627413f, 25.041626f, 25.455839f, 26.455839f, 27.455839f, 28.455839f, 29.455839f,
+    30.455837f, 31.455837f, 32.455837f, 1.000000f, 34.455841f, 35.455841f, 36.455841f, 37.455841f, 38.455841f, 39.455841f, 40.455841f, 41.455841f, 42.455841f, 43.455841f, 44.455841f, 2.414214f, 2.000000f, 2.414214f, 7.656854f, 6.656854f,
+    5.656854f, 5.242640f, 12.242640f, 11.242640f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 2.000000f,
+    1.000000f, 0.000000f, 1.000000f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f,
+    5.656854f, 5.242640f, 4.828427f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 17.828426f,
+    18.242640f, 18.656853f, 19.071066f, 19.485279f, 19.899492f, 20.313705f, 20.727919f, 21.142132f, 21.556345f, 21.970558f, 22.384773f, 22.798986f, 23.213200f, 23.627413f, 24.041626f, 25.041626f, 26.041626f, 27.041626f, 28.041626f, 29.041624f,
+    30.041624f, 31.041624f, 32.041626f, 33.041626f, 34.041626f, 35.041626f, 36.041626f, 37.041626f, 38.041626f, 39.041626f, 40.041626f, 41.041626f, 42.041626f, 43.041626f, 44.041626f, 45.041626f, 46.041626f, 47.041626f, 7.242640f, 6.242640f,
+    5.242640f, 4.242640f, 3.828427f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f,
+    1.414214f, 1.000000f, 1.414214f, 11.485280f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f,
+    5.242640f, 4.242640f, 3.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 16.414213f, 16.828426f,
+    17.242640f, 17.656853f, 18.071066f, 18.485279f, 18.899492f, 19.313705f, 19.727919f, 20.142132f, 20.556345f, 20.970560f, 21.384773f, 21.798986f, 22.213200f, 22.627413f, 23.627413f, 24.627413f, 25.627413f, 26.627413f, 27.627411f, 28.627411f,
+    29.627411f, 30.627411f, 31.627411f, 32.627411f, 33.627411f, 34.627411f, 35.627411f, 36.627411f, 37.627411f, 38.627411f, 39.627411f, 40.627411f, 41.627411f, 42.627411f, 43.627411f, 44.627411f, 45.627411f, 46.627411f, 47.627411f, 48.627411f,
+    4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f,
+    2.414214f, 2.000000f, 2.414214f, 2.828427f, 10.899494f, 9.899494f, 9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f,
+    4.828427f, 3.828427f, 2.828427f, 2.414214f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 15.000000f, 15.414213f, 15.828426f,
+    16.242640f, 16.656853f, 17.071066f, 17.485279f, 17.899492f, 18.313705f, 18.727919f, 19.142132f, 19.556347f, 19.970560f, 20.384773f, 20.798986f, 21.213200f, 22.213200f, 23.213200f, 24.213200f, 25.213200f, 26.213198f, 27.213198f, 28.213198f,
+    29.213198f, 30.213198f, 31.213198f, 32.213196f, 33.213196f, 34.213196f, 35.213196f, 36.213196f, 37.213196f, 38.213196f, 39.213196f, 40.213196f, 41.213196f, 42.213196f, 43.213196f, 44.213196f, 45.213196f, 46.213196f, 47.213196f, 48.213196f,
+    49.213196f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f,
+    7.000000f, 8.000000f, 3.414214f, 3.828427f, 11.313707f, 10.899494f, 10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f, 10.899494f,
+    4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 14.828426f, 14.414213f, 14.000000f, 14.414213f, 14.828426f,
+    15.242640f, 15.656853f, 16.071066f, 16.485279f, 16.899492f, 17.313705f, 17.727919f, 18.142134f, 18.556347f, 18.970560f, 19.384773f, 19.798986f, 20.798986f, 21.798986f, 22.798986f, 23.798986f, 24.798985f, 25.798985f, 26.798985f, 27.798985f,
+    28.798985f, 29.798985f, 30.798985f, 31.798985f, 32.798985f, 33.798985f, 34.798985f, 35.798985f, 36.798985f, 37.798985f, 38.798985f, 39.798985f, 40.798985f, 41.798985f, 42.798985f, 43.798985f, 44.798985f, 45.798985f, 46.798985f, 47.798985f,
+    48.798985f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f,
+    7.414214f, 8.414213f, 9.414213f, 4.828427f, 5.242640f, 6.242640f, 11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 11.071067f, 11.485280f, 11.899494f,
+    4.828427f, 3.828427f, 2.828427f, 1.000000f, 0.000000f, 1.000000f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 14.656853f, 14.242640f, 13.828426f, 13.414213f, 13.000000f, 13.414213f, 13.828426f,
+    14.242640f, 14.656853f, 15.071066f, 15.485279f, 15.899493f, 16.313705f, 16.727921f, 17.142134f, 17.556347f, 17.970560f, 18.384773f, 19.384773f, 20.384773f, 21.384773f, 22.384773f, 23.384771f, 24.384771f, 25.384771f, 26.384771f, 27.384771f,
+    28.384771f, 29.384771f, 30.384771f, 31.384771f, 32.384773f, 33.384773f, 34.384773f, 35.384773f, 36.384773f, 37.384773f, 38.384773f, 39.384773f, 40.384773f, 41.384773f, 42.384773f, 43.384773f, 44.384773f, 22.071066f, 22.485279f, 22.899492f,
+    23.313705f, 23.727919f, 24.142132f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f,
+    7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f, 11.242640f, 11.656854f, 12.071067f, 12.485280f, 12.899493f,
+    2.000000f, 2.414214f, 1.000000f, 0.000000f, 1.000000f, 1.414214f, 2.414214f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 10.071067f, 13.656853f, 13.242640f, 12.828426f, 12.414213f, 12.000000f, 12.414213f, 12.828426f,
+    13.242640f, 13.656853f, 14.071066f, 14.485280f, 14.899493f, 15.313706f, 15.727920f, 16.142134f, 16.556347f, 16.970560f, 17.970560f, 18.970560f, 19.970560f, 20.970560f, 21.970558f, 22.970558f, 23.970558f, 24.970558f, 25.970558f, 26.970558f,
+    27.970558f, 28.970558f, 29.970558f, 30.970558f, 31.970558f, 32.970558f, 33.970558f, 34.970558f, 35.970558f, 36.970558f, 37.970558f, 20.242640f, 19.828426f, 19.414213f, 19.828426f, 20.242640f, 20.656853f, 21.071066f, 21.485279f, 21.899492f,
+    22.313705f, 22.727919f, 23.142132f, 23.556345f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f,
+    8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 15.242640f, 12.656853f, 12.242640f, 11.828426f, 11.414213f, 11.000000f, 11.414213f, 11.828426f, 12.242640f, 12.656853f, 13.071067f, 13.485280f, 13.899493f,
+    1.000000f, 1.414214f, 4.828427f, 1.000000f, 2.000000f, 2.414214f, 2.828427f, 8.242640f, 7.828427f, 7.414214f, 7.656854f, 8.656854f, 13.071067f, 12.656853f, 12.242640f, 11.828426f, 11.414213f, 11.000000f, 11.414213f, 11.828426f,
+    12.242640f, 12.656853f, 13.071067f, 13.485280f, 13.899493f, 14.313706f, 14.727921f, 15.142134f, 15.556347f, 16.556347f, 17.556347f, 18.556347f, 19.556347f, 20.556345f, 21.556345f, 22.556345f, 23.556345f, 24.556345f, 25.556345f, 26.556345f,
+    27.556345f, 28.556345f, 29.556345f, 30.556345f, 31.556345f, 32.556343f, 33.556343f, 34.556343f, 35.556343f, 36.556343f, 19.656853f, 19.242640f, 18.828426f, 18.414213f, 18.828426f, 19.242640f, 19.656853f, 20.071066f, 20.485279f, 20.899492f,
+    21.313705f, 21.727919f, 22.142132f, 22.556345f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f,
+    8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 15.656853f, 16.656853f, 17.656853f, 12.828426f, 12.414213f, 12.000000f, 12.414213f, 12.828426f, 13.242640f, 13.656853f, 14.071066f, 14.485280f, 14.899493f,
+    0.000000f, 5.414214f, 4.414214f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f,
+    11.242640f, 11.656854f, 12.071067f, 12.485280f, 12.899493f, 13.313707f, 13.727921f, 14.142134f, 15.142134f, 16.142134f, 17.142134f, 18.142134f, 19.142132f, 20.142132f, 21.142132f, 22.142132f, 23.142132f, 24.142132f, 25.142132f, 26.142132f,
+    27.142132f, 28.142132f, 29.142132f, 30.142132f, 31.142132f, 32.142132f, 33.142132f, 34.142132f, 19.485279f, 19.071066f, 18.656853f, 18.242640f, 17.828426f, 17.414213f, 17.828426f, 18.242640f, 18.656853f, 19.071066f, 19.485279f, 19.899492f,
+    20.313705f, 20.727919f, 21.142132f, 21.556345f, 21.970558f, 22.384773f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f,
+    9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f, 17.071066f, 18.071066f, 19.071066f, 20.071066f, 21.071066f, 13.414213f, 13.828426f, 14.242640f, 14.656853f, 15.071066f, 19.414213f, 19.828426f,
+    1.000000f, 5.828427f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f,
+    10.242640f, 10.656854f, 11.071067f, 11.485280f, 11.899494f, 12.313707f, 12.727921f, 13.727921f, 14.727921f, 15.727920f, 16.727921f, 17.727919f, 18.727919f, 19.727919f, 20.727919f, 21.727919f, 22.727919f, 23.727919f, 24.727919f, 25.727919f,
+    26.727919f, 27.727919f, 28.727919f, 29.727919f, 30.727919f, 31.727919f, 32.727921f, 33.727921f, 18.485279f, 18.071066f, 17.656853f, 17.242640f, 16.828426f, 16.414213f, 16.828426f, 17.242640f, 17.656853f, 18.071066f, 18.485279f, 18.899492f,
+    19.313705f, 19.727919f, 20.142132f, 20.556345f, 20.970560f, 21.970558f, 22.970558f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f,
+    9.485281f, 10.485281f, 11.485280f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 16.485279f, 17.485279f, 18.485279f, 19.485279f, 20.485279f, 21.485279f, 22.485279f, 2.414214f, 2.000000f, 2.414214f, 18.000000f, 18.414213f, 18.828426f,
+    2.000000f, 2.414214f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 10.899494f, 10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f,
+    9.242640f, 9.656854f, 10.071067f, 10.485281f, 10.899494f, 11.313707f, 12.313707f, 13.313707f, 14.313706f, 15.313706f, 16.313705f, 17.313705f, 18.313705f, 19.313705f, 20.313705f, 21.313705f, 22.313705f, 23.313705f, 24.313705f, 25.313705f,
+    26.313705f, 27.313705f, 28.313705f, 29.313705f, 30.313705f, 31.313705f, 32.313705f, 33.313705f, 17.485279f, 17.071066f, 16.656853f, 16.242640f, 15.828426f, 15.414213f, 15.828426f, 16.242640f, 16.656853f, 17.071066f, 17.485279f, 17.899492f,
+    18.313705f, 18.727919f, 19.142132f, 19.556347f, 20.556345f, 21.556345f, 22.556345f, 23.556345f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f,
+    9.899494f, 10.899494f, 11.899494f, 12.899493f, 13.899493f, 14.899493f, 15.899493f, 16.899492f, 17.899492f, 18.899492f, 5.828427f, 5.414214f, 21.899492f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 17.000000f, 17.414213f, 17.828426f,
+    8.242641f, 7.242641f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 9.899494f, 9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f,
+    8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f, 10.899494f, 11.899494f, 12.899493f, 13.899493f, 14.899493f, 15.899493f, 16.899492f, 17.899492f, 18.899492f, 19.899492f, 20.899492f, 21.899492f, 22.899492f, 23.899492f, 24.899492f,
+    25.899492f, 26.899492f, 27.899492f, 28.899492f, 29.899492f, 30.899492f, 31.899492f, 32.899490f, 16.485279f, 16.071066f, 15.656853f, 15.242640f, 14.828426f, 14.414213f, 14.828426f, 15.242640f, 15.656853f, 16.071066f, 16.485279f, 16.899492f,
+    17.313705f, 17.727919f, 18.142134f, 19.142132f, 20.142132f, 21.142132f, 22.142132f, 22.556345f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f,
+    10.899494f, 11.313707f, 12.313707f, 13.313707f, 14.313706f, 15.313706f, 16.313705f, 17.313705f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 16.000000f, 16.414213f, 16.828426f,
+    8.656855f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f,
+    7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f, 10.485281f, 11.485280f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 16.485279f, 17.485279f, 18.485279f, 19.485279f, 20.485279f, 21.485279f, 22.485279f, 23.485279f, 24.485279f,
+    25.485279f, 26.485279f, 27.485279f, 28.485279f, 29.485279f, 30.485279f, 31.485279f, 32.485279f, 15.485279f, 15.071066f, 14.656853f, 14.242640f, 13.828426f, 13.414213f, 13.828426f, 14.242640f, 14.656853f, 15.071066f, 15.485279f, 15.899493f,
+    16.313705f, 16.727921f, 17.727919f, 18.727919f, 19.727919f, 20.727919f, 21.142132f, 21.556345f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 9.828427f, 10.242640f, 0.000000f, 11.071067f, 11.485280f,
+    11.899494f, 12.313707f, 8.414213f, 8.000000f, 14.727921f, 15.727920f, 16.727921f, 17.727919f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 15.000000f, 15.414213f, 15.828426f,
+    9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f,
+    6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f, 17.071066f, 18.071066f, 19.071066f, 20.071066f, 21.071066f, 22.071066f, 23.071066f, 0.000000f,
+    25.071066f, 26.071066f, 27.071066f, 28.071066f, 29.071066f, 30.071066f, 31.071066f, 14.899493f, 14.485280f, 14.071066f, 13.656853f, 13.242640f, 12.828426f, 12.414213f, 12.828426f, 13.242640f, 13.656853f, 14.071066f, 14.485280f, 14.899493f,
+    15.313706f, 16.313705f, 17.313705f, 18.313705f, 19.313705f, 19.727919f, 20.142132f, 20.556345f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 11.242640f, 11.656854f, 12.071067f, 12.485280f,
+    12.899493f, 13.313707f, 7.414214f, 7.000000f, 7.414214f, 16.142134f, 17.142134f, 18.142134f, 19.142132f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.414214f, 2.000000f, 2.414214f, 14.000000f, 14.414213f, 14.828426f,
+    10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f,
+    5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 15.656853f, 16.656853f, 17.656853f, 18.656853f, 19.656853f, 20.656853f, 21.656853f, 22.656853f, 23.656853f,
+    24.656853f, 25.656853f, 26.656853f, 27.656853f, 28.656853f, 29.656853f, 30.656853f, 14.485280f, 13.485280f, 13.071067f, 12.656853f, 12.242640f, 11.828426f, 11.414213f, 11.828426f, 12.242640f, 12.656853f, 13.071067f, 13.485280f, 13.899493f,
+    2.414214f, 16.727921f, 17.727919f, 18.727919f, 19.142132f, 18.727919f, 19.142132f, 19.556347f, 20.556345f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 7.000000f, 7.414214f, 7.828427f, 13.485280f,
+    13.899493f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 17.142134f, 17.556347f, 18.556347f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.000000f, 13.414213f, 13.000000f, 13.414213f, 13.828426f,
+    11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f, 11.242640f, 10.242640f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f,
+    4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 15.242640f, 16.242640f, 17.242640f, 18.242640f, 19.242640f, 20.242640f, 21.242640f, 22.242640f, 23.242640f,
+    24.242640f, 25.242640f, 26.242640f, 27.242640f, 28.242640f, 29.242640f, 30.242640f, 14.071067f, 13.071067f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.828426f, 11.242640f, 11.656854f, 12.071067f, 12.485280f, 13.485280f,
+    2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 17.727919f, 18.142134f, 19.142132f, 20.142132f, 21.142132f, 22.142132f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.000000f, 6.414214f, 6.828427f, 7.242640f,
+    14.899493f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 18.556347f, 18.970560f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 12.414213f, 12.000000f, 12.414213f, 12.828426f,
+    12.656853f, 12.242640f, 11.828426f, 11.414213f, 11.000000f, 11.414213f, 11.828426f, 10.828426f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f,
+    3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f, 14.828426f, 15.828426f, 16.828426f, 17.828426f, 18.828426f, 19.828426f, 20.828426f, 21.828426f, 22.828426f,
+    23.828426f, 24.828426f, 25.828426f, 26.828426f, 27.828426f, 28.828426f, 29.828426f, 30.828426f, 12.656854f, 11.656854f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 11.071067f, 12.071067f, 13.071067f,
+    14.071067f, 15.071067f, 15.485280f, 15.899493f, 16.313705f, 16.727921f, 17.727919f, 18.727919f, 19.727919f, 20.727919f, 21.727919f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 5.000000f, 5.414214f, 5.828427f, 6.242640f,
+    6.656854f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 7.828427f, 20.384773f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 11.414213f, 11.000000f, 11.414213f, 11.828426f,
+    13.656853f, 13.242640f, 12.828426f, 12.414213f, 12.000000f, 12.414213f, 11.414213f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f,
+    3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f, 14.414213f, 15.414213f, 16.414213f, 17.414213f, 18.414213f, 19.414213f, 20.414213f, 21.414213f, 22.414213f,
+    23.414213f, 24.414213f, 25.414213f, 26.414213f, 27.414213f, 28.414213f, 29.414213f, 30.414213f, 31.414213f, 32.414215f, 10.242640f, 9.242640f, 8.828427f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.656854f, 11.656854f, 12.656854f,
+    13.656854f, 14.071067f, 14.485280f, 14.899493f, 15.313706f, 16.313705f, 17.313705f, 18.313705f, 19.313705f, 20.313705f, 21.313705f, 22.313705f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 4.000000f, 4.414214f, 4.828427f, 5.242640f,
+    5.656854f, 6.656854f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 6.828427f, 6.414214f, 6.000000f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 10.414213f, 10.000000f, 10.414213f, 10.828426f,
+    14.656853f, 14.242640f, 13.828426f, 13.414213f, 13.000000f, 13.414213f, 13.828426f, 10.000000f, 9.000000f, 8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f,
+    3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 8.000000f, 9.000000f, 10.000000f, 11.000000f, 12.000000f, 13.000000f, 14.000000f, 15.000000f, 16.000000f, 17.000000f, 18.000000f, 19.000000f, 20.000000f, 21.000000f, 22.000000f,
+    23.000000f, 24.000000f, 25.000000f, 26.000000f, 27.000000f, 24.142134f, 29.828426f, 30.828426f, 31.828426f, 32.828426f, 33.828426f, 34.828426f, 7.828427f, 7.414214f, 7.828427f, 8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f,
+    12.656854f, 13.071067f, 13.485280f, 13.899493f, 14.899493f, 15.899493f, 16.899492f, 17.899492f, 18.899492f, 19.899492f, 20.899492f, 21.899492f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f,
+    5.242640f, 6.242640f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 9.414213f, 9.000000f, 9.414213f, 9.828426f,
+    15.656853f, 15.242640f, 14.828426f, 14.414213f, 14.000000f, 14.414213f, 14.828426f, 10.414213f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f,
+    3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f, 14.414213f, 15.414213f, 16.414213f, 17.414213f, 18.414213f, 19.414213f, 20.414213f, 21.414213f, 22.414213f,
+    23.414213f, 24.414213f, 25.414213f, 22.313707f, 22.727921f, 28.414213f, 29.414213f, 30.414213f, 31.414213f, 32.414215f, 33.414215f, 34.414215f, 6.828427f, 6.414214f, 6.828427f, 7.828427f, 3.000000f, 3.414214f, 11.656854f, 11.242640f,
+    11.656854f, 12.071067f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 16.485279f, 17.485279f, 18.485279f, 19.485279f, 20.485279f, 21.485279f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f,
+    4.828427f, 5.828427f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 8.414213f, 8.000000f, 8.414213f, 8.828427f,
+    16.656853f, 16.242640f, 15.828426f, 15.414213f, 15.000000f, 15.414213f, 15.828426f, 16.242640f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f,
+    3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f, 14.828426f, 15.828426f, 16.828426f, 17.828426f, 18.828426f, 19.828426f, 20.828426f, 21.828426f, 22.828426f,
+    23.828426f, 20.485281f, 20.899494f, 21.313707f, 29.828426f, 29.414213f, 29.828426f, 30.828426f, 31.828426f, 32.828426f, 33.828426f, 34.828426f, 35.828426f, 5.414214f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 10.242640f,
+    10.656854f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f, 17.071066f, 18.071066f, 19.071066f, 20.071066f, 21.071066f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f,
+    4.414214f, 5.414214f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.414214f, 5.828427f, 6.242640f, 7.414214f, 7.000000f, 7.414214f, 7.828427f,
+    17.656853f, 17.242640f, 16.828426f, 16.414213f, 16.000000f, 16.414213f, 16.828426f, 17.242640f, 17.656853f, 18.656853f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f,
+    4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 15.242640f, 16.242640f, 17.242640f, 18.242640f, 19.242640f, 20.242640f, 21.242640f, 22.242640f, 20.313707f,
+    19.899494f, 19.485281f, 19.899494f, 31.242640f, 30.828426f, 30.414213f, 30.828426f, 31.242640f, 32.242638f, 33.242638f, 34.242638f, 35.242638f, 4.000000f, 4.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 9.242640f,
+    9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 15.656853f, 16.656853f, 17.656853f, 18.656853f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f,
+    4.000000f, 5.000000f, 1.414214f, 1.000000f, 1.414214f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f,
+    18.656853f, 18.242640f, 17.828426f, 17.414213f, 17.000000f, 17.414213f, 17.828426f, 18.242640f, 18.656853f, 19.071066f, 20.071066f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f,
+    5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 15.656853f, 16.656853f, 17.656853f, 18.656853f, 19.656853f, 20.656853f, 21.656853f, 19.727921f, 19.313707f,
+    18.899494f, 18.485281f, 18.899494f, 32.242638f, 31.828426f, 31.414213f, 31.828426f, 32.242638f, 32.656853f, 33.656853f, 34.656853f, 35.656853f, 3.000000f, 3.414214f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 8.242640f,
+    9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 15.242640f, 16.242640f, 17.242640f, 18.242640f, 19.242640f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f,
+    4.414214f, 5.414214f, 2.414214f, 2.000000f, 2.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f,
+    1.414214f, 1.000000f, 18.828426f, 18.414213f, 18.000000f, 18.414213f, 18.828426f, 12.899494f, 19.656853f, 10.071068f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f,
+    6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f, 17.071066f, 18.071066f, 19.071066f, 20.071066f, 21.071066f, 22.071066f, 18.727921f, 18.313707f,
+    17.899494f, 17.485281f, 33.656853f, 33.242638f, 32.828426f, 32.414215f, 32.828426f, 33.242638f, 33.656853f, 34.071068f, 35.071068f, 36.071068f, 2.000000f, 2.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 6.828427f, 7.828427f,
+    8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f, 14.828426f, 15.828426f, 16.828426f, 17.828426f, 18.828426f, 19.828426f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f,
+    13.242640f, 12.828426f, 3.414214f, 3.000000f, 3.414214f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f,
+    1.000000f, 0.000000f, 19.828426f, 19.414213f, 19.000000f, 19.414213f, 13.485281f, 12.485281f, 11.485281f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f,
+    7.242640f, 7.656854f, 8.071068f, 8.485281f, 3.000000f, 3.414214f, 3.828427f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 16.485279f, 17.485279f, 18.485279f, 19.485279f, 20.485279f, 21.485279f, 22.485279f, 17.727921f, 17.313707f,
+    16.899494f, 16.485281f, 34.656853f, 34.242638f, 33.828426f, 33.414215f, 33.828426f, 34.242638f, 34.656853f, 35.071068f, 35.485283f, 1.414214f, 1.000000f, 1.414214f, 2.828427f, 2.414214f, 2.000000f, 5.414214f, 6.414214f, 7.414214f,
+    8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f, 14.414213f, 15.414213f, 16.414213f, 17.414213f, 18.414213f, 19.414213f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f,
+    12.242640f, 11.828426f, 11.414213f, 4.000000f, 4.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f,
+    20.727921f, 19.727921f, 18.727921f, 20.414213f, 20.000000f, 14.899494f, 13.899494f, 12.899494f, 11.899494f, 10.899494f, 9.899494f, 9.485281f, 9.071068f, 8.656854f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f,
+    8.242640f, 8.656854f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 13.899493f, 14.899493f, 15.899493f, 16.899492f, 17.899492f, 18.899492f, 19.899492f, 20.899492f, 21.899492f, 22.899492f, 17.313707f, 16.313707f,
+    15.899494f, 15.485281f, 35.656853f, 35.242638f, 34.828426f, 34.414215f, 34.828426f, 35.242638f, 35.656853f, 36.071068f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f,
+    8.000000f, 9.000000f, 10.000000f, 11.000000f, 12.000000f, 13.000000f, 14.000000f, 15.000000f, 16.000000f, 17.000000f, 18.000000f, 19.000000f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f,
+    11.242640f, 10.828426f, 10.414213f, 5.000000f, 5.414214f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f,
+    20.313707f, 19.313707f, 18.313707f, 17.313707f, 16.313707f, 15.313707f, 14.313707f, 13.313707f, 12.313707f, 11.313707f, 10.899494f, 10.485281f, 10.071067f, 9.656854f, 9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f,
+    4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 14.899493f, 15.313706f, 16.313705f, 17.313705f, 18.313705f, 19.313705f, 20.313705f, 21.313705f, 22.313705f, 23.313705f, 24.313705f, 15.899494f,
+    14.899494f, 14.485281f, 36.656853f, 36.242638f, 35.828426f, 35.414215f, 35.828426f, 36.242638f, 36.656853f, 37.071068f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f,
+    8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f, 14.414213f, 15.414213f, 16.414213f, 17.414213f, 18.414213f, 19.414213f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 11.071067f, 10.656854f,
+    10.242640f, 9.828426f, 9.414213f, 6.000000f, 6.414214f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 0.000000f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f,
+    20.727921f, 19.727921f, 18.727921f, 17.727921f, 16.727921f, 15.727921f, 14.727921f, 13.727921f, 12.727921f, 12.313707f, 11.899494f, 11.485280f, 11.071067f, 10.656854f, 10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f,
+    4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 15.899493f, 16.313705f, 16.727921f, 17.727919f, 18.727919f, 19.727919f, 20.727919f, 21.727919f, 22.727919f, 23.727919f, 24.727919f, 15.485281f,
+    14.485281f, 13.485281f, 37.656853f, 37.242638f, 36.828426f, 36.414215f, 36.828426f, 37.242638f, 37.656853f, 38.071068f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f,
+    8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f, 14.828426f, 15.828426f, 16.828426f, 17.828426f, 18.828426f, 19.828426f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 10.485281f, 10.071067f, 9.656854f,
+    9.242640f, 8.828427f, 8.414213f, 8.000000f, 7.414214f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f,
+    21.142134f, 20.142134f, 19.142134f, 18.142134f, 17.142134f, 16.142134f, 15.142134f, 14.142134f, 13.727921f, 13.313707f, 12.899493f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f,
+    4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 16.899494f, 17.313705f, 17.727919f, 18.142134f, 19.142132f, 20.142132f, 21.142132f, 22.142132f, 23.142132f, 24.142132f, 25.142132f, 26.142132f,
+    14.071068f, 13.071068f, 12.071068f, 38.242638f, 37.828426f, 37.414215f, 37.828426f, 38.242638f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f,
+    9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 15.242640f, 16.242640f, 17.242640f, 18.242640f, 19.242640f, 20.242640f, 4.000000f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 9.485281f, 9.071068f, 8.656854f,
+    8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.656854f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f,
+    21.556347f, 20.556347f, 19.556347f, 18.556347f, 17.556347f, 16.556347f, 15.556347f, 15.142134f, 14.727921f, 14.313706f, 13.899493f, 13.485280f, 13.071067f, 12.656853f, 12.242640f, 11.828426f, 11.414213f, 11.000000f, 11.414213f, 11.828426f,
+    0.000000f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 18.313707f, 17.899494f, 18.313705f, 18.727919f, 19.142132f, 19.556347f, 20.556345f, 21.556345f, 22.556345f, 23.556345f, 24.556345f, 25.556345f, 26.556345f,
+    13.656855f, 12.656855f, 11.656855f, 10.656855f, 9.656855f, 8.656855f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f,
+    9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 15.656853f, 16.656853f, 17.656853f, 18.656853f, 19.656853f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f,
+    7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 12.071067f, 7.656854f, 8.071068f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f,
+    21.970560f, 20.970560f, 19.970560f, 18.970560f, 17.970560f, 16.970560f, 16.556347f, 16.142134f, 15.727920f, 15.313706f, 14.899493f, 14.485280f, 14.071066f, 13.656853f, 13.242640f, 12.828426f, 12.414213f, 12.000000f, 12.414213f, 12.828426f,
+    13.242640f, 14.242640f, 15.242640f, 3.414214f, 3.000000f, 19.071066f, 19.727921f, 19.313707f, 18.899494f, 19.313705f, 19.727919f, 20.142132f, 20.556345f, 20.970560f, 21.970558f, 22.970558f, 23.970558f, 24.970558f, 25.970558f, 26.970558f,
+    27.970558f, 13.071068f, 12.071068f, 11.071068f, 10.071068f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f,
+    10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f, 17.071066f, 18.071066f, 19.071066f, 20.071066f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 8.071068f, 7.071068f, 6.656854f,
+    6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 11.071067f, 12.071067f, 13.071067f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f,
+    22.384773f, 21.384773f, 20.384773f, 19.384773f, 18.384773f, 17.970560f, 17.556347f, 17.142134f, 16.727921f, 16.313705f, 15.899493f, 15.485279f, 15.071066f, 14.656853f, 14.242640f, 13.828426f, 13.414213f, 13.000000f, 13.414213f, 13.828426f,
+    14.242640f, 14.656853f, 15.656853f, 16.656853f, 17.656853f, 18.656853f, 19.656853f, 20.313707f, 19.899494f, 20.313705f, 3.414214f, 3.000000f, 3.414214f, 21.970558f, 22.384773f, 23.384771f, 24.384771f, 25.384771f, 26.384771f, 27.384771f,
+    28.384771f, 29.384771f, 12.485281f, 11.485281f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f,
+    10.485281f, 11.485280f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 16.485279f, 17.485279f, 18.485279f, 19.485279f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 7.656854f, 6.656854f, 5.656854f,
+    5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 8.000000f, 8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656853f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f,
+    22.798986f, 21.798986f, 20.798986f, 19.798986f, 19.384773f, 18.970560f, 18.556347f, 18.142134f, 17.727919f, 17.313705f, 16.899492f, 16.485279f, 16.071066f, 15.656853f, 15.242640f, 14.828426f, 14.414213f, 14.000000f, 14.414213f, 14.828426f,
+    15.242640f, 15.656853f, 16.071066f, 17.071066f, 18.071066f, 19.071066f, 20.071066f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 25.798985f, 26.798985f, 27.798985f,
+    28.798985f, 29.798985f, 30.798985f, 11.899494f, 10.899494f, 9.899494f, 9.485281f, 9.071068f, 1.414214f, 1.000000f, 0.000000f, 1.000000f, 3.414214f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f,
+    10.899494f, 11.899494f, 12.899493f, 13.899493f, 14.899493f, 15.899493f, 16.899492f, 17.899492f, 18.899492f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.242640f, 5.242640f,
+    4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f,
+    23.213200f, 22.213200f, 21.213200f, 20.798986f, 20.384773f, 19.970560f, 19.556347f, 19.142132f, 18.727919f, 18.313705f, 17.899492f, 17.485279f, 17.071066f, 16.656853f, 16.242640f, 15.828426f, 15.414213f, 15.000000f, 1.000000f, 0.000000f,
+    16.242640f, 16.656853f, 17.071066f, 17.485279f, 18.485279f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 27.213198f, 28.213198f,
+    29.213198f, 30.213198f, 31.213198f, 32.213196f, 9.242640f, 9.656854f, 10.071067f, 10.485281f, 1.000000f, 0.000000f, 1.000000f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 9.242640f, 9.656854f, 10.071067f, 10.485281f, 10.899494f,
+    11.313707f, 12.313707f, 13.313707f, 14.313706f, 15.313706f, 1.414214f, 17.313707f, 18.313705f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 6.828427f, 5.828427f, 4.828427f,
+    3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 6.414214f, 6.000000f, 6.414214f, 6.828427f,
+    23.627413f, 22.627413f, 22.213200f, 21.798986f, 21.384773f, 20.970560f, 20.556345f, 20.142132f, 19.727919f, 19.313705f, 18.899492f, 18.485279f, 18.071066f, 17.656853f, 17.242640f, 16.828426f, 16.414213f, 16.000000f, 16.414213f, 17.414213f,
+    17.242640f, 17.656853f, 18.071066f, 18.485279f, 18.899492f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 28.213198f, 28.627411f,
+    29.627411f, 30.627411f, 31.627411f, 32.627411f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 1.414214f, 1.000000f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 10.656854f, 11.071067f, 11.485280f, 11.899494f,
+    12.313707f, 12.727921f, 13.727921f, 14.727921f, 15.727920f, 1.000000f, 0.000000f, 7.656854f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 6.414214f, 5.414214f, 4.414214f,
+    3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f, 7.000000f, 7.414214f, 7.828427f,
+    24.041626f, 23.627413f, 23.213200f, 22.798986f, 22.384773f, 21.970558f, 21.556345f, 21.142132f, 20.727919f, 20.313705f, 19.899492f, 19.485279f, 19.071066f, 18.656853f, 18.242640f, 17.828426f, 17.414213f, 17.000000f, 17.414213f, 17.828426f,
+    18.242640f, 18.656853f, 19.071066f, 2.414214f, 19.899492f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 29.213198f, 29.627411f,
+    6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 12.071067f, 3.828427f, 2.828427f,
+    2.414214f, 2.000000f, 14.142134f, 15.142134f, 16.142134f, 1.414214f, 1.000000f, 6.656854f, 6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 6.000000f, 5.000000f, 4.000000f,
+    3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 8.000000f, 9.000000f, 10.000000f, 11.000000f, 12.000000f, 13.000000f, 8.000000f, 8.414213f, 8.828427f,
+    25.041626f, 24.627413f, 24.213200f, 23.798986f, 23.384771f, 22.970558f, 22.556345f, 22.142132f, 21.727919f, 21.313705f, 20.899492f, 20.485279f, 20.071066f, 19.656853f, 19.242640f, 18.828426f, 18.414213f, 18.000000f, 18.414213f, 18.828426f,
+    19.242640f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 3.828427f, 32.727921f, 33.142132f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 5.828427f,
+    5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 3.414214f, 2.414214f,
+    1.414214f, 1.000000f, 1.414214f, 15.556347f, 16.556347f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 6.414214f, 5.414214f, 4.414214f,
+    3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f, 9.000000f, 9.414213f, 9.828426f,
+    26.041626f, 25.627413f, 25.213200f, 24.798985f, 24.384771f, 23.970558f, 23.556345f, 23.142132f, 22.727919f, 22.313705f, 21.899492f, 21.485279f, 21.071066f, 20.656853f, 20.242640f, 19.828426f, 19.414213f, 19.000000f, 19.414213f, 19.828426f,
+    20.242640f, 20.656853f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 31.727919f, 32.142132f, 33.142132f, 34.142132f, 35.142132f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 4.828427f,
+    4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 0.000000f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 5.828427f, 6.242640f, 6.656854f, 4.828427f, 2.000000f,
+    1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 5.828427f, 4.828427f,
+    3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f, 10.000000f, 10.414213f, 10.828426f,
+    27.041626f, 26.627413f, 26.213198f, 25.798985f, 25.384771f, 24.970558f, 24.556345f, 24.142132f, 23.727919f, 23.313705f, 22.899492f, 22.485279f, 22.071066f, 21.656853f, 21.242640f, 20.828426f, 20.414213f, 20.000000f, 20.414213f, 20.828426f,
+    21.242640f, 21.656853f, 22.071066f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 30.313705f, 30.727919f, 31.727919f, 32.727921f, 33.727921f, 34.727921f, 35.727921f, 1.414214f, 1.000000f, 1.414214f, 4.242640f, 3.828427f,
+    3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 4.242640f, 3.828427f, 3.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 3.828427f, 3.414214f,
+    3.000000f, 1.000000f, 1.414214f, 2.414214f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 6.242640f, 5.242640f,
+    4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 11.000000f, 11.414213f, 11.828426f,
+    28.041626f, 27.627411f, 27.213198f, 26.798985f, 26.384771f, 25.970558f, 25.556345f, 25.142132f, 24.727919f, 24.313705f, 23.899492f, 23.485279f, 23.071066f, 22.656853f, 22.242640f, 21.828426f, 21.414213f, 21.000000f, 21.414213f, 21.828426f,
+    22.242640f, 22.656853f, 23.071066f, 23.485279f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 29.313705f, 30.313705f, 31.313705f, 32.313705f, 33.313705f, 34.313705f, 35.313705f, 36.313705f, 37.313705f, 2.414214f, 3.828427f, 2.828427f,
+    2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f, 4.242640f, 4.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 2.828427f, 2.414214f,
+    2.000000f, 2.414214f, 2.414214f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 6.656854f, 5.656854f,
+    5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 12.000000f, 12.414213f, 12.828426f,
+    29.041624f, 28.627411f, 28.213198f, 27.798985f, 27.384771f, 26.970558f, 26.556345f, 26.142132f, 25.727919f, 25.313705f, 24.899492f, 24.485279f, 24.071066f, 23.656853f, 23.242640f, 22.828426f, 22.414213f, 22.000000f, 22.414213f, 22.828426f,
+    23.242640f, 23.656853f, 24.071066f, 24.485279f, 24.899492f, 25.899492f, 26.899492f, 27.899492f, 28.899492f, 29.899492f, 30.899492f, 31.899492f, 32.899490f, 33.899490f, 34.899490f, 35.899490f, 36.899490f, 37.899490f, 3.414214f, 2.414214f,
+    1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 2.414214f, 1.414214f,
+    1.000000f, 1.414214f, 9.000000f, 8.000000f, 7.000000f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 6.656854f,
+    6.242640f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f, 13.414213f, 13.828426f,
+    30.041624f, 29.627411f, 29.213198f, 28.798985f, 28.384771f, 27.970558f, 27.556345f, 27.142132f, 26.727919f, 26.313705f, 25.899492f, 25.485279f, 25.071066f, 24.656853f, 24.242640f, 23.828426f, 23.414213f, 23.000000f, 23.414213f, 23.828426f,
+    24.242640f, 24.656853f, 25.071066f, 25.485279f, 25.899492f, 26.313705f, 27.313705f, 28.313705f, 29.313705f, 30.313705f, 31.313705f, 32.313705f, 33.313705f, 34.313705f, 35.313705f, 36.313705f, 37.313705f, 38.313705f, 3.000000f, 2.000000f,
+    1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 2.000000f, 1.000000f,
+    0.000000f, 1.000000f, 9.414213f, 8.414213f, 7.414214f, 6.414214f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 8.414213f,
+    7.242640f, 6.828427f, 6.414214f, 6.000000f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 8.071068f, 8.485281f, 9.485281f, 10.485281f, 11.485280f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 16.485279f, 14.414213f, 14.828426f,
+    31.041624f, 30.627411f, 30.213198f, 29.798985f, 29.384771f, 28.970558f, 28.556345f, 28.142132f, 27.727919f, 27.313705f, 26.899492f, 26.485279f, 26.071066f, 25.656853f, 25.242640f, 24.828426f, 24.414213f, 24.000000f, 24.414213f, 24.828426f,
+    25.242640f, 25.656853f, 26.071066f, 26.485279f, 26.899492f, 27.313705f, 27.727919f, 28.727919f, 29.727919f, 30.727919f, 1.000000f, 32.727921f, 33.727921f, 34.727921f, 35.727921f, 36.727921f, 37.727921f, 38.727921f, 3.414214f, 2.414214f,
+    1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 7.414214f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 2.414214f, 1.414214f,
+    1.000000f, 1.414214f, 9.828426f, 8.828427f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 7.828427f, 8.828427f,
+    8.242640f, 7.828427f, 7.414214f, 7.000000f, 7.414214f, 7.828427f, 8.242640f, 8.656854f, 9.071068f, 9.485281f, 9.899494f, 10.899494f, 11.899494f, 12.899493f, 13.899493f, 14.899493f, 15.899493f, 16.899492f, 15.414213f, 15.828426f,
+    32.041626f, 31.627411f, 31.213198f, 30.798985f, 30.384771f, 29.970558f, 29.556345f, 29.142132f, 28.727919f, 28.313705f, 27.899492f, 27.485279f, 27.071066f, 26.656853f, 26.242640f, 25.828426f, 25.414213f, 25.000000f, 25.414213f, 25.828426f,
+    26.242640f, 26.656853f, 27.071066f, 27.485279f, 27.899492f, 28.313705f, 28.727919f, 29.142132f, 30.142132f, 1.000000f, 0.000000f, 33.727921f, 34.142136f, 35.142136f, 7.828427f, 6.828427f, 5.828427f, 4.828427f, 3.828427f, 2.828427f,
+    2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 4.828427f, 5.828427f, 6.828427f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 1.000000f, 1.414214f,
+    2.000000f, 2.414214f, 2.828427f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 8.242640f, 9.242640f,
+    9.242640f, 8.828427f, 8.414213f, 8.000000f, 8.414213f, 8.828427f, 9.242640f, 9.656854f, 10.071067f, 10.485281f, 10.899494f, 11.313707f, 12.313707f, 13.313707f, 14.313706f, 15.313706f, 16.313705f, 17.313705f, 16.414213f, 16.828426f,
+    33.041626f, 32.627411f, 32.213196f, 31.798985f, 31.384771f, 30.970558f, 30.556345f, 30.142132f, 29.727919f, 29.313705f, 28.899492f, 28.485279f, 28.071066f, 27.656853f, 27.242640f, 26.828426f, 26.414213f, 26.000000f, 26.414213f, 26.828426f,
+    27.242640f, 27.656853f, 28.071066f, 28.485279f, 28.899492f, 29.313705f, 29.727919f, 30.142132f, 30.556345f, 31.556345f, 1.000000f, 34.384773f, 35.142136f, 9.242640f, 8.242640f, 7.242640f, 6.242640f, 5.242640f, 4.242640f, 3.828427f,
+    3.414214f, 3.000000f, 3.414214f, 3.828427f, 4.242640f, 5.242640f, 6.242640f, 7.242640f, 5.828427f, 4.828427f, 3.828427f, 2.828427f, 2.414214f, 2.000000f, 2.414214f, 2.828427f, 3.828427f, 1.000000f, 0.000000f, 1.000000f,
+    3.000000f, 3.414214f, 3.828427f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f, 4.414214f, 4.000000f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 7.656854f, 8.656854f, 0.000000f,
+    10.242640f, 9.828426f, 9.414213f, 9.000000f, 9.414213f, 9.828426f, 10.242640f, 10.656854f, 11.071067f, 11.485280f, 11.899494f, 12.313707f, 12.727921f, 13.727921f, 14.727921f, 15.727920f, 16.727921f, 17.727919f, 17.414213f, 17.828426f,
+    34.041626f, 33.627411f, 33.213196f, 32.798985f, 32.384773f, 31.970558f, 31.556345f, 31.142132f, 30.727919f, 30.313705f, 29.899492f, 29.485279f, 29.071066f, 28.656853f, 28.242640f, 27.828426f, 27.414213f, 27.000000f, 27.414213f, 27.828426f,
+    28.242640f, 28.656853f, 29.071066f, 29.485279f, 29.899492f, 30.313705f, 30.727919f, 31.142132f, 31.556345f, 31.970558f, 32.970558f, 33.970558f, 10.656854f, 9.656854f, 8.656854f, 7.656854f, 6.656854f, 5.656854f, 5.242640f, 4.828427f,
+    4.414214f, 1.414214f, 4.414214f, 4.828427f, 5.242640f, 5.656854f, 6.656854f, 5.828427f, 4.828427f, 3.828427f, 4.242640f, 3.828427f, 3.414214f, 3.000000f, 3.414214f, 3.828427f, 2.414214f, 1.414214f, 1.000000f, 1.414214f,
+    5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 5.828427f, 5.414214f, 5.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 8.071068f, 12.656854f, 11.656854f,
+    11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f, 11.242640f, 11.656854f, 12.071067f, 12.485280f, 12.899493f, 13.313707f, 13.727921f, 14.142134f, 15.142134f, 16.142134f, 17.142134f, 18.142134f, 18.414213f, 18.828426f,
+    35.041626f, 34.627411f, 34.213196f, 33.798985f, 33.384773f, 32.970558f, 32.556343f, 32.142132f, 31.727919f, 31.313705f, 30.899492f, 30.485279f, 30.071066f, 29.656853f, 29.242640f, 28.828426f, 28.414213f, 28.000000f, 28.414213f, 28.828426f,
+    29.242640f, 29.656853f, 30.071066f, 30.485279f, 30.899492f, 31.313705f, 31.727919f, 32.142132f, 32.556343f, 32.970558f, 33.384773f, 34.384773f, 11.071067f, 10.071067f, 9.071068f, 8.071068f, 7.071068f, 6.656854f, 6.242640f, 5.828427f,
+    0.000000f, 1.000000f, 5.414214f, 5.828427f, 6.242640f, 6.656854f, 7.071068f, 5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 7.000000f, 6.000000f,
+    5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 6.000000f, 7.000000f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 12.656853f,
+    12.242640f, 11.828426f, 11.414213f, 11.000000f, 11.414213f, 11.828426f, 12.242640f, 12.656853f, 13.071067f, 13.485280f, 13.899493f, 14.313706f, 14.727921f, 15.142134f, 15.556347f, 16.556347f, 17.556347f, 18.556347f, 1.414214f, 1.000000f,
+    36.041626f, 35.627411f, 35.213196f, 34.798985f, 34.384773f, 33.970558f, 33.556343f, 33.142132f, 32.727921f, 32.313705f, 31.899492f, 31.485279f, 31.071066f, 30.656853f, 30.242640f, 29.828426f, 29.414213f, 29.000000f, 29.414213f, 29.828426f,
+    30.242640f, 30.656853f, 31.071066f, 31.485279f, 31.899492f, 32.313705f, 32.727921f, 33.142132f, 33.556343f, 33.970558f, 34.384773f, 34.798988f, 11.485280f, 10.485281f, 9.485281f, 8.485281f, 8.071068f, 7.656854f, 7.242640f, 6.828427f,
+    1.000000f, 1.414214f, 6.414214f, 6.828427f, 7.242640f, 7.656854f, 6.000000f, 5.000000f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f, 4.000000f, 5.000000f, 7.414214f, 6.414214f,
+    5.414214f, 4.414214f, 3.414214f, 2.414214f, 1.414214f, 1.000000f, 1.414214f, 2.414214f, 3.414214f, 4.414214f, 5.414214f, 6.414214f, 4.000000f, 3.000000f, 2.000000f, 1.000000f, 0.000000f, 1.000000f, 2.000000f, 3.000000f,
+    4.000000f, 12.828426f, 12.414213f, 12.000000f, 12.414213f, 12.828426f, 13.242640f, 13.656853f, 14.071066f, 14.485280f, 14.899493f, 15.313706f, 15.727920f, 16.142134f, 16.556347f, 16.970560f, 17.970560f, 18.970560f, 1.000000f, 0.000000f,
+};
+
+static unsigned int eccTrafo_centers[196] = {
+    0, 0, 8, 5, 35, 20, 53, 22, 67, 2, 64, 0, 70, 1, 74, 1, 79, 3, 92, 10,
+    14, 11, 23, 16, 77, 10, 80, 10, 7, 11, 7, 15, 86, 24, 1, 14, 1, 19, 14, 25,
+    98, 21, 3, 22, 10, 35, 36, 29, 39, 29, 73, 33, 34, 35, 43, 33, 24, 42, 24, 32,
+    95, 36, 88, 39, 40, 36, 69, 38, 76, 36, 84, 36, 91, 34, 92, 47, 70, 36, 36, 41,
+    53, 40, 44, 47, 73, 55, 4, 57, 72, 42, 7, 43, 34, 43, 36, 44, 10, 52, 53, 49,
+    76, 48, 56, 50, 81, 52, 17, 70, 43, 51, 64, 56, 3, 58, 52, 77, 0, 60, 71, 64,
+    97, 79, 95, 63, 92, 67, 77, 64, 83, 72, 39, 65, 62, 67, 76, 73, 89, 75, 56, 74,
+    1, 76, 83, 87, 24, 79, 94, 78, 72, 84, 20, 81, 31, 86, 49, 85, 50, 84, 53, 87,
+    19, 85, 41, 93, 66, 86, 71, 92, 24, 89, 61, 89, 36, 89, 48, 89, 53, 94, 60, 93,
+    30, 95, 58, 96, 79, 96, 40, 98, 52, 99, 65, 98, 76, 99, 99, 99
+};
+
+static unsigned int eccTrafo_volume[64000] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6,
+    2, 2, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6,
+    6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6,
+    6, 6, 6, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 1, 1, 1, 9, 9, 1, 1, 1, 1, 6, 6, 6, 6, 6,
+    6, 6, 6, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 1, 1, 1, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 10, 10, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 10, 10, 10, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 5, 5, 5, 5,
+    12, 12, 12, 12, 7, 7, 13, 13, 13, 13, 13, 9, 9, 9, 11, 11, 6, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 5, 5, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 9, 9, 11, 11, 6, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 11, 11, 11, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 11, 11, 11, 6, 6, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 16, 16,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 16, 16, 16, 16,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 13, 13, 13, 13,
+    8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 13, 13, 13, 13,
+    13, 13, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 16, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 13, 13, 13, 13,
+    13, 13, 13, 17, 17, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 13, 13, 13, 13, 13, 13, 15, 15, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 20, 20, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 16, 16,
+    18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 16,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 16, 16, 16, 16, 20, 20, 20, 20, 20, 20,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 22, 18, 18, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 23,
+    23, 23, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 23,
+    23, 25, 25, 25, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 13, 13, 13, 13, 13, 13, 13, 23, 23,
+    23, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 24, 24, 24, 27,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 13, 23, 23,
+    29, 29, 29, 29, 29, 29, 29, 26, 26, 26, 26, 21, 21, 21, 21, 21, 24, 24, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 23, 29,
+    29, 29, 29, 29, 29, 29, 29, 29, 29, 26, 26, 21, 21, 21, 24, 24, 24, 24, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 23, 29,
+    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 21, 21, 21, 24, 24, 24, 24, 24, 24,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6,
+    6, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 1, 1, 9, 9, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6,
+    6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 1, 1, 1, 1, 6, 6, 6, 6, 6,
+    6, 6, 6, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 1, 1, 1, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 10, 10, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 10, 10, 10, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 10, 10, 10, 5, 5, 5, 14,
+    12, 12, 12, 7, 7, 7, 7, 13, 13, 13, 9, 9, 9, 9, 11, 11, 6, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 9, 9, 9, 11, 11, 6, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 9, 11, 11, 11, 6, 6, 6,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 11, 11, 11, 11, 6, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 16, 16,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 16, 16, 16, 16,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 13, 13, 13, 13,
+    8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 13, 13, 13, 13,
+    13, 17, 17, 17, 17, 8, 8, 17, 10, 10, 10, 10, 10, 10, 16, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 13, 13, 13, 13,
+    13, 13, 17, 17, 17, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 13, 13, 13, 13,
+    13, 13, 13, 17, 17, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 13, 13, 13, 13, 13, 13, 15, 15, 15, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 13, 13, 13, 13, 13, 15, 15, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 16,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 20,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 13, 13, 13, 13, 13, 13, 13, 13, 13, 23,
+    23, 23, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 18, 18, 22, 22, 22, 22, 22, 22, 22, 28, 13, 13, 13, 13, 13, 13, 13, 23,
+    23, 25, 25, 25, 26, 26, 26, 26, 13, 13, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 23, 23, 23, 23,
+    23, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 24, 24, 24, 27,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 23, 23, 23,
+    29, 29, 29, 29, 29, 29, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 24, 24, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 23, 23, 23,
+    29, 29, 29, 29, 29, 29, 29, 29, 29, 26, 26, 21, 21, 21, 21, 24, 24, 24, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 23, 23, 29,
+    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 21, 21, 21, 24, 24, 24, 24, 24, 24,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 30, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 30, 30, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6,
+    6, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 30, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 1, 1, 1, 1, 6, 6, 6, 6, 6,
+    6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 30, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 10, 10, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 10, 10, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 10, 10, 5, 5, 5, 14,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 11, 6, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 9, 9, 9, 9, 11, 11, 11, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 9, 9, 9, 11, 11, 11, 6, 6, 6,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 15,
+    8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    31, 17, 17, 17, 17, 17, 8, 17, 10, 10, 10, 10, 10, 10, 16, 16, 16, 16, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    17, 17, 17, 17, 17, 17, 17, 17, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 13, 13, 13, 13,
+    13, 17, 17, 17, 17, 17, 17, 17, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 13, 15, 15, 15, 15, 15, 15, 13, 13, 13, 13,
+    13, 17, 17, 17, 17, 17, 17, 17, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 13, 13, 13, 13,
+    13, 13, 17, 17, 17, 17, 20, 20, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13,
+    13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 16, 20, 20, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 20, 20, 20, 20, 16, 16,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 20, 20, 20, 20, 20, 16,
+    18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 23, 23, 23, 23,
+    23, 23, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 18, 18, 18, 18, 18, 18, 22, 22, 22, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 26, 26, 26, 26, 13, 13, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 18, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 24, 24, 24,
+    18, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 23, 23, 23,
+    25, 25, 29, 29, 26, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 24, 24, 24, 24,
+    18, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 23, 23, 23,
+    29, 29, 29, 29, 29, 29, 29, 29, 26, 26, 26, 21, 21, 21, 21, 21, 24, 24, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 23, 23,
+    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 21, 21, 21, 21, 24, 24, 24, 24, 24,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 30, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 6, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 1, 1, 1, 1, 1, 6, 6, 6, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 1, 1, 6, 6, 6, 6, 6,
+    6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 30, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 10, 10, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 10, 10, 5, 5, 5, 14,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 10, 10, 10, 14, 14, 14,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 11, 6, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 10, 10, 10, 32, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 32, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 6, 6,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 32, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 32, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 15, 11, 11, 11, 11, 11, 8,
+    31, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 15,
+    31, 31, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 15, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 15, 31,
+    31, 17, 17, 17, 17, 17, 17, 17, 10, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 31,
+    17, 17, 17, 17, 17, 17, 17, 17, 10, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 15, 15, 15, 15, 15, 31,
+    17, 17, 17, 17, 17, 17, 17, 17, 10, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 15, 15, 15,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 16, 16, 16, 16, 16, 20, 20, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13,
+    13, 17, 17, 17, 17, 17, 17, 17, 17, 20, 16, 16, 16, 16, 20, 20, 20, 20, 16, 16,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13,
+    13, 13, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13,
+    13, 13, 23, 25, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 19, 13, 13, 13, 13, 13,
+    13, 13, 23, 25, 25, 25, 25, 25, 25, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13,
+    13, 13, 23, 25, 25, 25, 25, 25, 25, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 13, 13, 13, 13, 13, 13,
+    13, 13, 23, 25, 25, 25, 25, 25, 25, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 23, 23, 23, 23, 23, 23,
+    23, 23, 23, 25, 25, 25, 25, 25, 25, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 23, 23, 23, 23,
+    23, 23, 25, 25, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21, 21, 21, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 23, 25, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21, 21, 21, 21, 24,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 22, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 26, 26, 26, 26, 13, 13, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 18, 18, 18, 18, 18, 22, 22, 22, 22, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 18, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 23, 23, 23,
+    25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 24, 24, 24,
+    18, 18, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 23, 23,
+    25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 24, 24, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 23, 23,
+    25, 29, 29, 29, 29, 29, 29, 29, 29, 26, 26, 21, 21, 21, 21, 21, 24, 24, 24, 24,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 30, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 30, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 1, 1, 1, 6, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 30, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 30, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    6, 6, 8, 8, 3, 3, 3, 8, 8, 8, 8, 3, 3, 3, 5, 5, 5, 5, 14, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 11, 6, 6, 6, 6,
+    6, 6, 8, 8, 8, 8, 3, 8, 8, 8, 8, 3, 3, 3, 10, 10, 32, 32, 14, 14,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 10, 32, 32, 32, 32, 14, 14,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 10, 10, 10, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11, 6,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 9, 9, 9, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 11, 11, 11, 11, 11, 31,
+    31, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 32, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 15, 11, 11, 11, 11, 11, 31,
+    31, 31, 31, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 11, 11, 11, 31,
+    31, 31, 31, 17, 17, 17, 17, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 11, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 10, 10, 10, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 15, 31, 31,
+    31, 17, 17, 17, 17, 17, 17, 17, 17, 10, 10, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 15, 15, 15, 33, 31, 31,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 10, 10, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 15, 15, 33, 33, 17,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 10, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 10, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 13, 33, 33, 33,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 16, 16,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 33, 33,
+    33, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 13, 13, 23,
+    23, 23, 17, 17, 17, 17, 17, 17, 17, 17, 26, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 13, 13, 23,
+    23, 23, 23, 17, 17, 17, 26, 26, 26, 26, 26, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 33, 33, 33, 33, 33, 23, 23,
+    23, 23, 23, 25, 25, 26, 26, 26, 26, 26, 26, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 33, 33, 23, 23, 23,
+    23, 23, 23, 25, 25, 26, 26, 26, 26, 26, 26, 21, 21, 21, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 23, 23, 25, 25, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 23, 25, 25, 25, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 24,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 18, 18, 18, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 34, 34, 34, 34, 34, 26, 21, 21, 21, 21, 21, 21, 24, 24, 24,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 23, 23,
+    25, 25, 25, 25, 34, 34, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 24, 24, 24, 24,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 30, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 6, 6, 6, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 30, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 6, 6, 6, 6,
+    6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 30, 30, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 11, 6, 6, 6,
+    6, 6, 8, 8, 3, 3, 3, 3, 8, 8, 3, 3, 3, 4, 32, 32, 32, 32, 14, 14,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 11, 11, 6, 6, 6,
+    6, 8, 8, 8, 8, 8, 8, 3, 8, 8, 3, 3, 3, 32, 32, 32, 32, 32, 14, 14,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11, 6,
+    6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 10, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11, 6,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 12, 9, 9, 9, 9, 9, 15, 11, 11, 11, 11, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 11, 11, 11, 11, 11, 11, 11, 31, 31,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 11, 11, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 32, 32, 14, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 15, 15, 15, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 17, 17, 17, 17, 10, 10, 10, 10, 10, 10, 10, 10, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 11, 31, 31,
+    31, 31, 31, 17, 17, 17, 17, 17, 10, 10, 10, 10, 10, 10, 10, 10, 10, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 17, 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, 14,
+    18, 18, 18, 12, 12, 12, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 15, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 17, 10, 10, 10, 10, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 15, 33, 31, 31, 31,
+    31, 17, 17, 17, 17, 17, 17, 17, 17, 17, 10, 10, 10, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 15, 33, 33, 31, 31,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 10, 10, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 17,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 17,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 16, 16,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 33, 33,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 16,
+    18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 33, 33, 33,
+    33, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 33, 33, 33,
+    23, 23, 17, 17, 17, 17, 17, 17, 17, 17, 26, 26, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 33, 33, 33, 33, 33, 23, 23,
+    23, 23, 23, 25, 25, 26, 26, 26, 26, 26, 26, 26, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 23, 23, 25, 25, 26, 26, 26, 26, 26, 26, 26, 21, 21, 21, 20, 20, 21, 21, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 23, 23, 25, 25, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 23, 23, 23, 25, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21, 24,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 22, 28, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 18, 18, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 28, 23, 23,
+    35, 25, 35, 35, 35, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 24, 24, 24,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 30, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 1, 1, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 1, 1, 2, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 30, 30, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 6, 2, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 30, 30, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6,
+    6, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 30, 30, 30, 30, 37,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6,
+    6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 30, 30, 32, 32, 32, 14, 14,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 11, 6, 6,
+    6, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 38, 32, 32, 32, 32, 32, 14, 14,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 6,
+    6, 8, 8, 8, 8, 8, 8, 3, 3, 3, 3, 38, 32, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11, 6,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 32, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 12, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 32, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 9, 9, 11, 11, 11, 11, 11, 11, 31, 31,
+    31, 31, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 11, 11, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 8, 8, 8, 10, 10, 10, 10, 10, 10, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 17, 17, 8, 10, 10, 10, 10, 10, 10, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 15, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 17, 17, 17, 10, 10, 10, 10, 10, 10, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 31, 31, 31,
+    31, 31, 31, 31, 17, 17, 17, 17, 10, 10, 10, 10, 10, 10, 10, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 31, 31, 31,
+    31, 31, 31, 17, 17, 17, 17, 17, 17, 10, 10, 10, 10, 10, 39, 39, 39, 39, 39, 14,
+    18, 18, 18, 12, 12, 12, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 31, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 17, 40, 10, 39, 39, 39, 39, 39, 39, 39, 39, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 15, 31, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 17, 17, 39, 39, 39, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 17, 17, 39, 39, 39, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 31, 31,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 39, 39, 16, 16, 16, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 31, 17,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 17,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 16, 16, 16,
+    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 33,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 16, 16,
+    18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 33, 33, 33,
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 41, 20, 20, 20, 20, 20, 20, 20, 20, 16,
+    18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 33, 33, 33,
+    23, 17, 17, 17, 17, 17, 17, 17, 41, 41, 41, 26, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 42, 28, 33, 33, 33, 33, 23, 23, 23,
+    23, 23, 25, 25, 17, 17, 17, 41, 41, 41, 41, 26, 20, 20, 20, 21, 21, 21, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 23, 25, 25, 25, 26, 26, 26, 41, 41, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 25, 26, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 25, 26, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 26, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 22, 22, 22, 28, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 35, 35, 34, 34, 34, 34, 43, 21, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    18, 18, 18, 18, 22, 22, 22, 22, 22, 22, 22, 22, 28, 28, 28, 28, 28, 28, 28, 23,
+    35, 35, 35, 35, 35, 35, 34, 34, 34, 43, 43, 21, 21, 21, 21, 21, 21, 21, 24, 24,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+    7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 2, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 1, 1, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 1, 1, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 30, 30, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 1, 2, 2, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 30, 30, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 6, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 30, 30, 32, 37, 37,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 11, 6, 6,
+    6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 38, 38, 38, 32, 32, 14, 37,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11, 6,
+    6, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 38, 38, 38, 38, 32, 32, 32, 14, 14,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11, 6,
+    8, 8, 8, 8, 8, 3, 3, 3, 3, 3, 38, 38, 38, 38, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 45, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11, 6,
+    8, 8, 8, 8, 8, 8, 8, 46, 38, 38, 38, 38, 38, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 45, 45, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 8, 8, 8, 46, 38, 38, 38, 38, 32, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 45, 45, 45, 9, 9, 9, 11, 11, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 31, 8, 46, 46, 38, 10, 32, 32, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 45, 45, 13, 13, 13, 13, 11, 11, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 31, 8, 10, 10, 10, 10, 10, 32, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 45, 45, 13, 13, 13, 13, 15, 15, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 31, 17, 10, 10, 10, 10, 10, 32, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 45, 45, 13, 13, 13, 13, 15, 15, 11, 11, 11, 31, 31, 31,
+    31, 31, 31, 31, 31, 17, 17, 17, 40, 40, 10, 10, 10, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 45, 13, 13, 13, 13, 15, 15, 15, 15, 15, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 17, 17, 17, 40, 40, 10, 10, 10, 32, 32, 32, 32, 32, 14, 14,
+    12, 12, 12, 12, 12, 12, 45, 13, 13, 13, 15, 15, 15, 15, 15, 15, 31, 31, 31, 31,
+    31, 31, 31, 31, 17, 17, 17, 17, 17, 40, 10, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 12, 12, 47, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, 31, 31, 31, 31,
+    31, 31, 31, 17, 17, 17, 17, 17, 17, 40, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 31, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 17, 17, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 31, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 17, 17, 17, 39, 39, 39, 39, 39, 39, 39, 39, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 41, 41, 41, 41, 39, 39, 39, 39, 39, 39, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 41, 41, 41, 41, 39, 39, 39, 39, 39, 16, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 31, 17,
+    17, 17, 17, 41, 41, 17, 41, 41, 41, 41, 41, 41, 39, 20, 20, 20, 20, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 33, 33, 33, 33, 17,
+    17, 17, 17, 41, 41, 41, 41, 41, 41, 41, 41, 41, 20, 20, 20, 20, 20, 20, 16, 16,
+    18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 48, 48, 33, 33, 33, 33, 33, 33, 33,
+    17, 17, 17, 41, 41, 41, 41, 41, 41, 41, 41, 41, 20, 20, 20, 20, 20, 20, 20, 16,
+    18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 48, 48, 33, 33, 33, 33, 33, 33, 33,
+    23, 17, 17, 41, 41, 41, 41, 41, 41, 41, 41, 41, 20, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 28, 28, 33, 33, 23, 23, 23,
+    23, 23, 17, 41, 41, 41, 41, 41, 41, 41, 41, 41, 21, 20, 20, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 28, 28, 28, 28, 23, 23, 23,
+    23, 23, 25, 25, 41, 41, 41, 41, 41, 41, 41, 34, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 28, 28, 28, 28, 28, 23, 23, 23,
+    23, 25, 25, 25, 25, 25, 34, 34, 41, 41, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 25, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 25, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 25, 25, 25, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 23, 23,
+    23, 25, 25, 35, 35, 35, 35, 35, 43, 43, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 28, 28, 49, 23,
+    35, 35, 35, 35, 35, 35, 35, 35, 43, 43, 43, 21, 21, 21, 21, 21, 21, 21, 21, 24,
+    18, 18, 18, 18, 18, 18, 18, 18, 22, 22, 22, 28, 28, 28, 28, 28, 28, 28, 49, 23,
+    35, 35, 35, 35, 35, 35, 35, 35, 43, 43, 43, 43, 21, 21, 21, 21, 21, 21, 24, 50,
+    7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 30, 30, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 9, 9, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 4, 4, 4, 4, 5, 5, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 9, 9, 9, 9, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 30, 30, 30, 30, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 1, 1, 1, 1, 2, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 30, 30, 30, 38, 37, 37,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 51, 51, 2,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 30, 30, 38, 38, 38, 37, 37,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 51, 51,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 38, 38, 38, 38, 38, 38, 37, 37,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11,
+    46, 46, 46, 46, 46, 3, 3, 3, 3, 3, 38, 38, 38, 38, 38, 38, 38, 32, 32, 37,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11,
+    46, 8, 8, 8, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 32, 32, 32, 37,
+    12, 12, 12, 12, 45, 45, 45, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 6,
+    8, 8, 8, 8, 8, 46, 46, 46, 46, 38, 38, 38, 38, 32, 32, 32, 32, 32, 32, 14,
+    12, 12, 12, 12, 45, 45, 45, 45, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11, 31,
+    31, 31, 31, 31, 8, 8, 46, 46, 46, 38, 38, 38, 32, 32, 32, 32, 32, 32, 32, 14,
+    12, 12, 12, 12, 45, 45, 45, 45, 45, 9, 9, 9, 9, 11, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 31, 46, 46, 46, 38, 38, 32, 32, 32, 32, 32, 32, 32, 32, 14,
+    12, 12, 12, 12, 45, 45, 45, 45, 45, 13, 9, 9, 11, 11, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 31, 46, 46, 46, 40, 52, 52, 52, 52, 52, 52, 52, 52, 52, 14,
+    12, 12, 12, 12, 45, 45, 45, 45, 45, 13, 13, 13, 11, 11, 11, 11, 11, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 40, 40, 40, 52, 52, 52, 52, 52, 52, 52, 52, 52, 14,
+    12, 12, 12, 12, 45, 45, 45, 45, 13, 13, 13, 13, 15, 15, 11, 11, 11, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 17, 17, 40, 40, 40, 39, 39, 39, 39, 52, 52, 52, 52, 52,
+    12, 12, 12, 12, 45, 45, 45, 45, 13, 13, 13, 15, 15, 15, 15, 15, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 17, 17, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    12, 12, 12, 12, 45, 45, 45, 47, 13, 13, 15, 15, 15, 15, 15, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 17, 17, 17, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 53, 47, 47, 47, 47, 19, 19, 15, 15, 15, 15, 15, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 17, 17, 17, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 19, 53, 19, 19, 19, 19, 19, 19, 19, 15, 15, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 17, 41, 41, 41, 40, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 19, 53, 19, 19, 19, 19, 19, 19, 19, 19, 48, 33, 31, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 41, 41, 41, 40, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 48, 33, 31, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 41, 41, 41, 41, 39, 39, 39, 39, 39, 39, 39, 39, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 48, 33, 33, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 41, 41, 41, 41, 39, 39, 39, 39, 39, 39, 39, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 19, 48, 48, 48, 48, 48, 48, 48, 33, 33, 33, 31, 31,
+    31, 31, 17, 17, 17, 17, 41, 41, 41, 41, 41, 41, 54, 39, 39, 39, 39, 16, 16, 16,
+    18, 18, 18, 18, 19, 19, 19, 48, 48, 48, 48, 48, 48, 48, 48, 33, 33, 33, 31, 31,
+    31, 31, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 20, 20, 16, 16, 16,
+    18, 18, 18, 18, 18, 18, 48, 48, 48, 48, 48, 48, 48, 48, 33, 33, 33, 33, 33, 31,
+    31, 31, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 20, 20, 20, 20, 20, 16,
+    18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 42, 42, 42, 33, 33, 33, 33, 33, 23,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 20, 20, 20, 20, 20, 20, 20,
+    18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 42, 42, 28, 28, 49, 23, 23, 23,
+    23, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 21, 20, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 42, 28, 28, 49, 49, 23, 23,
+    23, 23, 25, 41, 41, 41, 41, 41, 41, 41, 41, 41, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 28, 28, 28, 49, 49, 23, 23,
+    23, 25, 25, 25, 25, 41, 41, 41, 41, 41, 41, 34, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 28, 28, 28, 28, 49, 49, 23, 23,
+    23, 25, 25, 25, 25, 34, 34, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 49, 49, 49, 23,
+    23, 25, 25, 25, 25, 25, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 49, 49, 49, 23,
+    23, 25, 25, 25, 25, 35, 34, 34, 34, 34, 43, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 49, 49, 49, 23,
+    35, 35, 35, 35, 35, 35, 35, 35, 43, 43, 43, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 49, 49, 49, 35,
+    35, 35, 35, 35, 35, 35, 35, 35, 43, 43, 43, 43, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 49, 49, 49, 35,
+    35, 35, 35, 35, 35, 35, 35, 35, 43, 43, 43, 43, 43, 21, 21, 21, 21, 21, 50, 50,
+    7, 7, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+    7, 7, 7, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 56, 56, 44, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 3, 3, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+    2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 1, 1, 1, 1, 1, 1, 1, 2,
+    2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 1, 1, 1, 1, 1, 1, 1, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 30, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 57, 1, 1, 1, 1, 51, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 30, 30, 30, 30, 58,
+    7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 57, 1, 1, 1, 51, 51, 51,
+    2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 30, 30, 38, 38, 58, 37,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 51, 51, 51, 51,
+    51, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 38, 38, 38, 38, 38, 38, 37, 37,
+    7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 51, 51, 51,
+    51, 46, 46, 46, 46, 3, 3, 3, 3, 3, 38, 38, 38, 38, 38, 38, 38, 38, 37, 37,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 51, 51,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 37,
+    7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 52, 52, 37,
+    12, 12, 45, 45, 45, 45, 45, 45, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 52, 52, 52, 37,
+    12, 12, 12, 45, 45, 45, 45, 45, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11, 11,
+    31, 31, 31, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 52, 52, 52, 52, 52, 52, 52,
+    12, 12, 12, 45, 45, 45, 45, 45, 45, 57, 57, 57, 57, 9, 11, 11, 11, 11, 11, 31,
+    31, 31, 31, 31, 46, 46, 46, 46, 46, 38, 38, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    12, 12, 45, 45, 45, 45, 45, 45, 45, 57, 57, 57, 57, 11, 11, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 31, 46, 46, 46, 46, 40, 40, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    12, 12, 45, 45, 45, 45, 45, 45, 45, 47, 57, 57, 11, 11, 11, 11, 11, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    12, 12, 45, 45, 45, 45, 45, 47, 47, 47, 13, 13, 15, 15, 11, 11, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 39, 39, 39, 39, 52, 52, 52, 52, 52,
+    12, 12, 45, 45, 45, 45, 47, 47, 47, 13, 13, 15, 15, 15, 15, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 17, 17, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 45, 47, 47, 47, 47, 47, 13, 15, 15, 15, 15, 15, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 17, 17, 17, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 53, 47, 47, 47, 47, 48, 48, 19, 15, 15, 15, 15, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 17, 17, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 53, 53, 48, 48, 48, 48, 19, 19, 19, 48, 48, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 41, 41, 41, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 19, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 31, 31, 31, 31, 31,
+    31, 31, 31, 17, 17, 17, 17, 41, 41, 41, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 18, 53, 48, 19, 19, 48, 48, 48, 48, 48, 48, 48, 31, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 41, 41, 41, 41, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 18, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 31, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 17, 41, 41, 41, 41, 39, 54, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 18, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 33, 31, 31, 31,
+    31, 31, 17, 17, 17, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 39, 39, 39, 16,
+    18, 18, 18, 18, 18, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 33, 33, 33, 31, 31,
+    31, 55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 16, 16,
+    18, 18, 18, 18, 18, 18, 48, 48, 42, 42, 42, 48, 48, 48, 48, 33, 33, 33, 33, 55,
+    55, 55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 20, 16, 16,
+    18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 42, 42, 42, 42, 33, 33, 33, 33, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 20, 20, 20, 21,
+    18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 23, 23,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49, 23,
+    23, 23, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 42, 49, 49, 49, 49, 49, 23,
+    23, 25, 25, 25, 41, 41, 41, 41, 41, 41, 41, 41, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 49, 49, 49, 49, 49, 49, 23,
+    23, 25, 25, 25, 25, 34, 34, 41, 41, 41, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 49, 49, 49, 49, 49, 49, 49,
+    23, 25, 25, 25, 25, 25, 34, 34, 34, 34, 34, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 28, 28, 49, 49, 49, 49, 49, 49,
+    60, 35, 35, 35, 35, 35, 34, 34, 34, 34, 43, 43, 21, 21, 21, 21, 21, 21, 21, 21,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 49, 49, 49, 49, 49, 49,
+    60, 35, 35, 35, 35, 35, 35, 35, 43, 43, 43, 43, 21, 21, 21, 21, 21, 21, 21, 50,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 49, 49, 49, 49, 49, 60,
+    60, 35, 35, 35, 35, 35, 35, 35, 43, 43, 43, 43, 43, 21, 21, 21, 21, 21, 21, 50,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 49, 49, 60, 60,
+    35, 35, 35, 35, 35, 35, 35, 35, 43, 43, 43, 43, 43, 43, 21, 21, 21, 50, 50, 50,
+    56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+    7, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    7, 7, 7, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    7, 7, 7, 7, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+    36, 2, 2, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 56, 56, 56, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+    2, 2, 2, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+    2, 2, 2, 2, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 3, 3, 3, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 30,
+    7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 1, 1, 1, 1, 1, 1, 51, 51,
+    2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 30, 30, 30,
+    7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 1, 1, 1, 51, 51, 51,
+    51, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 30, 30, 30, 58, 58,
+    7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 57, 1, 51, 51, 51, 51, 51,
+    51, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 38, 30, 38, 38, 58, 58, 58,
+    7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 57, 51, 51, 51, 51, 51, 51,
+    51, 46, 46, 46, 46, 3, 3, 3, 3, 4, 4, 38, 38, 38, 38, 38, 38, 38, 58, 37,
+    7, 7, 7, 7, 7, 7, 7, 7, 9, 57, 57, 57, 57, 57, 57, 51, 51, 51, 51, 51,
+    51, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 37,
+    7, 7, 7, 7, 7, 7, 7, 57, 57, 57, 57, 57, 57, 57, 57, 57, 51, 51, 51, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 37,
+    61, 7, 7, 7, 7, 7, 45, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 38, 52, 37,
+    61, 61, 45, 45, 45, 45, 45, 45, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 52, 52, 52, 37,
+    12, 12, 12, 45, 45, 45, 45, 45, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 11, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 52, 52, 52, 52, 52,
+    12, 12, 12, 45, 45, 45, 45, 45, 57, 57, 57, 57, 57, 57, 57, 57, 11, 11, 11, 31,
+    31, 31, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 52, 52, 52, 52, 52, 52, 52,
+    12, 12, 12, 45, 45, 45, 45, 45, 47, 57, 57, 57, 57, 57, 57, 11, 11, 11, 31, 31,
+    31, 31, 31, 31, 46, 46, 46, 46, 46, 40, 40, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+    12, 12, 45, 45, 45, 45, 47, 47, 47, 47, 57, 57, 57, 57, 57, 11, 11, 31, 31, 31,
+    31, 31, 31, 31, 31, 46, 46, 40, 40, 40, 40, 40, 52, 52, 52, 52, 52, 52, 52, 52,
+    45, 45, 45, 45, 45, 47, 47, 47, 47, 47, 47, 57, 57, 57, 11, 11, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 52, 52, 52, 52, 52, 52, 52, 52,
+    45, 45, 45, 47, 47, 47, 47, 47, 47, 47, 47, 15, 15, 15, 15, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 47, 47, 47, 47, 47, 47, 48, 15, 15, 15, 15, 62, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 17, 17, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 53, 47, 47, 47, 47, 48, 48, 19, 15, 15, 62, 62, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 17, 17, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 53, 53, 53, 48, 48, 48, 48, 19, 62, 62, 62, 62, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 41, 41, 41, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 53, 53, 53, 48, 48, 48, 48, 48, 48, 62, 62, 62, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 17, 17, 17, 41, 41, 41, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 18, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 31, 31, 31, 31,
+    31, 31, 31, 17, 17, 17, 17, 41, 41, 41, 41, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 18, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 31, 31, 31, 31,
+    31, 31, 17, 17, 17, 17, 41, 41, 41, 41, 41, 54, 54, 54, 54, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 18, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 31, 31, 31,
+    55, 55, 17, 17, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 39, 39, 39, 39,
+    18, 18, 18, 18, 18, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 33, 55, 55, 55,
+    55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54,
+    18, 18, 18, 18, 18, 63, 48, 42, 42, 42, 42, 42, 48, 48, 48, 48, 33, 33, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54,
+    18, 18, 18, 18, 18, 63, 63, 42, 42, 42, 42, 42, 42, 42, 42, 42, 49, 49, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 20, 64,
+    18, 18, 18, 18, 18, 63, 63, 42, 42, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 23,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 21, 21, 64,
+    18, 18, 18, 18, 18, 63, 63, 42, 42, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    23, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 65, 65, 65, 65, 21, 21, 64,
+    18, 18, 18, 18, 18, 63, 63, 63, 42, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    23, 25, 25, 41, 41, 41, 41, 41, 41, 41, 41, 41, 65, 65, 65, 65, 65, 21, 21, 64,
+    18, 18, 18, 18, 18, 63, 63, 18, 42, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    23, 25, 25, 25, 25, 41, 41, 41, 41, 41, 41, 66, 65, 65, 65, 65, 65, 21, 50, 50,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 42, 49, 49, 49, 49, 49, 49, 49,
+    60, 60, 60, 35, 35, 35, 34, 34, 34, 34, 34, 66, 65, 65, 65, 65, 65, 50, 50, 50,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 42, 49, 49, 49, 49, 49, 49, 49,
+    60, 60, 60, 35, 35, 35, 34, 34, 34, 34, 43, 43, 65, 65, 65, 65, 65, 50, 50, 50,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 42, 42, 49, 49, 49, 49, 49, 49, 49, 60,
+    60, 60, 35, 35, 35, 35, 35, 35, 43, 43, 43, 21, 21, 21, 21, 21, 67, 50, 50, 50,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 49, 49, 49, 49, 49, 49, 60, 60,
+    60, 60, 35, 35, 35, 35, 35, 35, 43, 43, 43, 43, 43, 21, 21, 21, 67, 67, 50, 50,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 28, 28, 28, 28, 49, 49, 60, 60,
+    60, 60, 35, 35, 35, 35, 35, 43, 43, 43, 43, 43, 43, 43, 43, 21, 67, 67, 50, 50,
+    56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 36, 4, 4, 5, 5, 5,
+    68, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    68, 68, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+    36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    7, 7, 7, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+    36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
+    7, 7, 7, 7, 56, 56, 56, 56, 56, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+    2, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 58,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 1, 1, 1, 51, 51, 51, 51, 51,
+    51, 2, 2, 3, 3, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 58, 58,
+    7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 1, 1, 1, 51, 51, 51, 51, 51,
+    51, 51, 2, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 30, 30, 58, 58,
+    7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 1, 1, 51, 51, 51, 51, 51,
+    51, 51, 51, 3, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 30, 30, 30, 58, 58, 58,
+    7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 57, 51, 51, 51, 51, 51, 51,
+    51, 51, 46, 46, 46, 3, 3, 4, 4, 4, 4, 4, 38, 38, 38, 38, 38, 58, 58, 58,
+    7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 57, 51, 51, 51, 51, 51, 51,
+    51, 46, 46, 46, 46, 46, 46, 46, 69, 69, 69, 38, 38, 38, 38, 38, 38, 58, 58, 58,
+    7, 7, 7, 7, 7, 7, 7, 44, 44, 57, 57, 57, 57, 57, 57, 51, 51, 51, 51, 51,
+    51, 46, 46, 46, 46, 46, 46, 46, 69, 69, 38, 38, 38, 38, 38, 38, 38, 38, 58, 37,
+    61, 61, 7, 7, 7, 7, 7, 57, 57, 57, 57, 57, 57, 57, 57, 57, 51, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 37,
+    61, 61, 61, 61, 61, 45, 45, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 37,
+    61, 61, 61, 61, 61, 45, 45, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 52, 52, 37,
+    12, 12, 12, 45, 45, 45, 45, 45, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 52, 52, 52, 52, 52,
+    12, 12, 12, 45, 45, 45, 45, 47, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 52, 52, 52, 52, 52, 52,
+    12, 12, 12, 45, 45, 47, 47, 47, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 31, 31,
+    31, 31, 31, 46, 46, 46, 46, 46, 46, 46, 38, 38, 52, 52, 52, 52, 52, 52, 52, 52,
+    12, 12, 45, 45, 47, 47, 47, 47, 57, 57, 57, 57, 57, 57, 57, 57, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 46, 46, 46, 46, 46, 40, 40, 40, 52, 52, 52, 52, 52, 52, 52,
+    47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 57, 57, 57, 57, 57, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 40, 52, 52, 52, 39, 39, 52, 52,
+    47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 62, 62, 62, 62, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 47, 47, 47, 47, 47, 47, 47, 62, 62, 62, 62, 62, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 17, 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 53, 47, 47, 47, 47, 62, 62, 62, 62, 62, 62, 62, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 31, 17, 17, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 53, 53, 53, 48, 48, 62, 62, 62, 62, 62, 62, 62, 62, 31, 31, 31, 31,
+    31, 31, 31, 31, 31, 31, 41, 41, 41, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 53, 53, 53, 48, 48, 48, 62, 62, 62, 62, 62, 62, 62, 31, 31, 31, 31,
+    31, 31, 70, 70, 70, 17, 41, 41, 41, 41, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 18, 53, 48, 48, 48, 48, 48, 62, 62, 62, 62, 62, 31, 31, 31, 31,
+    31, 70, 70, 70, 41, 41, 41, 41, 41, 41, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39,
+    18, 18, 18, 18, 18, 53, 71, 48, 48, 48, 48, 62, 62, 62, 62, 62, 62, 31, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 39, 39, 54, 39,
+    18, 18, 18, 18, 18, 53, 71, 48, 48, 48, 48, 48, 48, 48, 48, 48, 55, 55, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 39, 39, 54, 54,
+    18, 18, 18, 18, 18, 72, 72, 48, 48, 48, 48, 48, 48, 48, 48, 48, 55, 55, 55, 55,
+    55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 39, 39, 54, 54,
+    18, 18, 63, 63, 63, 63, 72, 48, 42, 42, 42, 42, 42, 48, 48, 48, 48, 55, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54,
+    18, 18, 63, 63, 63, 63, 63, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 49, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54,
+    18, 18, 63, 63, 63, 63, 63, 42, 42, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 65, 64,
+    63, 63, 63, 63, 63, 63, 63, 63, 42, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    49, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 42, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    49, 60, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 65, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 73, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    60, 60, 60, 60, 41, 41, 41, 41, 41, 41, 41, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 63, 42, 42, 42, 42, 42, 49, 49, 49, 49, 49, 60,
+    60, 60, 60, 60, 60, 35, 41, 34, 41, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 63, 73, 42, 42, 42, 49, 49, 49, 49, 49, 49, 60,
+    60, 60, 60, 60, 35, 35, 35, 34, 34, 43, 43, 66, 65, 65, 65, 65, 65, 65, 65, 50,
+    18, 18, 63, 63, 63, 63, 74, 74, 73, 73, 42, 42, 49, 49, 49, 49, 49, 49, 60, 60,
+    60, 60, 60, 60, 35, 35, 35, 35, 43, 43, 43, 65, 65, 65, 65, 65, 65, 65, 50, 50,
+    18, 18, 63, 74, 74, 74, 74, 74, 74, 73, 73, 49, 49, 49, 49, 49, 49, 60, 60, 60,
+    60, 60, 60, 60, 35, 35, 35, 35, 43, 43, 43, 43, 43, 65, 65, 65, 65, 65, 50, 50,
+    18, 18, 63, 74, 74, 74, 74, 74, 74, 74, 73, 49, 49, 49, 49, 49, 49, 60, 60, 60,
+    60, 60, 60, 35, 35, 35, 35, 43, 43, 43, 43, 43, 43, 43, 43, 67, 67, 67, 50, 50,
+    68, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 36, 4, 4, 4, 5, 5,
+    68, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
+    68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
+    68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
+    7, 68, 68, 56, 56, 56, 56, 56, 56, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
+    7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 1, 1, 1, 1, 51, 51, 51, 51, 51,
+    51, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 58,
+    7, 7, 7, 7, 7, 7, 7, 7, 44, 44, 44, 44, 1, 1, 1, 51, 51, 51, 51, 51,
+    51, 51, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 58, 58,
+    7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 44, 1, 1, 1, 51, 51, 51, 51, 51,
+    51, 51, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 58, 58, 58, 58, 58,
+    7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 44, 44, 1, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 38, 58, 58, 58, 58, 58,
+    7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 51, 51, 51,
+    51, 51, 46, 46, 46, 46, 46, 4, 4, 4, 69, 69, 69, 38, 38, 38, 58, 58, 58, 58,
+    7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 57, 57, 51, 51, 51, 51, 51, 51,
+    51, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 38, 38, 38, 38, 38, 58, 58, 58,
+    61, 61, 61, 61, 7, 7, 44, 44, 44, 57, 57, 57, 57, 57, 51, 51, 51, 51, 51, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 69, 69, 69, 38, 38, 38, 38, 38, 38, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 38, 58, 58,
+    61, 61, 61, 61, 61, 61, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 37, 37,
+    61, 61, 61, 61, 61, 61, 45, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 52, 52, 37,
+    61, 61, 61, 61, 61, 47, 47, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 52, 52, 52, 52,
+    12, 12, 12, 45, 45, 47, 47, 47, 57, 57, 57, 57, 57, 57, 57, 75, 75, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 52, 52, 52, 52, 52, 52,
+    12, 12, 12, 47, 47, 47, 47, 47, 57, 57, 57, 57, 57, 57, 75, 75, 75, 75, 59, 31,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 52, 52, 52, 52, 52, 52, 52,
+    12, 12, 45, 47, 47, 47, 47, 47, 57, 57, 57, 57, 57, 75, 75, 75, 75, 31, 31, 31,
+    31, 31, 31, 46, 46, 46, 46, 46, 46, 46, 40, 40, 40, 52, 52, 52, 52, 52, 52, 52,
+    47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 57, 75, 75, 75, 75, 31, 31, 31, 31,
+    31, 31, 70, 70, 70, 46, 40, 40, 40, 40, 40, 40, 40, 40, 52, 52, 52, 52, 52, 52,
+    47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 62, 62, 62, 62, 31, 31, 31, 31, 31,
+    31, 70, 70, 70, 70, 70, 40, 40, 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 47, 47, 47, 47, 47, 47, 47, 62, 62, 62, 62, 62, 62, 31, 31, 31, 31,
+    31, 70, 70, 70, 70, 70, 70, 40, 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 76,
+    53, 53, 53, 53, 47, 47, 47, 47, 47, 62, 62, 62, 62, 62, 62, 62, 31, 31, 31, 31,
+    31, 70, 70, 70, 70, 70, 70, 70, 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 53, 53, 53, 48, 48, 62, 62, 62, 62, 62, 62, 62, 62, 31, 31, 31, 31,
+    70, 70, 70, 70, 70, 31, 41, 41, 41, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 53, 53, 53, 53, 48, 62, 62, 62, 62, 62, 62, 62, 62, 62, 31, 31, 31, 31,
+    70, 70, 70, 70, 70, 41, 41, 41, 41, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39,
+    53, 53, 18, 18, 18, 53, 71, 71, 71, 62, 62, 62, 62, 62, 62, 62, 62, 31, 31, 31,
+    70, 70, 70, 70, 41, 41, 41, 41, 41, 41, 40, 40, 40, 39, 39, 39, 54, 54, 54, 39,
+    53, 53, 53, 53, 53, 71, 71, 71, 71, 48, 62, 62, 62, 62, 62, 62, 62, 55, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+    53, 53, 53, 53, 53, 72, 71, 71, 48, 48, 48, 48, 62, 62, 62, 62, 55, 55, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 39, 39, 54, 54,
+    53, 53, 53, 53, 53, 72, 72, 72, 48, 48, 48, 48, 48, 48, 48, 62, 62, 55, 55, 55,
+    55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 39, 39, 54, 54,
+    63, 63, 63, 53, 72, 72, 72, 72, 42, 42, 42, 42, 42, 48, 48, 48, 48, 55, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54,
+    63, 63, 63, 63, 63, 63, 63, 73, 42, 42, 42, 42, 42, 42, 42, 42, 42, 49, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 42, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 73, 73, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    60, 60, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 73, 73, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    60, 60, 60, 60, 41, 41, 41, 41, 41, 41, 41, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 42, 42, 42, 49, 49, 49, 49, 49, 60,
+    60, 60, 60, 60, 60, 60, 41, 41, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 63, 73, 73, 42, 42, 49, 49, 49, 49, 49, 60, 60,
+    60, 60, 60, 60, 60, 60, 35, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 63, 63, 74, 74, 73, 73, 73, 73, 42, 49, 49, 49, 49, 49, 60, 60,
+    60, 60, 60, 60, 60, 35, 35, 43, 43, 43, 43, 66, 65, 65, 65, 65, 65, 65, 65, 50,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 49, 49, 49, 49, 49, 60, 60, 60,
+    60, 60, 60, 60, 60, 35, 35, 43, 43, 43, 43, 43, 43, 65, 65, 65, 65, 65, 65, 50,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 49, 49, 49, 49, 49, 60, 60, 60,
+    60, 60, 60, 60, 60, 35, 35, 43, 43, 43, 43, 43, 43, 43, 65, 65, 65, 65, 50, 50,
+    68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 36, 36, 36, 36, 36, 36, 36, 5, 5,
+    68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 36, 36, 36, 5, 5,
+    68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 36, 36, 36, 5, 5,
+    68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 36, 36, 36, 36, 36,
+    68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 51, 51, 51, 51, 51,
+    51, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 36, 36, 36, 36, 36,
+    68, 68, 68, 56, 56, 56, 56, 56, 44, 44, 44, 44, 1, 1, 1, 51, 51, 51, 51, 51,
+    51, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 58,
+    7, 7, 7, 56, 56, 44, 44, 44, 44, 44, 44, 44, 1, 1, 1, 51, 51, 51, 51, 51,
+    51, 51, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 58, 58, 58,
+    7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 44, 44, 1, 1, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 58, 58, 58, 58, 58,
+    7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 46, 36, 36, 36, 4, 4, 4, 4, 69, 69, 69, 69, 58, 58, 58, 58, 58,
+    7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 51, 51, 51,
+    51, 51, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 38, 58, 58, 58, 58, 58,
+    7, 7, 7, 61, 61, 44, 44, 44, 44, 44, 44, 44, 57, 51, 51, 51, 51, 51, 51, 51,
+    46, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 38, 38, 38, 58, 58, 58, 58,
+    61, 61, 61, 61, 61, 44, 44, 44, 44, 44, 57, 57, 57, 57, 51, 51, 51, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 38, 38, 38, 38, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 44, 44, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 61, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 58, 58,
+    61, 61, 61, 61, 61, 61, 61, 57, 57, 57, 57, 57, 57, 57, 75, 75, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 58, 37,
+    61, 61, 61, 61, 61, 47, 47, 57, 57, 57, 57, 57, 57, 75, 75, 75, 59, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 52, 52,
+    61, 61, 61, 61, 47, 47, 47, 47, 57, 57, 57, 57, 75, 75, 75, 75, 75, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 52, 52,
+    61, 61, 61, 47, 47, 47, 47, 47, 57, 57, 57, 75, 75, 75, 75, 75, 75, 75, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 52, 52, 52, 52, 52, 52,
+    61, 61, 47, 47, 47, 47, 47, 47, 57, 57, 75, 75, 75, 75, 75, 75, 75, 75, 70, 70,
+    70, 70, 46, 46, 46, 46, 46, 46, 46, 46, 40, 40, 40, 40, 52, 52, 52, 52, 52, 52,
+    47, 47, 47, 47, 47, 47, 47, 47, 57, 75, 75, 75, 75, 75, 75, 75, 75, 70, 70, 70,
+    70, 70, 70, 70, 46, 46, 40, 40, 40, 40, 40, 40, 40, 40, 52, 52, 52, 52, 52, 76,
+    47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 75, 75, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 39, 39, 39, 76, 76,
+    53, 53, 47, 47, 47, 47, 47, 47, 47, 47, 62, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 40, 40, 40, 40, 40, 40, 40, 40, 40, 39, 39, 39, 76, 76,
+    53, 53, 53, 53, 47, 47, 47, 47, 71, 71, 62, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 70, 40, 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 76, 76,
+    53, 53, 53, 53, 53, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 70, 31, 31, 31,
+    70, 70, 70, 70, 70, 70, 70, 41, 40, 40, 40, 40, 40, 40, 39, 54, 39, 39, 39, 76,
+    53, 53, 53, 53, 53, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 70, 31, 31, 31,
+    70, 70, 70, 70, 70, 41, 41, 41, 41, 40, 40, 40, 40, 40, 39, 54, 54, 54, 54, 77,
+    53, 53, 53, 53, 53, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 62, 62, 31, 31, 31,
+    70, 70, 70, 70, 41, 41, 41, 41, 41, 41, 40, 40, 40, 39, 39, 54, 54, 54, 54, 77,
+    53, 53, 53, 53, 53, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 62, 62, 55, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54, 54, 77,
+    53, 53, 53, 53, 53, 72, 72, 71, 71, 62, 62, 62, 62, 62, 62, 62, 55, 55, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54, 77,
+    63, 63, 63, 53, 72, 72, 72, 72, 72, 48, 48, 62, 62, 62, 62, 62, 62, 55, 55, 55,
+    55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 39, 54, 54, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 42, 42, 42, 42, 42, 62, 62, 62, 55, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 65, 54, 54, 54, 54, 54,
+    63, 63, 63, 63, 63, 63, 72, 72, 73, 73, 42, 42, 42, 42, 42, 42, 42, 49, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 65, 54, 54, 54, 54, 54,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 42, 42, 42, 42, 42, 42, 42, 49, 49, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 42, 42, 42, 42, 42, 42, 49, 49, 49, 49,
+    60, 60, 41, 41, 41, 41, 41, 41, 41, 41, 41, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 42, 42, 42, 42, 49, 49, 49, 60,
+    60, 60, 60, 60, 41, 41, 41, 41, 41, 41, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 42, 42, 49, 49, 49, 49, 60, 60,
+    60, 60, 60, 60, 60, 60, 41, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    74, 63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 42, 49, 49, 49, 49, 60, 60,
+    60, 60, 60, 60, 60, 60, 60, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 49, 49, 49, 49, 60, 60, 60,
+    60, 60, 60, 60, 60, 60, 60, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 49, 49, 49, 49, 60, 60, 60,
+    60, 60, 60, 60, 60, 60, 60, 43, 43, 43, 43, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 78, 78, 78, 78, 78, 60, 60, 60,
+    60, 60, 60, 60, 60, 60, 35, 43, 43, 43, 43, 43, 66, 65, 65, 65, 65, 65, 65, 65,
+    68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 79, 1, 1, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 5, 5,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 36, 36, 36, 36, 36, 36, 5,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 36, 36, 36, 36, 5,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 51,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 51, 51, 51, 51, 51,
+    51, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 80, 1, 1, 51, 51, 51, 51, 51,
+    51, 51, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 4, 58, 58,
+    68, 68, 68, 68, 56, 56, 56, 56, 44, 44, 44, 44, 44, 1, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 58, 58, 58, 58, 58,
+    7, 7, 68, 68, 68, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 51, 36, 36, 36, 36, 36, 36, 4, 4, 69, 69, 58, 58, 58, 58, 58, 58,
+    7, 7, 61, 68, 44, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 46, 46, 46, 36, 69, 69, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58,
+    7, 7, 61, 61, 44, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 51, 51, 51,
+    51, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58,
+    7, 7, 61, 61, 44, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 51, 51, 51,
+    51, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58,
+    61, 61, 61, 61, 61, 44, 44, 44, 44, 44, 44, 57, 57, 57, 51, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 38, 38, 58, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 44, 44, 44, 44, 57, 57, 57, 75, 59, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 61, 57, 57, 57, 57, 57, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 58, 58,
+    61, 61, 61, 61, 61, 61, 61, 57, 57, 57, 57, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 38, 58, 58,
+    61, 61, 61, 61, 61, 61, 47, 57, 57, 57, 75, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 52, 52,
+    61, 61, 61, 61, 61, 47, 47, 47, 57, 75, 75, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 38, 38, 38, 38, 38, 52, 52,
+    61, 61, 61, 47, 47, 47, 47, 47, 75, 75, 75, 75, 75, 75, 75, 75, 75, 59, 59, 59,
+    46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 38, 38, 52, 52, 52, 52, 52, 81,
+    61, 61, 47, 47, 47, 47, 47, 47, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 70, 70,
+    70, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 40, 40, 40, 52, 52, 52, 52, 81, 81,
+    61, 47, 47, 47, 47, 47, 47, 47, 75, 75, 75, 75, 75, 75, 75, 75, 75, 70, 70, 70,
+    70, 70, 70, 82, 82, 82, 40, 40, 40, 40, 40, 40, 40, 40, 40, 52, 52, 81, 81, 81,
+    47, 47, 47, 47, 47, 47, 47, 47, 75, 75, 83, 75, 75, 75, 75, 75, 70, 70, 70, 70,
+    70, 70, 70, 70, 82, 82, 40, 40, 40, 40, 40, 40, 40, 40, 40, 39, 39, 76, 76, 76,
+    47, 47, 47, 47, 47, 47, 83, 83, 83, 83, 62, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 39, 39, 76, 76, 76,
+    53, 53, 53, 53, 47, 83, 83, 83, 71, 71, 62, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 40, 40, 40, 40, 40, 40, 40, 40, 40, 54, 39, 76, 76, 76,
+    53, 53, 53, 53, 53, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 70, 40, 40, 40, 40, 40, 40, 40, 54, 54, 54, 76, 76, 76,
+    53, 53, 53, 53, 53, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 70, 41, 40, 40, 40, 40, 40, 40, 54, 54, 54, 54, 77, 77,
+    53, 53, 53, 53, 53, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 41, 41, 41, 41, 41, 40, 40, 40, 40, 40, 54, 54, 54, 54, 77, 77,
+    63, 63, 63, 53, 53, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 55, 55, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54, 54, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 71, 71, 62, 62, 62, 62, 62, 62, 62, 55, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54, 54, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 62, 62, 62, 62, 62, 62, 62, 55, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 54, 65, 54, 54, 54, 54, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 73, 42, 62, 62, 62, 62, 62, 62, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 65, 65, 54, 54, 54, 54, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 73, 73, 42, 42, 42, 42, 42, 42, 42, 55, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 65, 65, 65, 54, 54, 54, 54,
+    63, 63, 63, 63, 63, 63, 72, 72, 73, 73, 73, 73, 42, 42, 42, 42, 42, 49, 49, 55,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 42, 42, 42, 42, 42, 49, 49, 49,
+    55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 42, 42, 42, 49, 49, 49, 60,
+    60, 60, 41, 41, 41, 41, 41, 41, 41, 41, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 42, 42, 42, 49, 49, 60, 60,
+    60, 60, 60, 60, 41, 41, 41, 41, 41, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 42, 49, 49, 49, 60, 60,
+    60, 60, 60, 60, 60, 60, 41, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 49, 49, 49, 60, 60, 60,
+    60, 60, 60, 60, 60, 60, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 73, 49, 49, 49, 60, 60, 60,
+    60, 60, 60, 60, 60, 60, 60, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 49, 49, 60, 60, 60, 60,
+    60, 60, 60, 60, 60, 60, 60, 60, 43, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 78, 78, 78, 78, 78, 60, 60, 60,
+    60, 60, 60, 60, 60, 60, 60, 43, 43, 43, 43, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 1, 1, 1, 79, 79, 79, 79, 79,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 5,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 1, 80, 1, 1, 79, 79, 79, 79,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 5,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 80, 1, 1, 1, 1, 1, 79,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 5,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 80, 1, 1, 1, 51, 51, 51,
+    51, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 56, 80, 80, 51, 51, 51, 51, 51,
+    51, 51, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 36, 36, 36, 36, 36, 84,
+    68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 80, 80, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 4, 4, 58, 58,
+    68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 44, 44, 80, 51, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 51, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 58, 58, 58, 58, 58, 58,
+    68, 68, 68, 68, 68, 44, 44, 44, 44, 44, 44, 44, 80, 51, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 51, 46, 36, 36, 36, 36, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58, 58,
+    7, 61, 68, 68, 68, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58,
+    7, 61, 61, 68, 44, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 51, 51, 51,
+    51, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58,
+    7, 61, 61, 61, 44, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 51, 51, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58,
+    61, 61, 61, 61, 61, 44, 44, 44, 44, 44, 44, 75, 75, 75, 59, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 38, 58, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 44, 44, 44, 44, 75, 75, 75, 75, 59, 59, 59, 59, 59, 59,
+    59, 59, 46, 46, 46, 46, 46, 46, 46, 69, 69, 46, 38, 38, 38, 38, 58, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 61, 57, 57, 75, 75, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 59, 46, 46, 46, 46, 46, 46, 46, 69, 69, 38, 38, 38, 38, 38, 38, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 61, 57, 75, 75, 75, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 69, 69, 38, 38, 38, 38, 38, 38, 38, 58, 58,
+    61, 61, 61, 61, 61, 61, 47, 75, 75, 75, 75, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 69, 69, 38, 38, 38, 38, 38, 38, 38, 52, 52,
+    61, 61, 61, 61, 61, 47, 47, 47, 75, 75, 75, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 46, 46, 46, 46, 46, 46, 46, 46, 46, 69, 69, 38, 38, 38, 38, 38, 38, 52, 81,
+    61, 61, 61, 61, 47, 47, 47, 47, 75, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    85, 82, 82, 82, 82, 82, 82, 82, 82, 82, 40, 40, 40, 40, 52, 52, 52, 81, 81, 81,
+    61, 61, 61, 47, 47, 47, 47, 83, 75, 75, 75, 75, 75, 75, 75, 75, 75, 85, 85, 85,
+    82, 82, 82, 82, 82, 82, 82, 82, 46, 46, 40, 40, 40, 40, 40, 52, 52, 81, 81, 81,
+    61, 47, 47, 47, 47, 47, 83, 83, 75, 75, 75, 75, 75, 75, 75, 75, 75, 85, 70, 70,
+    70, 70, 82, 82, 82, 82, 82, 86, 86, 86, 40, 40, 40, 40, 40, 52, 81, 81, 81, 81,
+    87, 87, 47, 47, 47, 83, 83, 83, 83, 83, 83, 75, 75, 75, 75, 75, 75, 70, 70, 70,
+    70, 70, 70, 82, 82, 82, 86, 86, 86, 86, 40, 40, 40, 40, 40, 40, 76, 76, 76, 76,
+    87, 87, 83, 83, 83, 83, 83, 83, 83, 83, 83, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 86, 86, 86, 86, 86, 40, 40, 40, 40, 40, 40, 76, 76, 76, 76,
+    53, 53, 53, 83, 83, 83, 83, 83, 83, 71, 71, 62, 62, 62, 88, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 86, 86, 86, 86, 40, 40, 40, 40, 40, 54, 76, 76, 76, 76,
+    53, 53, 53, 53, 83, 83, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 70, 86, 86, 86, 40, 40, 40, 40, 54, 54, 76, 76, 76, 76,
+    53, 53, 53, 53, 71, 71, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 70, 41, 86, 86, 40, 40, 40, 54, 54, 54, 77, 77, 77, 77,
+    63, 63, 63, 53, 71, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 70, 70, 70, 70,
+    70, 55, 55, 55, 41, 41, 41, 41, 41, 86, 40, 40, 40, 54, 54, 54, 54, 77, 77, 77,
+    63, 63, 63, 53, 72, 72, 72, 72, 71, 71, 62, 62, 62, 62, 62, 62, 62, 55, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 71, 71, 62, 62, 62, 62, 62, 62, 55, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 54, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 62, 62, 62, 62, 62, 62, 55, 55, 55,
+    55, 55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 54, 65, 65, 54, 54, 54, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 62, 62, 62, 62, 62, 62, 55, 55,
+    55, 55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 66, 65, 65, 54, 54, 54, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 73, 73, 42, 42, 42, 42, 42, 89, 89, 55,
+    55, 55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 54, 66, 65, 65, 65, 54, 54, 54, 77,
+    63, 63, 63, 63, 63, 63, 72, 72, 73, 73, 73, 73, 73, 42, 42, 42, 42, 89, 89, 89,
+    55, 55, 41, 41, 41, 41, 41, 41, 41, 41, 41, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 42, 42, 42, 49, 49, 60,
+    60, 55, 41, 41, 41, 41, 41, 41, 41, 41, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 42, 42, 49, 49, 60, 60,
+    60, 60, 41, 41, 41, 41, 41, 41, 41, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 42, 42, 49, 49, 60, 60,
+    60, 60, 60, 60, 41, 41, 41, 41, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 42, 49, 49, 60, 60, 60,
+    60, 60, 60, 60, 90, 90, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 63, 63, 73, 73, 73, 73, 73, 73, 73, 49, 49, 60, 60, 60,
+    60, 60, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 73, 73, 49, 60, 60, 60, 60,
+    60, 60, 60, 90, 90, 90, 90, 90, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 49, 60, 60, 60, 60, 60,
+    60, 60, 60, 60, 90, 90, 90, 90, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 78, 78, 78, 78, 78, 60, 60, 60,
+    60, 60, 60, 60, 90, 90, 90, 90, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 80, 79, 79, 79, 79, 79, 79, 79,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 80, 80, 79, 79, 79, 79, 79, 79,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, 80, 80, 80, 79, 79, 79, 79, 79,
+    79, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 80, 80, 80, 80, 79, 79, 79, 79,
+    79, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 5,
+    68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 80, 80, 80, 80, 51, 51, 51, 51,
+    51, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84,
+    68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 80, 80, 80, 80, 80, 51, 51, 51, 51,
+    51, 51, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 4, 4, 4, 4, 4, 58, 58, 84,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 80, 80, 80, 80, 51, 51, 51, 51, 51,
+    51, 51, 91, 91, 91, 36, 36, 36, 36, 36, 36, 92, 92, 92, 58, 58, 58, 58, 58, 58,
+    68, 68, 68, 68, 68, 68, 56, 56, 44, 44, 44, 44, 80, 80, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 91, 91, 91, 36, 36, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58, 58,
+    68, 68, 68, 68, 68, 68, 44, 44, 44, 44, 44, 44, 80, 51, 51, 51, 51, 51, 51, 51,
+    51, 51, 51, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58, 58,
+    68, 68, 68, 68, 68, 68, 44, 44, 44, 44, 44, 44, 80, 51, 51, 51, 51, 51, 51, 59,
+    59, 51, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58, 58,
+    61, 61, 61, 93, 93, 44, 44, 44, 44, 44, 44, 44, 44, 51, 51, 59, 59, 59, 59, 59,
+    59, 94, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 58, 58, 58, 58, 58,
+    61, 61, 61, 61, 93, 93, 44, 44, 44, 44, 95, 75, 75, 59, 59, 59, 59, 59, 59, 59,
+    59, 59, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 96, 58, 58, 58, 58,
+    61, 61, 61, 61, 61, 93, 93, 44, 95, 95, 95, 75, 75, 75, 59, 59, 59, 59, 59, 59,
+    59, 59, 94, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 96, 96, 58, 58, 58,
+    61, 61, 61, 61, 61, 93, 93, 95, 95, 75, 75, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 94, 46, 46, 46, 46, 46, 46, 69, 69, 69, 38, 38, 38, 38, 38, 96, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 93, 75, 75, 75, 75, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 94, 46, 46, 46, 46, 46, 46, 69, 69, 69, 38, 38, 38, 38, 38, 38, 58, 58, 58,
+    61, 61, 61, 61, 61, 61, 61, 75, 75, 75, 75, 75, 75, 75, 75, 59, 59, 59, 59, 59,
+    59, 94, 82, 82, 82, 82, 82, 82, 82, 69, 69, 38, 38, 38, 38, 38, 38, 38, 52, 81,
+    61, 61, 61, 61, 61, 61, 47, 97, 75, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    85, 82, 82, 82, 82, 82, 82, 82, 82, 82, 69, 69, 69, 38, 38, 38, 38, 81, 81, 81,
+    61, 61, 61, 61, 47, 83, 83, 83, 97, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    85, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 86, 52, 98, 98, 81, 81, 81,
+    61, 61, 61, 47, 83, 83, 83, 83, 97, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    82, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 86, 40, 98, 98, 81, 81, 81,
+    87, 87, 47, 47, 83, 83, 83, 83, 83, 83, 75, 75, 75, 75, 75, 75, 75, 85, 85, 85,
+    70, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 86, 40, 98, 81, 81, 81, 81,
+    87, 87, 87, 47, 83, 83, 83, 83, 83, 83, 83, 97, 75, 75, 75, 75, 75, 85, 70, 70,
+    70, 70, 82, 82, 82, 82, 86, 86, 86, 86, 86, 86, 86, 86, 40, 98, 81, 81, 81, 81,
+    87, 87, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 97, 75, 75, 88, 88, 70, 70, 70,
+    70, 70, 70, 70, 82, 86, 86, 86, 86, 86, 86, 86, 86, 86, 40, 99, 81, 81, 81, 81,
+    53, 87, 83, 83, 83, 83, 83, 83, 83, 83, 71, 62, 62, 62, 88, 88, 88, 70, 70, 70,
+    70, 70, 70, 70, 70, 86, 86, 86, 86, 86, 86, 86, 86, 86, 40, 99, 81, 81, 81, 81,
+    53, 53, 53, 83, 83, 83, 83, 83, 71, 71, 71, 62, 62, 62, 88, 62, 62, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 86, 86, 86, 86, 86, 86, 86, 86, 54, 76, 76, 76, 76, 76,
+    53, 53, 53, 53, 83, 71, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 70, 86, 86, 86, 86, 86, 86, 54, 54, 77, 77, 77, 77, 77,
+    63, 63, 63, 53, 71, 71, 71, 71, 71, 71, 71, 62, 62, 62, 62, 62, 62, 70, 70, 70,
+    70, 55, 55, 55, 55, 55, 41, 41, 86, 86, 86, 86, 86, 54, 54, 54, 77, 77, 77, 77,
+    63, 63, 63, 53, 72, 72, 72, 72, 71, 71, 71, 62, 62, 62, 62, 62, 62, 55, 55, 55,
+    55, 55, 55, 55, 55, 55, 41, 41, 41, 86, 86, 54, 54, 54, 54, 54, 77, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 71, 62, 62, 62, 62, 62, 62, 62, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 54, 54, 54, 54, 54, 54, 54, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 62, 62, 62, 62, 62, 62, 55, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 66, 66, 65, 65, 54, 54, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 62, 62, 62, 62, 62, 89, 89, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 66, 66, 65, 65, 54, 54, 54, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 73, 73, 42, 42, 62, 89, 89, 89, 55,
+    55, 55, 55, 55, 41, 41, 41, 41, 41, 41, 66, 66, 66, 65, 65, 65, 54, 54, 77, 77,
+    63, 63, 63, 63, 63, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 42, 89, 89, 89, 89,
+    55, 55, 55, 41, 41, 41, 41, 41, 41, 41, 66, 66, 66, 65, 65, 65, 65, 65, 65, 77,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 73, 73, 89, 89, 89, 89,
+    89, 89, 55, 41, 41, 41, 41, 41, 41, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 73, 73, 49, 89, 60, 89,
+    60, 90, 90, 90, 41, 41, 41, 41, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 73, 73, 49, 60, 60, 60,
+    60, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 73, 73, 49, 60, 60, 60,
+    60, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 63, 73, 73, 73, 73, 73, 73, 73, 73, 49, 60, 60, 60,
+    60, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 73, 73, 49, 49, 60, 60, 60,
+    60, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 100, 100, 100, 60, 60, 60,
+    60, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 78, 78, 78, 78, 60, 60, 60,
+    60, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65,
+    68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 80, 79, 79, 79, 79, 79, 79, 79, 79,
+    79, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 80, 80, 79, 79, 79, 79, 79, 79, 79,
+    79, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 80, 80, 80, 80, 79, 79, 79, 79, 79,
+    79, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 80, 80, 80, 80, 80, 79, 79, 79, 79,
+    91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 5,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 80, 80, 80, 80, 80, 80, 79, 79, 79,
+    91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 80, 80, 80, 80, 80, 80, 51, 51, 51,
+    91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 92, 92, 58, 58, 58, 84, 84,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 80, 80, 80, 80, 80, 51, 51, 51, 51,
+    51, 91, 91, 91, 91, 36, 36, 36, 36, 92, 92, 92, 92, 92, 92, 58, 58, 58, 58, 84,
+    68, 68, 68, 68, 68, 68, 68, 56, 44, 44, 44, 80, 80, 80, 80, 51, 51, 51, 51, 51,
+    51, 51, 51, 91, 91, 91, 69, 69, 69, 92, 92, 92, 92, 92, 92, 58, 58, 58, 58, 84,
+    68, 68, 68, 68, 68, 68, 68, 44, 44, 44, 44, 80, 80, 80, 80, 51, 51, 51, 51, 51,
+    51, 59, 59, 59, 101, 101, 69, 69, 69, 69, 69, 69, 69, 92, 92, 58, 58, 58, 58, 58,
+    68, 68, 68, 68, 68, 68, 68, 44, 44, 44, 44, 95, 80, 80, 51, 51, 51, 59, 59, 59,
+    59, 59, 59, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 92, 92, 58, 58, 58, 58, 58,
+    61, 61, 93, 93, 93, 93, 93, 44, 95, 95, 95, 95, 95, 80, 59, 59, 59, 59, 59, 59,
+    59, 94, 94, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 96, 96, 96, 96, 58, 58,
+    61, 61, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 59, 59, 59, 59, 59, 59, 59,
+    59, 94, 94, 94, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 96, 96, 96, 96, 96, 96,
+    61, 61, 61, 93, 93, 93, 93, 95, 95, 95, 95, 95, 75, 75, 59, 59, 59, 59, 59, 59,
+    94, 94, 94, 94, 46, 46, 46, 69, 69, 69, 69, 69, 69, 69, 69, 96, 96, 96, 96, 96,
+    61, 61, 61, 61, 93, 93, 93, 95, 95, 95, 95, 75, 75, 75, 59, 59, 59, 59, 59, 59,
+    94, 94, 94, 94, 82, 46, 46, 69, 69, 69, 69, 38, 38, 38, 38, 96, 96, 96, 96, 96,
+    61, 61, 61, 61, 61, 93, 93, 95, 95, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    94, 94, 94, 82, 82, 82, 82, 82, 69, 69, 69, 38, 38, 38, 38, 38, 96, 96, 96, 96,
+    61, 61, 61, 61, 61, 61, 97, 97, 75, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    94, 94, 82, 82, 82, 82, 82, 82, 82, 69, 69, 69, 69, 69, 69, 38, 96, 96, 98, 98,
+    61, 61, 61, 61, 61, 83, 97, 97, 97, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    85, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 69, 69, 69, 98, 98, 98, 98, 98, 98,
+    61, 61, 61, 61, 83, 83, 83, 97, 97, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    85, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 86, 98, 98, 98, 98, 98, 81,
+    61, 61, 87, 87, 83, 83, 83, 83, 97, 97, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    82, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 99, 98, 98, 98, 98, 98, 81,
+    87, 87, 87, 87, 83, 83, 83, 83, 83, 97, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85,
+    82, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 99, 99, 98, 98, 98, 98, 98,
+    87, 87, 87, 87, 83, 83, 83, 83, 83, 83, 97, 97, 75, 75, 75, 75, 85, 85, 85, 85,
+    70, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 99, 99, 98, 98, 98, 98, 98,
+    87, 87, 87, 83, 83, 83, 83, 83, 83, 83, 83, 97, 97, 75, 75, 88, 88, 88, 88, 70,
+    70, 70, 70, 82, 82, 86, 86, 86, 86, 86, 86, 86, 86, 99, 99, 99, 98, 81, 81, 81,
+    87, 87, 87, 83, 83, 83, 83, 83, 83, 83, 83, 71, 71, 88, 88, 88, 88, 88, 70, 70,
+    70, 70, 70, 70, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 99, 99, 81, 81, 81, 81,
+    63, 87, 87, 83, 83, 83, 83, 83, 83, 71, 71, 71, 62, 62, 88, 88, 88, 70, 70, 70,
+    70, 70, 70, 70, 70, 86, 86, 86, 86, 86, 86, 86, 86, 86, 99, 99, 76, 76, 76, 76,
+    63, 53, 53, 53, 83, 83, 71, 71, 71, 71, 71, 71, 62, 62, 62, 88, 88, 70, 70, 70,
+    70, 70, 70, 70, 70, 70, 86, 86, 86, 86, 86, 86, 86, 54, 99, 99, 77, 77, 77, 77,
+    63, 63, 63, 53, 72, 71, 71, 71, 71, 71, 71, 71, 62, 62, 62, 62, 88, 70, 70, 70,
+    70, 55, 55, 55, 55, 55, 55, 86, 86, 86, 86, 86, 86, 54, 102, 77, 77, 77, 77, 77,
+    63, 63, 63, 53, 72, 72, 72, 72, 71, 71, 71, 71, 62, 62, 62, 62, 88, 88, 55, 55,
+    55, 55, 55, 55, 55, 55, 41, 41, 86, 86, 86, 86, 54, 54, 54, 77, 77, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 71, 62, 62, 62, 62, 88, 88, 55, 55,
+    55, 55, 55, 55, 55, 55, 41, 41, 86, 86, 86, 54, 54, 54, 54, 54, 77, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 62, 62, 62, 62, 89, 89, 55, 55,
+    55, 55, 55, 55, 55, 41, 41, 41, 41, 103, 103, 66, 66, 66, 54, 54, 77, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 72, 62, 62, 89, 89, 89, 89, 55,
+    55, 55, 55, 55, 55, 41, 41, 41, 41, 103, 103, 66, 66, 66, 66, 54, 54, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 89, 89, 89, 89, 89, 89,
+    55, 55, 55, 55, 41, 41, 41, 41, 103, 103, 103, 66, 66, 66, 66, 65, 54, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 89, 89, 89, 89, 89,
+    89, 55, 55, 55, 41, 41, 41, 41, 103, 103, 66, 66, 66, 66, 66, 65, 65, 65, 77, 77,
+    63, 63, 63, 63, 63, 63, 72, 73, 73, 73, 73, 73, 73, 73, 73, 73, 89, 89, 89, 89,
+    89, 89, 90, 41, 41, 41, 41, 41, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 73, 73, 89, 89, 89, 89,
+    100, 90, 90, 90, 90, 90, 103, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65,
+    63, 63, 74, 63, 63, 63, 63, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 73, 73, 73, 49, 60, 100, 100,
+    90, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 100, 73, 49, 60, 100, 100,
+    90, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 100, 100, 100, 100, 100, 100,
+    90, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 78, 100, 100, 100, 100, 100, 100,
+    90, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 104, 104, 104, 104, 104, 105,
+    68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    79, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 80, 80, 79, 79, 79, 79, 79, 79, 79,
+    79, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 80, 80, 80, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 80, 80, 80, 80, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 5,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 80, 80, 80, 80, 80, 80, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 56, 80, 80, 80, 80, 80, 80, 80, 79, 79, 91,
+    91, 91, 91, 91, 91, 36, 36, 36, 92, 92, 92, 92, 92, 92, 92, 92, 58, 84, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 56, 80, 80, 80, 80, 80, 80, 80, 80, 79, 91,
+    91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 58, 58, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 56, 80, 80, 80, 80, 80, 80, 80, 51, 51, 51,
+    51, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 58, 58, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 95, 95, 80, 80, 80, 80, 80, 51, 51, 51, 59,
+    94, 101, 101, 101, 101, 101, 69, 92, 92, 92, 92, 92, 92, 92, 92, 96, 96, 58, 58, 84,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 80, 80, 80, 80, 59, 59, 59, 59,
+    94, 94, 94, 101, 101, 101, 69, 69, 69, 69, 69, 92, 92, 92, 92, 96, 96, 96, 96, 58,
+    61, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 80, 59, 59, 59, 59, 59, 59,
+    94, 94, 94, 94, 94, 101, 46, 69, 69, 69, 69, 69, 69, 92, 96, 96, 96, 96, 96, 96,
+    61, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 95, 59, 59, 85, 85, 59, 59,
+    94, 94, 94, 94, 94, 94, 69, 69, 69, 69, 69, 69, 69, 69, 96, 96, 96, 96, 96, 96,
+    61, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 75, 59, 59, 85, 85, 85, 94,
+    94, 94, 94, 94, 94, 82, 82, 69, 69, 69, 69, 69, 69, 69, 96, 96, 96, 96, 96, 96,
+    61, 61, 61, 93, 93, 93, 93, 95, 95, 95, 95, 95, 75, 75, 85, 85, 85, 85, 85, 94,
+    94, 94, 94, 94, 82, 82, 82, 82, 69, 69, 69, 38, 38, 38, 96, 96, 96, 96, 96, 96,
+    61, 61, 61, 61, 93, 93, 93, 95, 95, 95, 75, 75, 75, 75, 85, 85, 85, 85, 85, 85,
+    94, 94, 94, 82, 82, 82, 82, 82, 82, 69, 69, 38, 38, 38, 96, 96, 96, 96, 96, 96,
+    61, 61, 61, 61, 93, 93, 93, 97, 97, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85, 85,
+    94, 94, 94, 82, 82, 82, 82, 82, 82, 82, 69, 69, 69, 69, 96, 96, 98, 98, 98, 98,
+    61, 61, 61, 61, 61, 97, 97, 97, 97, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85, 85,
+    94, 94, 82, 82, 82, 82, 82, 82, 82, 82, 82, 69, 69, 99, 98, 98, 98, 98, 98, 98,
+    61, 61, 61, 61, 83, 97, 97, 97, 97, 75, 75, 75, 75, 75, 75, 85, 85, 85, 85, 85,
+    85, 82, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 99, 98, 98, 98, 98, 98, 98,
+    61, 61, 87, 87, 83, 83, 97, 97, 97, 97, 97, 97, 75, 75, 75, 85, 85, 85, 85, 85,
+    85, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 99, 99, 99, 98, 98, 98, 98, 98,
+    87, 87, 87, 87, 83, 83, 83, 97, 97, 97, 97, 97, 75, 75, 75, 85, 85, 85, 85, 85,
+    82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 99, 99, 99, 98, 98, 98, 98, 98,
+    87, 87, 87, 87, 83, 83, 83, 83, 97, 97, 97, 97, 97, 97, 88, 88, 88, 88, 85, 106,
+    82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 83, 83, 83, 83, 83, 97, 97, 97, 97, 88, 88, 88, 88, 88, 88, 106,
+    106, 82, 82, 82, 82, 82, 86, 86, 86, 86, 86, 86, 86, 99, 99, 99, 98, 98, 98, 81,
+    87, 87, 87, 83, 83, 83, 83, 83, 83, 83, 97, 97, 97, 88, 88, 88, 88, 88, 88, 70,
+    70, 70, 70, 82, 82, 86, 86, 86, 86, 86, 86, 86, 86, 99, 99, 99, 98, 98, 98, 81,
+    63, 87, 87, 83, 83, 83, 83, 83, 83, 83, 71, 71, 88, 88, 88, 88, 88, 88, 88, 70,
+    70, 70, 70, 70, 86, 86, 86, 86, 86, 86, 86, 86, 86, 99, 99, 99, 76, 76, 76, 76,
+    63, 63, 63, 87, 83, 83, 83, 83, 71, 71, 71, 71, 88, 88, 88, 88, 88, 88, 70, 70,
+    70, 70, 70, 70, 70, 86, 86, 86, 86, 86, 86, 86, 86, 99, 99, 99, 77, 77, 77, 77,
+    63, 63, 63, 53, 72, 72, 71, 71, 71, 71, 71, 71, 71, 88, 88, 88, 88, 88, 70, 70,
+    70, 55, 55, 55, 55, 86, 86, 86, 86, 86, 86, 86, 86, 102, 102, 102, 77, 77, 77, 77,
+    63, 63, 63, 53, 72, 72, 72, 72, 72, 71, 71, 71, 71, 88, 88, 88, 88, 88, 55, 55,
+    55, 55, 55, 55, 55, 55, 103, 86, 86, 86, 86, 86, 102, 102, 102, 102, 77, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 62, 88, 88, 88, 88, 88, 89, 55,
+    55, 55, 55, 55, 55, 55, 41, 103, 103, 103, 102, 103, 102, 102, 102, 102, 77, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 72, 62, 88, 89, 89, 89, 89, 89,
+    55, 55, 55, 55, 55, 41, 41, 103, 103, 103, 103, 103, 103, 102, 102, 102, 77, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 107, 107, 89, 89, 89, 89, 89, 89,
+    55, 55, 55, 55, 55, 41, 41, 103, 103, 103, 103, 66, 66, 66, 102, 102, 102, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 55, 55, 103, 103, 103, 103, 103, 103, 103, 66, 66, 66, 66, 102, 54, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 89, 108, 103, 103, 103, 103, 103, 103, 103, 66, 66, 66, 66, 65, 65, 65, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 107, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89,
+    89, 89, 89, 90, 108, 103, 103, 103, 103, 66, 66, 66, 66, 66, 66, 65, 65, 65, 109, 109,
+    63, 63, 63, 63, 63, 63, 73, 73, 107, 107, 107, 107, 107, 107, 107, 110, 89, 89, 89, 89,
+    89, 89, 90, 90, 90, 103, 103, 103, 103, 66, 66, 66, 66, 66, 66, 65, 65, 65, 109, 109,
+    63, 63, 63, 63, 63, 63, 63, 73, 73, 107, 107, 107, 107, 107, 110, 110, 110, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 109, 109,
+    63, 63, 74, 74, 74, 74, 63, 73, 73, 73, 73, 73, 107, 107, 110, 110, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 107, 110, 110, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 100, 100, 100, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 100, 100, 100, 100, 100, 100, 100,
+    90, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 100, 100, 100, 100, 100, 100, 100,
+    90, 90, 90, 90, 90, 90, 90, 90, 111, 111, 111, 66, 66, 66, 112, 104, 104, 104, 104, 105,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    79, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 80, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 56, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 56, 80, 80, 80, 80, 80, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 56, 80, 80, 80, 80, 80, 80, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 84, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 68, 56, 56, 80, 80, 80, 80, 80, 80, 80, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 84, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 68, 56, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 91,
+    91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 96, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 95, 95, 95, 95, 80, 80, 80, 80, 80, 80, 59, 59, 94,
+    94, 101, 101, 101, 101, 101, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 96, 96, 96, 84,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 80, 80, 80, 80, 59, 59, 59, 94,
+    94, 94, 101, 101, 101, 101, 101, 69, 69, 69, 92, 92, 92, 92, 92, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 80, 80, 59, 59, 59, 59, 94,
+    94, 94, 94, 101, 101, 101, 101, 69, 69, 69, 69, 92, 92, 92, 96, 96, 96, 96, 96, 96,
+    61, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 95, 85, 85, 85, 85, 85, 94,
+    94, 94, 94, 94, 94, 101, 101, 113, 69, 69, 69, 69, 69, 92, 96, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 95, 85, 85, 85, 85, 85, 94,
+    94, 94, 94, 94, 94, 94, 113, 113, 113, 69, 69, 69, 69, 69, 96, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 85, 85, 85, 85, 85, 85, 94,
+    94, 94, 94, 94, 94, 82, 82, 82, 113, 113, 113, 113, 113, 69, 96, 96, 96, 96, 96, 96,
+    61, 61, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 75, 85, 85, 85, 85, 85, 85, 94,
+    94, 94, 94, 82, 82, 82, 82, 82, 82, 113, 113, 113, 113, 69, 96, 96, 96, 96, 96, 96,
+    61, 61, 61, 61, 93, 93, 93, 97, 97, 95, 75, 75, 75, 75, 85, 85, 85, 85, 85, 85,
+    94, 94, 94, 82, 82, 82, 82, 82, 82, 82, 82, 69, 69, 69, 96, 98, 98, 98, 98, 98,
+    61, 61, 61, 61, 61, 97, 97, 97, 97, 97, 97, 75, 75, 75, 85, 85, 85, 85, 85, 85,
+    94, 94, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 99, 99, 99, 98, 98, 98, 98, 98,
+    61, 61, 61, 87, 87, 97, 97, 97, 97, 97, 97, 97, 75, 75, 85, 85, 85, 85, 85, 85,
+    94, 82, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 99, 99, 99, 98, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 75, 85, 85, 85, 85, 85, 85,
+    85, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 83, 97, 97, 97, 97, 97, 97, 97, 75, 85, 85, 85, 85, 85, 85,
+    106, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 83, 83, 83, 97, 97, 97, 97, 97, 97, 97, 88, 88, 88, 88, 88, 106,
+    106, 106, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 83, 83, 83, 83, 97, 97, 97, 97, 97, 88, 88, 88, 88, 88, 88, 106,
+    106, 106, 82, 82, 82, 82, 82, 86, 86, 86, 86, 86, 99, 99, 99, 99, 99, 98, 98, 98,
+    87, 87, 87, 87, 83, 83, 83, 83, 83, 97, 97, 97, 88, 88, 88, 88, 88, 88, 88, 88,
+    106, 106, 106, 82, 82, 86, 86, 86, 86, 86, 86, 86, 99, 99, 99, 99, 99, 98, 98, 98,
+    63, 87, 87, 87, 83, 83, 83, 83, 83, 83, 97, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+    70, 70, 70, 106, 86, 86, 86, 86, 86, 86, 86, 86, 99, 99, 99, 99, 99, 98, 98, 77,
+    63, 63, 63, 87, 83, 83, 83, 83, 71, 71, 71, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+    70, 70, 70, 70, 86, 86, 86, 86, 86, 86, 86, 86, 99, 99, 99, 99, 99, 77, 77, 77,
+    63, 63, 63, 53, 72, 72, 72, 72, 71, 71, 71, 71, 88, 88, 88, 88, 88, 88, 88, 88,
+    70, 55, 55, 55, 55, 86, 86, 86, 86, 86, 86, 102, 102, 102, 102, 102, 102, 77, 77, 77,
+    63, 63, 63, 53, 72, 72, 72, 72, 72, 72, 71, 71, 88, 88, 88, 88, 88, 88, 88, 88,
+    55, 55, 55, 55, 55, 103, 103, 86, 86, 86, 102, 102, 102, 102, 102, 102, 102, 77, 77, 77,
+    63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 72, 88, 88, 88, 88, 88, 88, 89, 89,
+    55, 55, 55, 55, 55, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 77, 77, 77,
+    63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 72, 72, 107, 88, 88, 89, 89, 89, 89, 89,
+    89, 89, 55, 108, 103, 103, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 89, 108, 103, 103, 103, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 77, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 89, 108, 108, 103, 103, 103, 103, 103, 103, 103, 103, 103, 102, 102, 102, 114, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 89, 108, 108, 103, 103, 103, 103, 103, 103, 66, 66, 66, 66, 102, 114, 114, 114, 77,
+    63, 63, 63, 63, 72, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89,
+    89, 89, 89, 89, 108, 103, 103, 103, 103, 66, 66, 66, 66, 66, 66, 66, 65, 109, 109, 109,
+    63, 63, 63, 63, 63, 63, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 89, 89, 89, 89,
+    89, 89, 90, 90, 90, 103, 103, 103, 103, 66, 66, 66, 66, 66, 66, 66, 65, 109, 109, 109,
+    63, 63, 63, 63, 63, 63, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 100, 100,
+    100, 90, 90, 90, 90, 90, 103, 103, 103, 66, 66, 66, 66, 66, 66, 65, 65, 109, 109, 109,
+    63, 63, 74, 74, 74, 74, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 66, 66, 66, 66, 66, 66, 66, 66, 65, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 107, 107, 110, 110, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 66, 66, 115, 66, 66, 66, 66, 66, 65, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 100, 100, 110, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 66, 66, 115, 115, 66, 66, 66, 66, 65, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 100, 100, 100, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 111, 111, 111, 111, 66, 66, 66, 116, 65, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 107, 100, 100, 100, 100, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 111, 111, 111, 111, 111, 111, 116, 116, 116, 104, 109, 109,
+    68, 68, 68, 68, 68, 68, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 91, 92, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 56, 56, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 68, 56, 80, 80, 80, 80, 80, 80, 80, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 68, 56, 80, 80, 80, 80, 80, 80, 80, 80, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 68, 95, 95, 80, 80, 80, 80, 80, 80, 80, 80, 79, 91,
+    101, 101, 101, 101, 101, 101, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 96, 96, 84,
+    68, 68, 68, 68, 68, 68, 68, 95, 95, 95, 95, 80, 80, 80, 80, 80, 80, 80, 101, 101,
+    101, 101, 101, 101, 101, 101, 101, 92, 92, 92, 92, 92, 92, 92, 92, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 80, 80, 80, 80, 59, 59, 94, 94,
+    101, 101, 101, 101, 101, 101, 101, 113, 69, 92, 92, 92, 92, 92, 92, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 95, 80, 85, 85, 85, 94, 94,
+    94, 94, 94, 101, 101, 101, 101, 113, 113, 69, 92, 92, 92, 92, 96, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 95, 85, 85, 85, 85, 94, 94,
+    94, 94, 94, 94, 94, 101, 113, 113, 113, 113, 69, 92, 92, 92, 96, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 95, 85, 85, 85, 85, 94, 94,
+    94, 94, 94, 94, 94, 94, 113, 113, 113, 113, 113, 69, 92, 96, 96, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 85, 85, 85, 85, 85, 85, 94,
+    94, 94, 94, 94, 94, 82, 82, 82, 113, 113, 113, 113, 113, 96, 96, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 85, 85, 85, 85, 85, 85, 94,
+    94, 94, 94, 94, 82, 82, 82, 82, 113, 113, 113, 113, 113, 96, 96, 96, 96, 96, 96, 96,
+    87, 87, 93, 93, 93, 93, 93, 97, 97, 95, 95, 95, 95, 85, 85, 85, 85, 85, 85, 94,
+    94, 94, 94, 82, 82, 82, 82, 82, 82, 82, 82, 69, 99, 99, 96, 98, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 117, 85, 85, 85, 85, 85, 94,
+    94, 94, 94, 82, 82, 82, 82, 82, 82, 82, 82, 99, 99, 99, 99, 98, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 85, 85, 85, 85, 85,
+    94, 94, 82, 82, 82, 82, 82, 82, 82, 82, 86, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 85, 85, 85, 85,
+    106, 106, 82, 82, 82, 82, 82, 82, 82, 86, 86, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 117, 85, 106, 106,
+    106, 106, 82, 82, 82, 82, 82, 82, 86, 86, 86, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 88, 88, 88, 88, 88, 106, 106,
+    106, 106, 106, 82, 82, 82, 82, 86, 86, 86, 86, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 83, 97, 97, 97, 97, 97, 97, 97, 88, 88, 88, 88, 88, 88, 106,
+    106, 106, 106, 82, 82, 82, 82, 86, 86, 86, 86, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    87, 87, 87, 87, 87, 83, 83, 97, 97, 97, 97, 97, 88, 88, 88, 88, 88, 88, 88, 88,
+    106, 106, 106, 106, 106, 82, 82, 86, 86, 86, 86, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    87, 87, 87, 87, 83, 83, 83, 83, 97, 97, 97, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+    106, 106, 106, 106, 106, 86, 86, 86, 86, 86, 86, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    63, 63, 63, 87, 83, 83, 83, 83, 83, 118, 118, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+    88, 106, 106, 106, 106, 86, 86, 86, 86, 86, 86, 99, 99, 99, 99, 99, 99, 99, 77, 77,
+    63, 63, 63, 53, 72, 72, 72, 72, 71, 71, 118, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+    88, 106, 106, 106, 106, 86, 86, 86, 86, 86, 102, 102, 102, 102, 102, 102, 102, 102, 77, 77,
+    63, 63, 63, 53, 72, 72, 72, 72, 72, 72, 118, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+    88, 89, 108, 108, 108, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 72, 88, 88, 88, 88, 88, 88, 88, 89, 89,
+    89, 89, 108, 108, 108, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 72, 107, 107, 107, 88, 88, 89, 89, 89, 89, 89,
+    89, 89, 108, 108, 108, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 114, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 108, 108, 108, 103, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 114, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 107, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 89, 108, 108, 103, 103, 103, 103, 103, 103, 103, 103, 102, 102, 102, 114, 114, 114, 119,
+    63, 63, 63, 63, 72, 72, 107, 107, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 89, 108, 108, 103, 103, 103, 103, 103, 103, 103, 103, 103, 102, 114, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 89, 89, 89, 89, 89,
+    89, 89, 90, 90, 108, 103, 103, 103, 103, 115, 115, 115, 66, 66, 66, 66, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 89, 89, 89,
+    89, 89, 90, 90, 90, 103, 103, 103, 103, 115, 115, 115, 115, 115, 66, 66, 109, 109, 109, 109,
+    63, 63, 63, 74, 74, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 100,
+    100, 90, 90, 90, 90, 90, 103, 103, 103, 115, 115, 115, 115, 115, 66, 66, 109, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 103, 103, 115, 115, 115, 115, 115, 66, 66, 109, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 103, 115, 115, 115, 115, 115, 115, 66, 109, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 107, 100, 100, 100, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 111, 111, 115, 115, 115, 115, 115, 66, 109, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 100, 100, 100, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 111, 111, 111, 115, 115, 115, 116, 116, 116, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 107, 107, 107, 100, 100, 100, 100, 100, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 111, 111, 111, 111, 115, 115, 115, 116, 116, 116, 116, 109, 109,
+    68, 68, 68, 68, 68, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 56, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 36, 36, 36, 36, 36, 36, 36, 84,
+    68, 68, 68, 68, 68, 68, 68, 56, 80, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 68, 80, 80, 80, 80, 80, 80, 80, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 68, 95, 80, 80, 80, 80, 80, 80, 80, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 68, 95, 95, 80, 80, 80, 80, 80, 80, 80, 79, 79, 101,
+    101, 101, 101, 101, 101, 101, 101, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 96, 96, 84,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 95, 80, 80, 80, 80, 80, 80, 80, 101, 101,
+    101, 101, 101, 101, 101, 101, 101, 101, 92, 92, 92, 92, 92, 92, 92, 92, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 80, 80, 80, 85, 85, 101, 101,
+    101, 101, 101, 101, 101, 101, 101, 113, 113, 92, 92, 92, 92, 92, 92, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 95, 80, 85, 85, 85, 94, 94,
+    101, 101, 101, 101, 101, 101, 113, 113, 113, 113, 92, 92, 92, 92, 96, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 95, 85, 85, 85, 85, 94, 94,
+    94, 94, 101, 101, 101, 101, 113, 113, 113, 113, 113, 92, 92, 92, 96, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 120, 85, 85, 85, 85, 94, 94,
+    94, 94, 94, 94, 101, 113, 113, 113, 113, 113, 113, 113, 121, 121, 96, 96, 96, 96, 96, 96,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 120, 120, 117, 85, 85, 85, 94, 94,
+    94, 94, 94, 94, 94, 113, 113, 113, 113, 113, 113, 113, 121, 121, 96, 96, 96, 96, 96, 96,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 95, 120, 120, 117, 117, 117, 85, 85, 85, 94,
+    94, 94, 94, 94, 94, 82, 82, 113, 113, 113, 113, 113, 121, 96, 96, 96, 96, 96, 96, 98,
+    87, 87, 93, 93, 93, 93, 97, 97, 97, 95, 120, 120, 120, 117, 117, 117, 117, 85, 85, 94,
+    94, 94, 94, 94, 82, 82, 82, 82, 82, 113, 113, 113, 99, 99, 96, 98, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 120, 117, 117, 117, 117, 117, 85, 94,
+    94, 94, 94, 82, 82, 82, 82, 82, 82, 82, 82, 99, 99, 99, 99, 98, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 117, 117, 117, 117, 85,
+    94, 94, 82, 82, 82, 82, 82, 82, 82, 82, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 82, 82, 82, 82, 82, 82, 86, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 82, 82, 82, 82, 86, 86, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 88, 88, 88, 88, 88, 106, 106,
+    106, 106, 106, 106, 106, 82, 82, 86, 86, 86, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 88, 88, 88, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 82, 82, 86, 86, 86, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    87, 87, 87, 87, 87, 83, 97, 97, 97, 97, 118, 118, 88, 88, 88, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 82, 86, 86, 86, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    87, 87, 87, 87, 87, 83, 83, 97, 97, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88, 88,
+    106, 106, 106, 106, 106, 106, 82, 86, 86, 86, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    63, 63, 87, 87, 87, 83, 83, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88, 88,
+    88, 106, 106, 106, 106, 106, 86, 86, 86, 86, 99, 99, 99, 99, 99, 99, 99, 99, 99, 77,
+    63, 63, 63, 87, 87, 83, 83, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88, 88,
+    88, 106, 106, 106, 106, 103, 86, 86, 86, 86, 102, 102, 102, 102, 102, 102, 102, 102, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88, 88,
+    88, 89, 108, 108, 108, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 77, 77,
+    63, 63, 63, 63, 72, 72, 72, 72, 72, 118, 118, 118, 88, 88, 88, 88, 88, 88, 89, 89,
+    89, 89, 108, 108, 108, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 114, 119,
+    63, 63, 63, 63, 72, 72, 72, 72, 107, 107, 107, 107, 107, 88, 88, 89, 89, 89, 89, 89,
+    89, 89, 108, 108, 108, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 114, 114, 119,
+    63, 63, 63, 63, 72, 72, 107, 107, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 108, 108, 108, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 114, 114, 114, 119,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 89, 89, 108, 108, 103, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 89, 89, 89, 89, 89,
+    89, 89, 89, 108, 108, 103, 103, 103, 103, 103, 103, 103, 103, 102, 102, 114, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 89, 89, 89, 89,
+    89, 89, 89, 89, 108, 103, 103, 103, 103, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 89, 89,
+    89, 90, 90, 90, 108, 103, 103, 103, 103, 115, 115, 115, 115, 115, 115, 115, 114, 109, 109, 109,
+    74, 74, 74, 74, 74, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110,
+    89, 90, 90, 90, 108, 103, 103, 103, 103, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 100, 100,
+    100, 90, 90, 90, 90, 90, 103, 103, 103, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 100, 100, 100,
+    100, 90, 90, 90, 90, 90, 90, 90, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    74, 74, 74, 74, 74, 74, 107, 107, 107, 107, 107, 107, 107, 107, 110, 100, 100, 100, 100, 100,
+    100, 100, 90, 90, 90, 90, 90, 90, 111, 111, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 74, 107, 107, 107, 107, 107, 107, 100, 100, 100, 100, 100, 100,
+    100, 100, 90, 90, 90, 90, 90, 111, 111, 111, 111, 115, 115, 115, 115, 116, 116, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 123, 123, 74, 107, 107, 107, 107, 100, 100, 100, 124, 124, 124, 100,
+    100, 100, 90, 90, 90, 90, 90, 111, 111, 111, 111, 115, 115, 115, 115, 116, 116, 116, 109, 109,
+    68, 68, 68, 68, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 91, 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 91, 91, 125, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 80, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 56, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 36, 36, 36, 36, 126, 84,
+    68, 68, 68, 68, 68, 68, 68, 56, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 56, 80, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 84, 84,
+    68, 68, 68, 68, 68, 68, 68, 95, 80, 80, 80, 80, 80, 80, 80, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 127, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 96, 84,
+    68, 68, 68, 68, 68, 68, 68, 95, 95, 95, 80, 80, 80, 80, 80, 80, 79, 79, 101, 101,
+    101, 101, 101, 101, 101, 101, 101, 127, 127, 92, 92, 92, 92, 92, 92, 92, 96, 96, 96, 84,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 80, 80, 80, 80, 80, 101, 101, 101,
+    101, 101, 101, 101, 101, 101, 101, 113, 127, 127, 92, 92, 92, 92, 92, 92, 96, 96, 96, 96,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 80, 80, 80, 80, 101, 101, 101,
+    101, 101, 101, 101, 101, 101, 101, 113, 113, 127, 127, 92, 92, 92, 92, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 95, 80, 117, 85, 94, 94, 101,
+    101, 101, 101, 101, 101, 101, 113, 113, 113, 113, 127, 121, 121, 92, 92, 96, 96, 96, 96, 96,
+    93, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 95, 120, 120, 117, 117, 94, 94, 94,
+    94, 101, 101, 101, 101, 113, 113, 113, 113, 113, 113, 121, 121, 121, 96, 96, 96, 96, 96, 96,
+    68, 93, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 120, 120, 117, 117, 117, 85, 94, 94,
+    94, 94, 94, 101, 101, 113, 113, 113, 113, 113, 113, 113, 121, 121, 96, 96, 96, 96, 96, 96,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 95, 120, 120, 120, 117, 117, 117, 85, 94, 94,
+    94, 94, 94, 94, 113, 113, 113, 113, 113, 113, 113, 113, 121, 121, 96, 96, 96, 96, 96, 96,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 94,
+    94, 94, 94, 94, 94, 113, 113, 113, 113, 113, 113, 113, 121, 121, 96, 96, 96, 96, 96, 98,
+    68, 68, 93, 93, 93, 93, 97, 97, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 117, 94,
+    94, 94, 94, 94, 82, 82, 113, 113, 113, 113, 113, 113, 121, 99, 96, 98, 98, 98, 98, 98,
+    68, 68, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 120, 117, 117, 117, 117, 117, 117, 117,
+    94, 94, 94, 82, 82, 82, 82, 82, 82, 113, 113, 99, 99, 99, 99, 98, 98, 98, 98, 98,
+    68, 68, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 120, 117, 117, 117, 117, 117, 117, 117,
+    106, 106, 106, 82, 82, 82, 82, 82, 82, 82, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    68, 68, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 82, 82, 82, 82, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    68, 68, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 82, 82, 82, 82, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 88, 88, 88, 88, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 82, 82, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 97, 97, 97, 118, 118, 88, 88, 88, 88, 88, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 86, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    87, 87, 87, 87, 87, 97, 97, 97, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 106, 86, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    87, 87, 87, 87, 87, 87, 97, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88,
+    106, 106, 106, 106, 106, 106, 106, 86, 86, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98,
+    87, 87, 87, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88,
+    106, 106, 106, 106, 106, 106, 106, 86, 86, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98,
+    63, 63, 63, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88,
+    88, 106, 106, 106, 106, 108, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 119,
+    63, 63, 63, 63, 72, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88, 88,
+    88, 108, 108, 108, 108, 108, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 119,
+    63, 63, 63, 63, 72, 72, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 114, 119,
+    63, 63, 63, 63, 72, 72, 107, 107, 107, 107, 107, 107, 107, 88, 88, 88, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 114, 114, 119,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 103, 102, 102, 102, 102, 114, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 103, 103, 102, 102, 102, 114, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 89, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 103, 103, 103, 103, 103, 103, 103, 103, 102, 114, 114, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 89, 89, 89,
+    89, 89, 108, 108, 108, 108, 103, 103, 103, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114,
+    63, 72, 72, 72, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110,
+    89, 89, 89, 108, 108, 108, 103, 103, 103, 115, 115, 115, 115, 115, 115, 114, 114, 114, 109, 109,
+    74, 74, 74, 74, 74, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110,
+    110, 100, 100, 108, 108, 108, 103, 103, 103, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    74, 74, 74, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 100,
+    100, 100, 100, 90, 90, 90, 103, 103, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 100, 100, 100,
+    100, 100, 100, 90, 90, 90, 90, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 110, 100, 100, 100, 100, 100,
+    100, 100, 100, 90, 90, 90, 90, 111, 111, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 123, 107, 107, 107, 107, 107, 110, 100, 100, 100, 100, 100,
+    100, 100, 90, 90, 90, 90, 90, 111, 111, 111, 111, 115, 115, 115, 115, 116, 116, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 123, 123, 107, 107, 107, 107, 107, 110, 124, 124, 124, 124, 124,
+    124, 124, 124, 90, 90, 90, 111, 111, 111, 111, 111, 111, 115, 115, 115, 116, 116, 116, 109, 109,
+    68, 68, 68, 68, 68, 68, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 125, 125, 125, 125, 125, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 91, 91, 91, 91, 125, 125, 125, 92, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 68, 68, 68, 80, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 125, 125, 92, 92, 92, 92, 36, 36, 36, 36, 36, 36, 126,
+    68, 68, 68, 68, 68, 68, 68, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 125, 125, 125, 92, 92, 92, 92, 92, 92, 92, 36, 126, 126, 126,
+    68, 68, 68, 68, 68, 68, 68, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 125, 128, 128, 92, 92, 92, 92, 92, 92, 92, 92, 126, 126, 126,
+    68, 68, 68, 68, 68, 68, 68, 80, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 125, 128, 92, 92, 92, 92, 92, 92, 92, 92, 126, 126, 126,
+    68, 68, 68, 68, 68, 68, 68, 80, 80, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 127, 92, 92, 92, 92, 92, 92, 92, 92, 92, 126, 126, 126,
+    68, 68, 68, 68, 93, 93, 93, 95, 95, 95, 95, 80, 80, 80, 80, 79, 79, 79, 101, 101,
+    101, 101, 101, 101, 101, 101, 101, 127, 127, 92, 92, 92, 92, 92, 92, 92, 92, 96, 126, 126,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 80, 80, 80, 80, 79, 101, 101, 101,
+    101, 101, 101, 101, 101, 101, 101, 113, 127, 127, 127, 92, 92, 92, 92, 92, 96, 96, 96, 126,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 120, 120, 80, 129, 129, 101, 101, 101,
+    101, 101, 101, 101, 101, 101, 113, 113, 113, 127, 127, 127, 92, 92, 92, 96, 96, 96, 96, 96,
+    68, 68, 68, 93, 93, 93, 93, 95, 95, 95, 95, 120, 120, 120, 120, 117, 129, 101, 101, 101,
+    101, 101, 101, 101, 101, 101, 113, 113, 113, 113, 121, 121, 121, 92, 92, 96, 96, 96, 96, 96,
+    68, 68, 68, 93, 93, 93, 93, 95, 95, 95, 95, 120, 120, 120, 120, 117, 117, 117, 94, 101,
+    101, 101, 101, 101, 130, 113, 113, 113, 113, 113, 113, 121, 121, 121, 96, 96, 96, 96, 96, 96,
+    68, 68, 68, 93, 93, 93, 93, 95, 95, 95, 95, 120, 120, 120, 120, 117, 117, 117, 117, 94,
+    94, 101, 101, 101, 130, 113, 113, 113, 113, 113, 113, 113, 121, 121, 96, 96, 96, 96, 96, 96,
+    68, 68, 68, 93, 93, 93, 93, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 94,
+    94, 94, 94, 130, 130, 113, 113, 113, 113, 113, 113, 113, 121, 121, 121, 96, 96, 96, 96, 96,
+    68, 68, 93, 93, 93, 93, 93, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 117,
+    94, 94, 94, 94, 113, 113, 113, 113, 113, 113, 113, 113, 121, 121, 121, 96, 96, 96, 98, 98,
+    68, 68, 93, 93, 93, 93, 97, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 117,
+    94, 94, 94, 94, 94, 113, 113, 113, 113, 113, 113, 113, 121, 99, 99, 98, 98, 98, 98, 98,
+    68, 68, 68, 87, 131, 97, 97, 97, 97, 97, 120, 120, 120, 117, 117, 117, 117, 117, 117, 117,
+    117, 106, 106, 94, 82, 82, 82, 113, 113, 113, 113, 99, 99, 99, 99, 98, 98, 98, 98, 98,
+    68, 68, 68, 87, 131, 97, 97, 97, 97, 97, 97, 97, 120, 117, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 82, 82, 82, 113, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    68, 68, 68, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 117, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 82, 82, 82, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    68, 68, 68, 87, 87, 97, 97, 97, 97, 97, 97, 97, 97, 117, 117, 117, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 82, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    68, 68, 68, 87, 87, 97, 118, 118, 97, 97, 97, 97, 118, 88, 88, 88, 88, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    68, 68, 68, 87, 87, 97, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    68, 68, 68, 87, 87, 97, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    68, 68, 68, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 106, 86, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98,
+    68, 68, 68, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88,
+    106, 106, 106, 106, 106, 106, 106, 86, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 98,
+    63, 63, 63, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88,
+    88, 106, 106, 106, 106, 108, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 119,
+    63, 63, 63, 63, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88,
+    88, 108, 108, 108, 108, 108, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 114, 119,
+    63, 63, 63, 63, 72, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 114, 114, 119,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 88, 88, 88, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 102, 102, 102, 102, 114, 114, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 89, 89, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 103, 102, 102, 102, 114, 114, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 89, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 103, 103, 102, 102, 114, 114, 114, 114, 114, 114,
+    63, 63, 63, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 103, 103, 103, 114, 114, 114, 114, 114, 114, 114,
+    72, 72, 72, 72, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 72, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110,
+    110, 108, 108, 108, 108, 108, 103, 103, 103, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110,
+    110, 100, 108, 108, 108, 108, 103, 103, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110,
+    100, 100, 100, 108, 108, 108, 103, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 100, 100,
+    100, 100, 100, 90, 90, 90, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 110, 110, 100, 100, 100, 100,
+    100, 100, 100, 90, 90, 90, 90, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 110, 100, 100, 100, 100, 124,
+    124, 124, 124, 90, 90, 90, 90, 111, 111, 111, 111, 115, 115, 115, 115, 115, 116, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 123, 123, 123, 107, 107, 107, 107, 107, 124, 124, 124, 124, 124,
+    124, 124, 124, 124, 90, 90, 111, 111, 111, 111, 111, 111, 115, 115, 115, 116, 116, 116, 109, 109,
+    68, 68, 68, 68, 132, 132, 132, 132, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 132, 132, 132, 132, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 125, 125, 125, 125, 125, 125, 92, 92, 36, 36, 36, 36, 36, 36, 36,
+    68, 68, 68, 68, 132, 132, 132, 132, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 125, 125, 125, 125, 125, 127, 127, 92, 92, 92, 36, 36, 36, 126, 126,
+    68, 68, 68, 68, 68, 132, 132, 132, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 125, 128, 128, 128, 127, 127, 127, 92, 92, 92, 92, 126, 126, 126,
+    68, 68, 68, 68, 68, 68, 80, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 125, 128, 128, 128, 127, 127, 127, 92, 92, 92, 92, 126, 126, 126,
+    68, 68, 68, 68, 68, 68, 80, 80, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 91, 125, 128, 128, 127, 127, 127, 92, 92, 92, 92, 126, 126, 126,
+    68, 68, 68, 68, 68, 68, 95, 95, 95, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 127, 127, 128, 128, 127, 127, 127, 127, 92, 92, 92, 126, 126, 126,
+    68, 68, 68, 68, 93, 93, 93, 95, 95, 95, 95, 80, 80, 80, 80, 79, 79, 79, 101, 101,
+    101, 101, 101, 101, 101, 101, 101, 127, 127, 92, 127, 127, 127, 127, 127, 92, 92, 126, 126, 126,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 95, 95, 80, 80, 129, 129, 129, 129, 101, 101,
+    101, 101, 101, 101, 101, 101, 113, 113, 127, 127, 127, 127, 127, 121, 121, 92, 96, 126, 126, 126,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 120, 120, 120, 120, 129, 129, 129, 129, 101, 101,
+    101, 101, 101, 101, 101, 130, 113, 113, 113, 127, 127, 127, 127, 121, 121, 96, 96, 96, 126, 126,
+    68, 68, 68, 93, 93, 93, 93, 95, 95, 120, 120, 120, 120, 120, 120, 129, 129, 129, 101, 101,
+    101, 101, 101, 101, 130, 130, 113, 113, 113, 113, 121, 121, 121, 121, 92, 96, 96, 96, 96, 126,
+    68, 68, 68, 93, 93, 93, 93, 95, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 101,
+    101, 101, 101, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 96, 96, 96, 96, 96, 96,
+    68, 68, 68, 93, 93, 93, 93, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 94,
+    101, 101, 130, 130, 130, 113, 113, 113, 113, 113, 113, 113, 121, 121, 121, 121, 96, 96, 96, 96,
+    68, 68, 68, 93, 93, 93, 93, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117,
+    94, 94, 130, 130, 130, 113, 113, 113, 113, 113, 113, 113, 121, 121, 121, 121, 96, 96, 96, 96,
+    68, 68, 68, 93, 93, 93, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 117,
+    94, 94, 130, 130, 130, 113, 113, 113, 113, 113, 113, 113, 121, 121, 121, 121, 96, 96, 98, 98,
+    68, 68, 68, 93, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 117,
+    117, 94, 94, 130, 113, 113, 113, 113, 113, 113, 113, 113, 121, 99, 99, 98, 98, 98, 98, 98,
+    68, 68, 68, 87, 131, 97, 97, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 113, 113, 113, 113, 113, 113, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    68, 68, 68, 87, 131, 97, 97, 97, 97, 97, 120, 120, 120, 117, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 113, 113, 113, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    68, 68, 68, 87, 131, 97, 97, 97, 97, 97, 97, 120, 120, 117, 117, 117, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 113, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    68, 68, 68, 87, 87, 118, 118, 118, 97, 97, 97, 97, 118, 117, 117, 117, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    68, 68, 68, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    68, 68, 68, 87, 87, 97, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    68, 68, 68, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98,
+    68, 68, 68, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 106, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 133,
+    68, 68, 68, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88,
+    106, 106, 106, 106, 106, 106, 106, 106, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+    68, 68, 68, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88, 88,
+    88, 106, 106, 106, 106, 108, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 114,
+    68, 68, 68, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88,
+    88, 108, 108, 108, 108, 108, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 114, 114,
+    63, 63, 63, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 114, 114, 114, 114,
+    87, 87, 87, 87, 72, 118, 118, 118, 107, 107, 118, 118, 118, 118, 88, 88, 88, 88, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 102, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    87, 87, 87, 87, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 89, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 103, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    87, 87, 87, 87, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 89, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 103, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 63, 72, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 89, 89, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 103, 103, 103, 102, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 89,
+    89, 108, 108, 108, 108, 108, 103, 103, 103, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110,
+    110, 108, 108, 108, 108, 108, 103, 103, 103, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110,
+    110, 108, 108, 108, 108, 108, 103, 103, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 109,
+    122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110, 110,
+    100, 100, 108, 108, 108, 108, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110, 100,
+    100, 100, 100, 108, 108, 108, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 110, 110, 110, 110, 100, 100, 100,
+    100, 100, 100, 100, 90, 108, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 122, 134, 107, 107, 107, 110, 110, 110, 124, 124, 124, 124,
+    124, 124, 124, 124, 90, 90, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 134, 134, 107, 107, 107, 107, 107, 107, 124, 124, 124, 124,
+    124, 124, 124, 124, 124, 90, 111, 111, 111, 111, 111, 111, 111, 115, 115, 116, 116, 116, 135, 135,
+    68, 68, 68, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 79, 79,
+    91, 91, 91, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 128, 128, 36, 36, 36, 36, 36,
+    68, 68, 68, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 92, 92, 36, 36, 36, 36, 36,
+    68, 68, 68, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 125, 125, 125, 125, 125, 125, 125, 125, 125, 128, 92, 92, 92, 126, 126, 126, 126,
+    68, 68, 68, 68, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 125, 125, 125, 128, 128, 128, 128, 128, 128, 92, 92, 92, 126, 126, 126, 126,
+    68, 68, 68, 68, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 125, 125, 128, 128, 128, 128, 128, 128, 92, 92, 92, 126, 126, 126, 126,
+    68, 68, 68, 68, 68, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 125, 125, 125, 128, 128, 128, 128, 128, 92, 92, 92, 126, 126, 126, 126,
+    68, 68, 68, 68, 68, 132, 132, 132, 95, 95, 80, 132, 80, 129, 129, 129, 79, 79, 79, 91,
+    91, 91, 91, 91, 91, 91, 127, 127, 128, 128, 128, 128, 127, 127, 127, 127, 126, 126, 126, 126,
+    68, 68, 68, 93, 93, 93, 93, 95, 95, 95, 120, 120, 129, 129, 129, 129, 129, 129, 129, 101,
+    101, 101, 101, 101, 101, 101, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126, 126, 126,
+    68, 68, 93, 93, 93, 93, 93, 95, 95, 95, 120, 120, 120, 129, 129, 129, 129, 129, 129, 101,
+    101, 101, 101, 101, 101, 130, 130, 127, 127, 127, 127, 127, 127, 121, 121, 121, 126, 126, 126, 126,
+    68, 68, 93, 93, 93, 93, 93, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129, 129, 101,
+    101, 101, 101, 101, 130, 130, 130, 113, 127, 127, 127, 121, 121, 121, 121, 121, 96, 126, 126, 126,
+    68, 68, 68, 93, 93, 93, 93, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129, 101,
+    101, 101, 101, 130, 130, 130, 113, 113, 113, 121, 121, 121, 121, 121, 121, 121, 96, 126, 126, 126,
+    68, 68, 68, 93, 93, 93, 93, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129, 101,
+    101, 101, 130, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 96, 96, 96, 96, 126, 126,
+    68, 68, 68, 93, 93, 93, 120, 120, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129,
+    101, 130, 130, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 121, 96, 96, 126,
+    68, 68, 68, 93, 93, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117,
+    130, 130, 130, 130, 130, 113, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 96, 96, 96, 96,
+    68, 68, 68, 93, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 117,
+    117, 130, 130, 130, 130, 113, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 96, 96, 98, 98,
+    68, 68, 68, 93, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 117,
+    117, 106, 130, 130, 130, 113, 113, 113, 113, 113, 113, 113, 99, 99, 99, 99, 98, 98, 98, 98,
+    68, 68, 68, 93, 131, 97, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 113, 113, 113, 113, 113, 113, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98,
+    68, 68, 68, 87, 131, 97, 97, 97, 120, 120, 120, 120, 120, 120, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 113, 113, 113, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    68, 68, 68, 87, 131, 118, 118, 97, 97, 97, 120, 120, 120, 120, 117, 117, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 113, 136, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98,
+    68, 68, 68, 87, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 117, 117, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 99, 99, 99, 99, 99, 99, 99, 98, 98,
+    68, 68, 68, 87, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 99, 99, 99, 99, 99, 99, 99, 133, 133,
+    68, 68, 68, 87, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 99, 99, 99, 99, 99, 99, 99, 133, 133,
+    68, 68, 68, 87, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 136, 102, 102, 102, 99, 99, 99, 99, 102, 133, 133, 133,
+    68, 68, 68, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 133, 133,
+    68, 68, 68, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 106, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 133,
+    68, 68, 68, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88,
+    88, 106, 106, 106, 106, 108, 108, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 114, 114,
+    68, 68, 68, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88,
+    108, 108, 108, 108, 108, 108, 108, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 114, 114, 114,
+    87, 87, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 89, 108,
+    108, 108, 108, 108, 108, 108, 108, 103, 103, 102, 102, 102, 102, 102, 102, 102, 114, 114, 114, 114,
+    87, 87, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 89, 89, 89, 137,
+    108, 108, 108, 108, 108, 108, 108, 103, 103, 103, 102, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    122, 87, 87, 87, 118, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 89, 89, 89, 137,
+    108, 108, 108, 108, 108, 108, 108, 103, 103, 103, 102, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 89, 89, 89, 89,
+    108, 108, 108, 108, 108, 108, 108, 103, 103, 103, 103, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 89, 137,
+    108, 108, 108, 108, 108, 108, 108, 103, 103, 103, 103, 115, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 137,
+    137, 108, 108, 108, 108, 108, 108, 103, 103, 103, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110,
+    137, 108, 108, 108, 108, 108, 108, 103, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 110, 110, 110, 110, 110, 110, 110,
+    137, 108, 108, 108, 108, 108, 108, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 138, 138, 110, 110, 110, 110, 110, 110,
+    110, 108, 108, 108, 108, 108, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 138, 138, 138, 110, 110, 110, 139, 100,
+    100, 100, 108, 108, 108, 108, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 138, 138, 138, 110, 110, 110, 100, 100,
+    100, 100, 100, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 109, 109, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 134, 134, 138, 138, 138, 138, 139, 139, 139, 139, 124, 124,
+    124, 124, 124, 124, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 122, 134, 134, 134, 134, 138, 138, 139, 139, 139, 139, 124, 124, 124,
+    124, 124, 124, 124, 124, 140, 111, 115, 115, 115, 115, 115, 115, 115, 115, 115, 116, 135, 135, 135,
+    68, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 79,
+    91, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 141, 141, 141, 36,
+    68, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 91,
+    91, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 141, 141, 126, 126,
+    68, 68, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 91,
+    91, 143, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 141, 126, 126, 126,
+    68, 68, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 79, 91,
+    91, 143, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126,
+    68, 68, 68, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 79, 79, 79, 79, 79, 91,
+    91, 91, 91, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126,
+    68, 68, 68, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 129, 129, 79, 79, 79, 91,
+    91, 91, 91, 91, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126,
+    68, 68, 93, 93, 132, 132, 132, 132, 132, 132, 132, 132, 129, 129, 129, 129, 129, 129, 101, 101,
+    101, 101, 101, 101, 101, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 127, 126, 126, 126, 126,
+    68, 68, 93, 93, 144, 144, 144, 144, 144, 120, 120, 129, 129, 129, 129, 129, 129, 129, 129, 101,
+    101, 101, 101, 101, 130, 130, 130, 127, 128, 128, 128, 128, 128, 128, 128, 127, 126, 126, 126, 126,
+    68, 68, 93, 93, 144, 144, 144, 144, 144, 120, 120, 120, 129, 129, 129, 129, 129, 129, 129, 129,
+    101, 101, 101, 130, 130, 130, 130, 127, 127, 127, 127, 127, 121, 121, 121, 121, 126, 126, 126, 126,
+    68, 68, 93, 93, 144, 144, 144, 144, 120, 120, 120, 120, 129, 129, 129, 129, 129, 129, 129, 129,
+    101, 101, 101, 130, 130, 130, 130, 113, 127, 127, 121, 121, 121, 121, 121, 121, 126, 126, 126, 126,
+    68, 68, 68, 93, 93, 144, 144, 144, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129, 129, 129,
+    101, 130, 130, 130, 130, 130, 130, 113, 113, 121, 121, 121, 121, 121, 121, 121, 126, 126, 126, 126,
+    68, 68, 68, 93, 93, 144, 144, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129, 129,
+    130, 130, 130, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 96, 96, 126, 126,
+    68, 68, 68, 93, 131, 131, 144, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129, 129,
+    130, 130, 130, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 121, 96, 126, 126,
+    68, 68, 68, 93, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129,
+    130, 130, 130, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 121, 96, 126, 126,
+    68, 68, 68, 93, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117,
+    130, 130, 130, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 121, 96, 98, 98,
+    68, 68, 68, 93, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 117,
+    117, 130, 130, 130, 130, 130, 113, 113, 113, 113, 113, 136, 136, 136, 99, 99, 98, 98, 98, 98,
+    68, 68, 68, 93, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 130, 113, 113, 113, 113, 136, 136, 136, 136, 136, 136, 99, 98, 98, 98, 98,
+    68, 68, 68, 131, 131, 120, 97, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 113, 113, 136, 136, 136, 136, 136, 136, 136, 99, 99, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 97, 97, 120, 120, 120, 120, 120, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 99, 99, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 102, 102, 102, 133, 133, 133, 133,
+    68, 68, 68, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 102, 102, 102, 133, 133, 133, 133,
+    68, 68, 68, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 106, 102, 136, 136, 136, 136, 136, 102, 102, 102, 102, 102, 133, 133,
+    68, 68, 68, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 88, 88, 88, 88,
+    88, 106, 106, 106, 106, 108, 108, 102, 136, 136, 136, 136, 102, 102, 102, 102, 102, 102, 114, 133,
+    68, 68, 68, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 145, 88, 88, 88, 88, 137,
+    108, 108, 108, 108, 108, 108, 108, 103, 102, 136, 136, 136, 102, 102, 102, 102, 114, 114, 114, 114,
+    87, 87, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 88, 88, 137, 137,
+    108, 108, 108, 108, 108, 108, 108, 103, 103, 102, 102, 102, 102, 102, 102, 114, 114, 114, 114, 114,
+    122, 122, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 89, 137, 137, 137,
+    108, 108, 108, 108, 108, 108, 108, 103, 103, 102, 102, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 118, 107, 107, 107, 107, 107, 107, 107, 107, 145, 145, 110, 137, 137, 137, 137,
+    108, 108, 108, 108, 108, 108, 108, 103, 103, 103, 102, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 137, 137, 137, 137,
+    108, 108, 108, 108, 108, 108, 108, 103, 103, 103, 103, 102, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 107, 110, 110, 110, 137, 137, 137,
+    137, 108, 108, 108, 108, 108, 108, 103, 103, 103, 115, 115, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 107, 138, 110, 110, 110, 137, 137, 137,
+    137, 137, 108, 108, 108, 108, 108, 103, 103, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 138, 138, 110, 110, 110, 137, 137, 137,
+    137, 137, 108, 108, 108, 108, 108, 103, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 138, 138, 138, 110, 110, 110, 110, 137, 137,
+    137, 137, 108, 108, 108, 108, 108, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 138, 138, 138, 138, 110, 110, 139, 139, 137,
+    137, 137, 137, 108, 108, 108, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 109,
+    122, 122, 122, 122, 122, 122, 122, 122, 138, 138, 138, 138, 138, 138, 138, 110, 110, 139, 139, 137,
+    137, 137, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 122, 122, 122, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139,
+    137, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 122, 122, 134, 134, 138, 138, 138, 138, 139, 139, 139, 139, 139, 124,
+    124, 124, 124, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 122, 134, 134, 134, 134, 138, 138, 139, 139, 139, 139, 139, 139, 124,
+    124, 124, 124, 124, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135, 135,
+    142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143,
+    143, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 141, 141, 141, 141,
+    142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143,
+    143, 143, 125, 125, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 141, 141, 141, 126,
+    142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143,
+    143, 143, 125, 125, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 141, 141, 126, 126,
+    142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126,
+    142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 129, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126,
+    68, 68, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 129, 129, 129, 143, 79, 91,
+    91, 143, 143, 143, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126,
+    68, 68, 93, 142, 132, 132, 132, 132, 132, 132, 132, 132, 129, 129, 129, 129, 129, 129, 129, 129,
+    101, 101, 143, 143, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126,
+    68, 68, 93, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    101, 101, 101, 130, 130, 130, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126,
+    68, 68, 93, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    101, 101, 130, 130, 130, 130, 130, 127, 128, 128, 128, 128, 128, 128, 128, 128, 126, 126, 126, 126,
+    68, 68, 93, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    101, 130, 130, 130, 130, 130, 130, 113, 113, 121, 121, 128, 128, 128, 128, 146, 146, 126, 126, 126,
+    68, 68, 93, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 113, 113, 121, 121, 121, 121, 128, 146, 146, 146, 126, 126, 126,
+    68, 68, 68, 144, 144, 144, 144, 144, 144, 120, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 113, 113, 113, 113, 121, 121, 121, 121, 121, 126, 126, 126, 126,
+    68, 68, 68, 131, 144, 144, 144, 144, 144, 120, 120, 120, 120, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 121, 126, 126, 126,
+    68, 68, 68, 131, 131, 144, 144, 144, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129, 129,
+    129, 129, 130, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 121, 126, 126, 126,
+    68, 68, 68, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129,
+    130, 130, 130, 130, 130, 130, 113, 113, 113, 113, 113, 121, 121, 121, 121, 121, 121, 121, 133, 133,
+    68, 68, 68, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 117, 117, 117,
+    147, 130, 130, 130, 130, 130, 113, 113, 113, 113, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 130, 130, 113, 113, 113, 113, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 113, 113, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 120, 120, 120, 120, 120, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 88, 88, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 68, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 88, 88, 106, 106,
+    106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 102, 102, 136, 133, 133, 133, 133,
+    68, 68, 68, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 88, 88, 106,
+    106, 106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 102, 102, 102, 102, 133, 133, 133,
+    68, 68, 68, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 88, 88,
+    137, 106, 106, 106, 106, 108, 108, 102, 136, 136, 136, 136, 136, 102, 102, 102, 102, 133, 133, 133,
+    131, 131, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 137, 137,
+    137, 108, 108, 108, 108, 108, 108, 108, 136, 136, 136, 136, 102, 102, 102, 102, 114, 114, 114, 114,
+    87, 87, 87, 87, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 137, 137, 137,
+    137, 108, 108, 108, 108, 108, 108, 108, 136, 136, 136, 136, 102, 102, 102, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 137, 137, 137,
+    137, 108, 108, 108, 108, 108, 108, 108, 103, 102, 102, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 118, 118, 118, 118, 107, 107, 107, 107, 145, 145, 145, 145, 137, 137, 137, 137,
+    137, 108, 108, 108, 108, 108, 108, 108, 103, 103, 102, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 138, 138, 145, 137, 137, 137, 137, 137,
+    137, 137, 108, 108, 108, 108, 108, 108, 103, 103, 103, 102, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 107, 107, 107, 107, 107, 107, 138, 138, 138, 137, 137, 137, 137, 137,
+    137, 137, 108, 108, 108, 108, 108, 108, 103, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 107, 107, 107, 138, 138, 138, 138, 138, 137, 137, 137, 137, 137,
+    137, 137, 108, 108, 108, 108, 108, 108, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 138, 138, 138, 138, 138, 138, 138, 137, 137, 137, 137, 137, 137,
+    137, 137, 137, 108, 108, 108, 108, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 122, 138, 138, 138, 138, 138, 138, 137, 137, 137, 137, 137, 137,
+    137, 137, 137, 108, 108, 108, 108, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 122, 138, 138, 138, 138, 138, 138, 138, 137, 137, 139, 139, 137,
+    137, 137, 137, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 135,
+    122, 122, 122, 122, 122, 122, 122, 122, 148, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 137,
+    137, 149, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 122, 122, 148, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139,
+    137, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 122, 148, 148, 134, 138, 138, 138, 138, 139, 139, 139, 139, 139, 139,
+    139, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 122, 134, 134, 134, 134, 138, 138, 139, 139, 139, 139, 139, 139, 139,
+    124, 124, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 150, 150, 135, 135, 135, 135,
+    142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 125, 125, 125, 125, 125, 125, 125, 125, 125, 151, 151, 151, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 141, 141, 141, 141,
+    142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 141, 141, 141, 141,
+    142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 141, 126, 141, 126,
+    142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 129, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 141, 141, 126, 126,
+    142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 129, 129, 129, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 141, 126, 126, 126,
+    142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 129, 129, 129, 129, 129, 129, 129, 129,
+    143, 143, 143, 143, 143, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 141, 126, 126, 126,
+    142, 142, 142, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 143, 143, 130, 130, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 141, 126, 126, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 128, 128, 128, 128, 128, 128, 128, 128, 128, 146, 126, 126, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 130, 113, 128, 128, 128, 128, 128, 146, 146, 146, 126, 126, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 113, 113, 121, 121, 121, 128, 128, 146, 146, 146, 126, 126, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 113, 113, 113, 121, 121, 121, 121, 121, 146, 146, 126, 126, 126,
+    144, 144, 131, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 113, 113, 113, 121, 121, 121, 121, 121, 146, 146, 126, 126, 126,
+    144, 144, 131, 131, 131, 144, 144, 144, 144, 144, 120, 120, 120, 129, 129, 129, 129, 129, 129, 129,
+    129, 129, 130, 130, 130, 130, 113, 113, 113, 113, 121, 121, 121, 121, 121, 146, 146, 146, 126, 126,
+    68, 68, 131, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 129, 129, 129,
+    152, 152, 130, 130, 130, 130, 113, 113, 113, 113, 113, 136, 136, 136, 121, 121, 121, 121, 133, 133,
+    68, 68, 131, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 129, 129, 129, 147, 147, 147,
+    147, 147, 130, 130, 130, 130, 113, 113, 113, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 120, 120, 120, 120, 120, 120, 120, 120, 120, 117, 117, 117, 147, 147, 147,
+    147, 147, 147, 130, 130, 113, 113, 113, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 131, 131, 131, 131, 120, 120, 120, 120, 120, 117, 117, 147, 147, 147, 147,
+    147, 147, 147, 106, 106, 113, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 118, 118, 118, 118, 120, 120, 120, 120, 120, 117, 147, 147, 147, 147, 147,
+    147, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 118, 117, 117, 117, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 106, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 106, 106, 106,
+    106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 106, 106,
+    106, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    131, 131, 131, 131, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 153, 153,
+    153, 153, 106, 106, 106, 106, 154, 136, 136, 136, 136, 136, 136, 136, 136, 136, 155, 133, 133, 133,
+    131, 131, 131, 131, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 153, 153,
+    153, 153, 108, 108, 106, 108, 156, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 133, 133,
+    131, 131, 131, 131, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 153, 137,
+    137, 108, 108, 108, 108, 108, 156, 154, 136, 136, 136, 136, 136, 136, 102, 155, 155, 155, 155, 133,
+    157, 157, 122, 157, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137,
+    137, 108, 108, 108, 108, 108, 156, 156, 136, 136, 136, 136, 136, 102, 102, 114, 114, 114, 114, 155,
+    157, 157, 122, 122, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137, 137,
+    137, 108, 137, 108, 108, 108, 156, 156, 156, 102, 102, 102, 102, 114, 114, 114, 114, 114, 114, 114,
+    157, 157, 122, 122, 122, 118, 118, 118, 107, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137, 137,
+    137, 137, 137, 108, 108, 108, 156, 156, 156, 156, 102, 102, 114, 114, 114, 114, 114, 114, 114, 114,
+    157, 157, 122, 122, 122, 157, 157, 107, 107, 107, 107, 107, 138, 145, 145, 137, 137, 137, 137, 137,
+    137, 137, 137, 108, 108, 108, 156, 156, 156, 156, 156, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 157, 107, 107, 107, 107, 107, 138, 138, 138, 137, 137, 137, 137, 137,
+    137, 137, 137, 108, 108, 108, 108, 156, 156, 156, 115, 115, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 138, 138, 138, 138, 138, 138, 138, 139, 137, 137, 137, 137, 137,
+    137, 137, 137, 108, 108, 108, 108, 108, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 138, 138, 138, 138, 138, 138, 138, 139, 139, 137, 137, 137, 137,
+    137, 137, 137, 137, 108, 140, 140, 140, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 148, 138, 138, 138, 138, 138, 138, 139, 139, 139, 137, 137, 137,
+    137, 137, 137, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 122, 148, 138, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 137,
+    149, 149, 149, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 114, 135, 135,
+    122, 122, 122, 122, 122, 122, 122, 148, 148, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 137,
+    149, 149, 140, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 122, 148, 148, 148, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139,
+    149, 149, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 148, 148, 148, 148, 138, 138, 138, 138, 139, 139, 139, 139, 139, 139,
+    139, 140, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 148, 134, 134, 134, 134, 138, 138, 139, 139, 139, 139, 139, 139, 139,
+    139, 139, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 150, 150, 150, 150, 135, 135, 135, 135,
+    142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 125, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 151, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 158, 129, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 158, 158, 129, 129, 129, 143, 143, 143,
+    143, 143, 143, 143, 143, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 126,
+    142, 142, 142, 142, 142, 142, 132, 132, 132, 132, 158, 158, 158, 129, 129, 129, 129, 129, 143, 143,
+    143, 143, 143, 143, 143, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 126,
+    142, 142, 142, 142, 144, 144, 144, 144, 144, 144, 144, 158, 129, 129, 129, 129, 129, 129, 129, 129,
+    143, 143, 143, 143, 143, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 146, 141, 126, 126,
+    144, 142, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 128, 128, 128, 128, 128, 128, 128, 128, 128, 146, 146, 126, 126, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 130, 128, 128, 128, 128, 128, 128, 146, 146, 146, 146, 126, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 130, 113, 121, 121, 128, 128, 146, 146, 146, 146, 146, 126, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 113, 113, 113, 121, 121, 121, 146, 146, 146, 146, 146, 126, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 152, 130, 130, 130, 130, 130, 113, 113, 113, 121, 121, 121, 146, 146, 146, 146, 146, 126, 126,
+    144, 144, 131, 131, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 152, 130, 130, 130, 130, 130, 113, 113, 113, 121, 121, 121, 146, 146, 146, 146, 146, 146, 126,
+    144, 144, 131, 131, 131, 144, 144, 144, 144, 144, 144, 120, 129, 129, 129, 129, 129, 152, 152, 152,
+    152, 152, 130, 130, 130, 130, 113, 113, 113, 113, 136, 136, 136, 136, 121, 121, 121, 133, 133, 126,
+    68, 68, 131, 131, 131, 120, 144, 144, 144, 144, 144, 120, 120, 129, 129, 152, 147, 147, 147, 147,
+    147, 147, 147, 130, 130, 130, 113, 113, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 131, 131, 131, 144, 144, 120, 120, 120, 120, 129, 152, 147, 147, 147, 147,
+    147, 147, 147, 147, 130, 130, 113, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 131, 131, 131, 131, 131, 131, 131, 131, 131, 120, 159, 159, 159, 152, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 147, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 118, 118, 118, 118, 118, 160, 159, 118, 145, 159, 159, 147, 147, 147, 147,
+    147, 147, 147, 147, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 118, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 147, 147, 147, 147,
+    147, 147, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 118, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 147, 147, 147, 147,
+    106, 106, 106, 106, 106, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 153, 147, 106,
+    106, 106, 106, 106, 153, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 118, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 153, 153, 153,
+    106, 106, 106, 106, 153, 154, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 145, 153, 153,
+    153, 153, 153, 153, 153, 154, 154, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 133, 133, 133,
+    160, 160, 160, 160, 160, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 145, 153, 153,
+    153, 153, 153, 153, 154, 154, 154, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 133, 133,
+    157, 157, 157, 131, 118, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 145, 145, 153, 137,
+    137, 137, 153, 153, 154, 154, 154, 154, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137,
+    137, 137, 153, 154, 154, 154, 156, 156, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 118, 118, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137,
+    137, 137, 137, 154, 154, 156, 156, 156, 156, 136, 136, 136, 136, 136, 155, 155, 114, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137, 137,
+    137, 137, 137, 137, 156, 156, 156, 156, 156, 156, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+    157, 157, 157, 157, 157, 157, 157, 145, 145, 107, 138, 138, 145, 145, 145, 137, 137, 137, 137, 137,
+    137, 137, 137, 137, 108, 156, 156, 156, 156, 156, 156, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 138, 137, 137, 137, 137, 137,
+    137, 137, 137, 137, 108, 156, 156, 156, 156, 156, 156, 115, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 157, 157, 157, 138, 138, 138, 138, 138, 138, 138, 137, 137, 137, 137, 137,
+    137, 137, 137, 137, 137, 156, 156, 156, 156, 156, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 157, 157, 138, 138, 138, 138, 138, 138, 138, 138, 137, 137, 137, 137,
+    137, 137, 149, 149, 140, 156, 156, 156, 156, 156, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 122, 122, 148, 148, 138, 138, 138, 138, 138, 138, 138, 138, 137, 137, 137, 137,
+    149, 149, 149, 149, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 161,
+    122, 122, 122, 122, 122, 122, 148, 148, 148, 138, 138, 138, 138, 138, 138, 139, 139, 139, 149, 149,
+    149, 149, 149, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 115, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 148, 148, 148, 138, 138, 138, 138, 138, 138, 139, 139, 139, 149, 149,
+    149, 149, 140, 140, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 135, 135, 135, 135,
+    122, 122, 122, 122, 122, 122, 148, 148, 148, 148, 138, 138, 138, 138, 138, 139, 139, 139, 139, 149,
+    149, 149, 140, 140, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 135, 135, 135, 135,
+    122, 122, 122, 122, 122, 148, 148, 148, 148, 148, 148, 138, 138, 138, 139, 139, 139, 139, 139, 139,
+    139, 140, 140, 140, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 135, 135, 135, 135, 135,
+    122, 122, 122, 122, 122, 148, 148, 148, 148, 148, 148, 138, 138, 139, 139, 139, 139, 139, 139, 139,
+    139, 140, 140, 140, 140, 140, 140, 140, 140, 115, 115, 150, 150, 150, 150, 150, 135, 135, 135, 135,
+    142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 125, 125, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 143, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 132, 132, 132, 158, 158, 158, 158, 158, 158, 129, 143, 143, 143,
+    143, 143, 143, 143, 143, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 132, 158, 158, 158, 158, 158, 158, 158, 158, 129, 143, 143, 143,
+    143, 143, 143, 143, 143, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 144, 144, 144, 144, 158, 158, 158, 158, 129, 129, 129, 129, 129, 129, 143,
+    143, 143, 143, 143, 143, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 146, 141, 141, 126,
+    144, 142, 142, 144, 144, 144, 144, 144, 144, 144, 144, 158, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 143, 143, 143, 143, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 146, 146, 146, 141, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 128, 128, 128, 128, 128, 128, 128, 128, 146, 146, 146, 146, 146, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 130, 128, 128, 128, 128, 128, 146, 146, 146, 146, 146, 146, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    129, 130, 130, 130, 130, 130, 130, 130, 113, 128, 128, 128, 146, 146, 146, 146, 146, 146, 146, 126,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129,
+    129, 152, 130, 130, 130, 130, 130, 113, 113, 113, 121, 121, 146, 146, 146, 146, 146, 146, 146, 126,
+    144, 144, 131, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 152, 152, 129,
+    129, 152, 130, 130, 130, 130, 130, 113, 113, 113, 121, 121, 146, 146, 146, 146, 146, 146, 146, 146,
+    144, 144, 131, 131, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 152, 152, 152, 152, 152,
+    152, 152, 152, 130, 130, 130, 130, 113, 113, 136, 136, 136, 136, 136, 136, 136, 136, 146, 146, 146,
+    144, 131, 131, 131, 131, 131, 131, 144, 144, 144, 144, 144, 159, 129, 129, 152, 152, 152, 147, 147,
+    147, 147, 147, 147, 130, 130, 113, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 144, 159, 159, 159, 159, 152, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 152, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 152, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 160, 118, 118, 118, 160, 159, 159, 159, 159, 159, 159, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 160, 118, 118, 118, 118, 159, 159, 159, 159, 159, 162, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 160, 118, 118, 118, 118, 145, 145, 145, 145, 145, 162, 162, 147, 147, 147,
+    147, 147, 147, 153, 153, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 160, 118, 118, 118, 118, 145, 145, 145, 145, 145, 145, 162, 153, 153, 147,
+    147, 147, 147, 153, 153, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 162, 153, 153, 153,
+    153, 153, 153, 153, 153, 154, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 145, 162, 153, 153,
+    153, 153, 153, 153, 153, 154, 154, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 133, 133,
+    157, 157, 157, 160, 160, 160, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 145, 145, 153, 153,
+    153, 153, 153, 153, 154, 154, 154, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 133,
+    157, 157, 157, 157, 157, 118, 118, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 153, 153,
+    153, 153, 153, 153, 154, 154, 154, 154, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 118, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 137,
+    153, 153, 153, 154, 154, 154, 154, 154, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137,
+    137, 137, 137, 154, 154, 156, 156, 156, 156, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137,
+    137, 137, 137, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137, 137,
+    137, 137, 137, 156, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 114, 114, 114, 114, 114, 155,
+    122, 122, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 138, 137, 137, 137, 137, 137,
+    137, 137, 137, 149, 156, 156, 156, 156, 156, 156, 156, 156, 114, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 138, 137, 137, 137, 137,
+    137, 149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 115, 114, 114, 114, 114, 114, 114, 114,
+    122, 122, 122, 122, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 138, 137, 137, 149, 149,
+    149, 149, 149, 149, 140, 156, 156, 156, 156, 156, 156, 115, 115, 115, 114, 114, 114, 114, 114, 161,
+    122, 122, 122, 122, 122, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 138, 149, 149, 149, 149,
+    149, 149, 149, 149, 140, 140, 140, 140, 156, 156, 115, 115, 115, 115, 115, 115, 114, 114, 163, 161,
+    122, 122, 122, 122, 122, 148, 148, 148, 148, 138, 138, 138, 138, 138, 138, 139, 139, 139, 149, 149,
+    149, 149, 149, 140, 140, 140, 140, 140, 140, 140, 115, 115, 115, 115, 115, 115, 115, 135, 135, 161,
+    122, 122, 122, 122, 122, 148, 148, 148, 148, 148, 138, 138, 138, 138, 138, 139, 139, 139, 149, 149,
+    149, 149, 149, 140, 140, 140, 140, 140, 140, 140, 140, 115, 115, 115, 164, 135, 135, 135, 135, 135,
+    122, 122, 122, 122, 122, 148, 148, 148, 148, 148, 138, 138, 138, 138, 138, 139, 139, 139, 139, 149,
+    149, 149, 140, 140, 140, 140, 140, 140, 140, 140, 140, 115, 115, 150, 150, 135, 135, 135, 135, 135,
+    122, 122, 122, 122, 148, 148, 148, 148, 148, 148, 148, 138, 138, 138, 139, 139, 139, 139, 139, 139,
+    149, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 150, 150, 150, 150, 135, 135, 135, 135, 135,
+    122, 122, 122, 122, 148, 148, 148, 148, 148, 148, 148, 148, 138, 139, 139, 139, 139, 139, 139, 139,
+    139, 140, 140, 140, 140, 140, 140, 140, 140, 140, 150, 150, 150, 150, 150, 150, 135, 135, 135, 135,
+    142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 125, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 125, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 125, 125, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 132, 132, 132, 158, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 125, 125, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 132, 132, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 143, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 143, 125, 125, 128, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 158, 129, 143, 143, 143,
+    143, 143, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 144, 144, 144, 158, 158, 158, 158, 158, 158, 158, 129, 129, 129, 129, 143,
+    143, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 146, 146, 141, 141, 141,
+    142, 142, 142, 144, 144, 144, 144, 144, 144, 144, 158, 158, 158, 158, 129, 129, 129, 129, 129, 129,
+    129, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 128, 146, 146, 146, 146, 141, 141,
+    142, 142, 144, 144, 144, 144, 144, 144, 144, 144, 144, 158, 158, 129, 129, 129, 129, 129, 129, 129,
+    129, 129, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 146, 146, 146, 146, 146, 146, 141,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 129, 129, 129,
+    152, 152, 130, 130, 130, 128, 128, 128, 128, 128, 128, 128, 146, 146, 146, 146, 146, 146, 146, 146,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 129, 129, 129, 129, 129, 152, 152,
+    152, 152, 152, 130, 130, 130, 130, 130, 128, 128, 128, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 165, 165, 129, 129, 129, 152, 152, 152, 152,
+    152, 152, 152, 130, 130, 130, 130, 130, 113, 128, 128, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 165, 165, 129, 152, 152, 152, 152, 152, 129,
+    152, 152, 152, 152, 130, 130, 130, 113, 113, 113, 136, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 165, 165, 129, 152, 152, 152, 152, 152, 152,
+    152, 152, 147, 147, 130, 130, 130, 113, 136, 136, 136, 136, 136, 136, 136, 136, 146, 146, 146, 146,
+    131, 131, 144, 144, 144, 131, 144, 144, 144, 144, 144, 159, 159, 159, 159, 152, 152, 152, 152, 147,
+    147, 147, 147, 147, 147, 147, 130, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 144, 159, 159, 159, 159, 159, 159, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 160, 118, 118, 118, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 160, 118, 118, 118, 159, 159, 159, 159, 159, 159, 162, 162, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    68, 68, 160, 160, 160, 160, 118, 118, 118, 145, 159, 159, 159, 159, 162, 162, 162, 162, 153, 147,
+    147, 147, 147, 153, 153, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 118, 118, 118, 145, 145, 145, 145, 145, 162, 162, 162, 162, 153, 153,
+    153, 147, 147, 153, 153, 166, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 118, 118, 118, 145, 145, 145, 145, 145, 145, 162, 162, 162, 153, 153,
+    153, 153, 153, 153, 153, 154, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 133, 133, 133,
+    157, 157, 157, 157, 160, 160, 118, 118, 118, 145, 145, 145, 145, 145, 145, 162, 162, 162, 153, 153,
+    153, 153, 153, 153, 154, 154, 154, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 133,
+    157, 157, 157, 157, 157, 160, 118, 118, 118, 145, 145, 145, 145, 145, 145, 145, 162, 153, 153, 153,
+    153, 153, 153, 153, 154, 154, 154, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 133,
+    157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 153, 153,
+    153, 153, 153, 153, 154, 154, 154, 154, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 153, 153,
+    153, 153, 153, 154, 154, 154, 154, 154, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137,
+    153, 153, 154, 154, 154, 154, 156, 156, 156, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137,
+    137, 137, 154, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137, 137,
+    137, 137, 149, 156, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 137, 137, 137, 137, 137,
+    149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 155, 155, 155,
+    122, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 138, 137, 137, 149, 149,
+    149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 155, 161,
+    122, 122, 122, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 149, 149, 149, 149,
+    149, 149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 156, 115, 114, 114, 163, 163, 163, 163,
+    122, 122, 122, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 149, 149, 149, 149,
+    149, 149, 149, 149, 140, 140, 156, 156, 156, 156, 156, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    122, 122, 122, 157, 148, 148, 148, 148, 148, 148, 138, 138, 138, 138, 138, 149, 149, 149, 149, 149,
+    149, 149, 149, 140, 140, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    122, 122, 122, 122, 148, 148, 148, 148, 148, 148, 138, 138, 138, 138, 138, 139, 139, 139, 149, 149,
+    149, 149, 149, 140, 140, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 164, 163, 163, 163, 135,
+    122, 122, 122, 122, 148, 148, 148, 148, 148, 148, 148, 138, 138, 138, 138, 139, 139, 139, 149, 149,
+    149, 149, 140, 140, 140, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 164, 167, 167, 135, 135,
+    122, 122, 122, 148, 148, 148, 148, 148, 148, 148, 148, 138, 138, 138, 139, 139, 139, 139, 139, 139,
+    149, 149, 140, 140, 140, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 135, 135, 135, 135, 135,
+    122, 122, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 138, 139, 139, 139, 139, 139, 139, 139,
+    139, 140, 140, 140, 140, 140, 140, 140, 140, 140, 150, 150, 150, 164, 168, 167, 167, 135, 135, 135,
+    142, 142, 142, 142, 142, 142, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 143, 143, 143, 143,
+    143, 143, 143, 125, 125, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 132, 132, 132, 132, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 132, 132, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 125, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 143, 125, 125, 128, 128, 128, 128, 128, 128, 128, 151, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 143, 125, 125, 128, 128, 128, 128, 128, 128, 128, 169, 141, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 128, 169, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 128, 169, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 144, 144, 158, 158, 158, 158, 158, 158, 158, 158, 129, 129, 129, 143,
+    143, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 146, 146, 141, 141, 141,
+    142, 142, 142, 142, 144, 144, 144, 144, 144, 158, 158, 158, 158, 158, 158, 129, 129, 129, 129, 129,
+    129, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 128, 146, 146, 146, 146, 141, 141,
+    142, 142, 144, 144, 144, 144, 144, 144, 144, 144, 165, 158, 158, 158, 129, 129, 129, 129, 129, 129,
+    152, 152, 143, 143, 143, 170, 128, 128, 128, 128, 128, 128, 128, 146, 146, 146, 146, 146, 146, 141,
+    142, 144, 144, 144, 144, 144, 144, 144, 144, 144, 165, 165, 158, 158, 129, 129, 129, 129, 152, 152,
+    152, 152, 152, 152, 170, 170, 170, 128, 128, 128, 128, 128, 146, 146, 146, 146, 146, 146, 146, 146,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 165, 165, 165, 165, 129, 129, 129, 152, 152, 152, 152,
+    152, 152, 152, 152, 170, 170, 170, 170, 128, 128, 128, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 165, 165, 165, 165, 129, 152, 152, 152, 152, 152, 152,
+    152, 152, 152, 152, 130, 170, 170, 170, 170, 128, 128, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    160, 160, 144, 144, 144, 144, 144, 144, 144, 165, 165, 165, 165, 165, 152, 152, 152, 152, 152, 152,
+    152, 152, 152, 152, 171, 130, 130, 170, 170, 136, 136, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    160, 160, 160, 144, 144, 144, 144, 144, 144, 165, 165, 165, 165, 159, 152, 152, 152, 152, 152, 152,
+    152, 152, 152, 147, 147, 147, 130, 170, 136, 136, 136, 136, 136, 136, 136, 146, 146, 146, 146, 146,
+    160, 160, 160, 144, 144, 144, 144, 144, 144, 165, 165, 159, 159, 159, 159, 152, 152, 152, 152, 152,
+    147, 147, 147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 152, 147, 147, 147,
+    147, 147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 118, 118, 159, 159, 159, 159, 159, 159, 159, 159, 162, 147, 147, 147,
+    147, 147, 147, 147, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 118, 118, 159, 159, 159, 159, 159, 159, 162, 162, 162, 162, 153, 153,
+    153, 147, 147, 153, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 155, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 118, 118, 159, 159, 159, 159, 162, 162, 162, 162, 162, 162, 153, 153,
+    153, 153, 153, 153, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 133, 133, 133, 133,
+    157, 157, 157, 157, 160, 160, 118, 118, 118, 145, 145, 145, 145, 162, 162, 162, 162, 162, 153, 153,
+    153, 153, 153, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 133, 133,
+    157, 157, 157, 157, 157, 160, 118, 118, 118, 145, 145, 145, 145, 145, 162, 162, 162, 162, 153, 153,
+    153, 153, 153, 166, 166, 154, 154, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 133,
+    157, 157, 157, 157, 157, 160, 145, 145, 145, 145, 145, 145, 145, 145, 145, 162, 162, 153, 153, 153,
+    153, 153, 153, 153, 154, 154, 154, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 162, 162, 153, 153,
+    153, 153, 153, 153, 154, 154, 154, 154, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 162, 153, 153,
+    153, 153, 153, 154, 154, 154, 154, 154, 154, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 145, 162, 153, 153,
+    153, 153, 154, 154, 154, 154, 154, 154, 156, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 145, 137, 137, 137,
+    149, 149, 154, 154, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 172, 172, 172, 145, 137, 137, 137, 149,
+    149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 172, 172, 172, 137, 149, 149, 149, 149,
+    149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 149, 149, 149, 149,
+    149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 149, 149, 149, 149,
+    149, 149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 138, 149, 149, 149, 149,
+    149, 149, 149, 149, 156, 156, 156, 156, 156, 156, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    122, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 149, 149, 149, 149, 149,
+    149, 149, 149, 149, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    122, 122, 157, 148, 148, 148, 148, 148, 148, 148, 148, 138, 138, 138, 138, 139, 149, 149, 149, 149,
+    149, 149, 149, 140, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 164, 164, 167, 167, 163, 163,
+    122, 122, 148, 148, 148, 148, 148, 148, 148, 148, 148, 138, 138, 138, 138, 139, 139, 139, 149, 149,
+    149, 149, 140, 140, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 164, 164, 167, 167, 163, 163,
+    122, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 138, 138, 139, 139, 139, 139, 139, 149,
+    149, 149, 140, 140, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 164, 164, 167, 167, 135, 135,
+    122, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 138, 139, 139, 139, 139, 139, 139, 139,
+    139, 140, 140, 140, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 168, 168, 167, 167, 135, 135,
+    142, 142, 142, 142, 142, 142, 142, 142, 132, 132, 158, 158, 158, 132, 132, 173, 143, 143, 143, 143,
+    143, 143, 143, 125, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 125, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 151, 169, 169, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 169, 169, 141, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 174, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 143, 143, 128, 128, 128, 128, 128, 128, 128, 128, 169, 169, 169, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 174, 174, 174, 158, 158, 158, 158, 158, 158, 158, 129, 129, 129, 143,
+    143, 143, 143, 143, 143, 170, 128, 128, 128, 128, 128, 128, 128, 128, 146, 169, 169, 141, 141, 141,
+    142, 142, 142, 142, 142, 144, 174, 174, 174, 174, 158, 158, 158, 158, 158, 158, 129, 129, 171, 171,
+    152, 143, 143, 143, 170, 170, 170, 128, 128, 128, 128, 128, 128, 146, 146, 146, 146, 146, 141, 141,
+    142, 142, 144, 144, 144, 144, 165, 165, 165, 165, 174, 158, 158, 158, 158, 129, 129, 152, 171, 171,
+    152, 152, 143, 143, 170, 170, 170, 170, 128, 128, 128, 128, 146, 146, 146, 146, 146, 146, 146, 141,
+    142, 144, 144, 144, 144, 144, 144, 165, 165, 165, 165, 165, 158, 158, 129, 152, 152, 152, 152, 152,
+    152, 152, 152, 171, 170, 170, 170, 170, 170, 128, 128, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    144, 144, 144, 144, 144, 144, 144, 165, 165, 165, 165, 165, 165, 129, 152, 152, 152, 152, 152, 152,
+    152, 152, 171, 171, 170, 170, 170, 170, 170, 170, 128, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    144, 144, 144, 144, 144, 144, 144, 165, 165, 165, 165, 165, 165, 165, 152, 152, 152, 152, 152, 152,
+    152, 152, 152, 171, 171, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    160, 160, 144, 144, 144, 144, 144, 165, 165, 165, 165, 165, 165, 165, 152, 152, 152, 152, 152, 152,
+    152, 152, 152, 171, 171, 171, 170, 170, 170, 170, 136, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+    160, 160, 160, 144, 144, 144, 144, 165, 165, 165, 165, 165, 165, 159, 152, 152, 152, 152, 152, 152,
+    152, 152, 152, 171, 171, 171, 171, 170, 136, 136, 136, 136, 136, 136, 146, 146, 146, 146, 146, 146,
+    160, 160, 160, 144, 144, 144, 144, 165, 165, 165, 165, 159, 159, 159, 159, 152, 152, 152, 152, 152,
+    152, 147, 147, 147, 171, 171, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 146,
+    160, 160, 160, 160, 160, 160, 160, 165, 165, 159, 159, 159, 159, 159, 159, 159, 152, 152, 147, 147,
+    147, 147, 147, 147, 147, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 118, 159, 159, 159, 159, 159, 159, 159, 159, 159, 162, 162, 147, 147,
+    147, 147, 147, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    157, 157, 157, 160, 160, 160, 118, 118, 159, 159, 159, 159, 159, 159, 159, 159, 162, 162, 153, 153,
+    153, 153, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 155, 133, 133, 133, 133,
+    157, 157, 157, 157, 160, 160, 118, 118, 159, 159, 159, 159, 159, 162, 162, 162, 162, 162, 153, 153,
+    153, 153, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 133, 133, 133,
+    157, 157, 157, 157, 175, 160, 118, 118, 118, 159, 159, 162, 162, 162, 162, 162, 162, 162, 153, 153,
+    153, 153, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 133,
+    157, 157, 157, 157, 157, 160, 145, 145, 145, 145, 145, 145, 162, 162, 162, 162, 162, 162, 153, 153,
+    153, 153, 166, 166, 166, 154, 154, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 162, 162, 162, 162, 176, 176, 153,
+    153, 153, 153, 166, 154, 154, 154, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 145, 145, 145, 145, 162, 162, 162, 176, 153, 153,
+    153, 153, 153, 166, 154, 154, 154, 154, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 172, 145, 145, 145, 145, 145, 145, 145, 162, 162, 162, 153, 153,
+    153, 153, 153, 154, 154, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 172, 145, 145, 145, 145, 145, 145, 162, 162, 162, 153, 153,
+    153, 153, 154, 154, 154, 154, 154, 154, 154, 177, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 172, 145, 145, 145, 145, 145, 145, 145, 162, 162, 153, 153,
+    153, 153, 154, 154, 154, 154, 177, 177, 177, 156, 156, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 172, 172, 172, 172, 178, 149, 149, 149,
+    149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 172, 172, 172, 178, 178, 149, 149, 149,
+    149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 155, 155, 155, 155, 155, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 178, 149, 149, 149, 149,
+    149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 156, 156, 164, 164, 155, 155, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 138, 149, 149, 149, 149, 149,
+    149, 149, 149, 149, 156, 156, 156, 156, 156, 156, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 149, 149, 149, 149, 149,
+    149, 149, 149, 149, 156, 156, 156, 156, 156, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 149, 149, 149, 149, 149,
+    149, 149, 149, 149, 140, 140, 140, 140, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 138, 138, 149, 149, 149, 149, 149,
+    149, 149, 149, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 163, 163,
+    179, 179, 148, 148, 148, 148, 148, 148, 148, 148, 148, 138, 138, 138, 138, 139, 139, 139, 149, 149,
+    149, 149, 149, 140, 140, 140, 140, 140, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 163,
+    180, 180, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 138, 138, 139, 139, 139, 139, 139, 181,
+    149, 149, 140, 140, 140, 140, 140, 182, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 183,
+    180, 180, 180, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 139, 139, 139, 139, 139, 139, 181,
+    181, 181, 140, 140, 140, 140, 140, 182, 164, 164, 164, 164, 164, 164, 164, 168, 167, 167, 167, 167,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 132, 132, 173, 173, 143, 143, 143, 143,
+    143, 143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 173, 143, 143, 143, 143,
+    143, 143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 173, 143, 143, 143, 143,
+    143, 143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 143, 170, 170, 170, 128, 128, 128, 128, 151, 151, 151, 169, 169, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 174, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 143, 170, 128, 128, 128, 128, 128, 128, 128, 169, 169, 169, 169, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 174, 174, 174, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 143, 184, 170, 170, 128, 128, 128, 128, 128, 128, 169, 169, 169, 169, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 174, 174, 174, 174, 158, 158, 158, 158, 158, 158, 158, 129, 129, 143,
+    143, 143, 143, 143, 170, 170, 170, 170, 128, 128, 128, 128, 128, 146, 146, 169, 169, 141, 141, 185,
+    142, 142, 142, 142, 142, 174, 174, 174, 174, 174, 158, 158, 158, 158, 158, 158, 158, 152, 171, 171,
+    171, 171, 143, 170, 170, 170, 170, 170, 170, 128, 128, 128, 128, 146, 146, 146, 146, 146, 141, 185,
+    142, 142, 142, 144, 165, 165, 165, 165, 165, 165, 174, 158, 158, 158, 158, 158, 152, 152, 171, 171,
+    171, 171, 171, 170, 170, 170, 170, 170, 170, 128, 128, 128, 146, 146, 146, 146, 146, 146, 141, 185,
+    142, 142, 144, 144, 165, 165, 165, 165, 165, 165, 165, 158, 158, 165, 152, 152, 152, 152, 171, 171,
+    171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 128, 146, 146, 146, 146, 146, 146, 146, 146, 185,
+    144, 144, 144, 144, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 152, 152, 152, 152, 171, 171,
+    171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 128, 146, 146, 146, 146, 146, 146, 146, 146, 185,
+    144, 144, 144, 144, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 152, 152, 152, 152, 152, 152,
+    171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 146, 186,
+    160, 144, 144, 144, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 152, 152, 152, 152, 152, 152,
+    152, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 146, 186,
+    160, 160, 160, 144, 165, 165, 165, 165, 165, 165, 165, 165, 165, 159, 152, 152, 152, 152, 152, 152,
+    152, 171, 171, 171, 171, 171, 170, 170, 170, 136, 136, 136, 136, 146, 146, 146, 146, 146, 146, 186,
+    160, 160, 160, 160, 165, 165, 165, 165, 165, 165, 165, 159, 159, 159, 159, 152, 152, 152, 152, 152,
+    152, 171, 171, 171, 171, 171, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 146, 186,
+    160, 160, 160, 160, 160, 160, 165, 165, 165, 159, 159, 159, 159, 159, 159, 159, 152, 152, 152, 147,
+    147, 147, 171, 171, 171, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 165, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 147, 147, 147, 171, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 147, 147, 147, 147, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    160, 160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 147, 147, 147, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    157, 157, 175, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147,
+    147, 147, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    157, 157, 157, 175, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 162, 153,
+    153, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 133, 133, 133,
+    157, 157, 157, 157, 175, 160, 160, 159, 159, 159, 159, 159, 159, 162, 162, 162, 162, 162, 162, 153,
+    153, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 133, 133,
+    157, 157, 157, 157, 175, 160, 160, 159, 159, 159, 159, 162, 162, 162, 162, 162, 162, 162, 162, 153,
+    153, 166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 175, 160, 159, 159, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 153,
+    153, 166, 166, 166, 166, 154, 154, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 145, 145, 145, 162, 162, 162, 162, 162, 162, 162, 176, 176, 153,
+    153, 166, 166, 166, 166, 154, 154, 154, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 172, 145, 145, 145, 145, 162, 162, 162, 162, 162, 176, 176, 176,
+    153, 166, 166, 166, 166, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 172, 172, 145, 145, 145, 162, 162, 162, 162, 162, 176, 176, 153,
+    153, 153, 166, 154, 154, 154, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 172, 145, 145, 145, 145, 162, 162, 162, 162, 176, 176, 153,
+    153, 153, 154, 154, 154, 154, 154, 154, 177, 177, 177, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 145, 145, 172, 172, 172, 172, 162, 178, 176, 176,
+    153, 153, 154, 154, 154, 177, 177, 177, 177, 177, 177, 177, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 172, 172, 172, 172, 178, 178, 178, 178,
+    149, 149, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 155, 155, 155, 155, 155, 155, 155, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 172, 172, 178, 178, 178, 178, 149,
+    149, 149, 149, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 155, 155, 155, 155, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 138, 178, 178, 178, 178, 178, 178, 149,
+    149, 149, 149, 156, 156, 156, 156, 156, 156, 156, 164, 164, 164, 164, 163, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 138, 138, 178, 178, 178, 178, 149, 149,
+    149, 149, 149, 156, 156, 156, 156, 156, 156, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 138, 138, 178, 149, 149, 149, 149, 149,
+    149, 149, 149, 149, 156, 156, 156, 156, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 178, 149, 149, 149, 149, 149,
+    149, 149, 149, 149, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 139, 149, 149, 149, 149, 149,
+    149, 149, 149, 140, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 163, 163,
+    179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 139, 139, 139, 139, 149, 149,
+    181, 149, 182, 182, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 183,
+    180, 180, 180, 187, 148, 148, 148, 148, 148, 148, 148, 148, 138, 138, 139, 139, 139, 181, 181, 181,
+    181, 181, 182, 182, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 183,
+    180, 180, 180, 187, 188, 188, 148, 148, 148, 148, 148, 148, 148, 139, 139, 139, 139, 181, 181, 181,
+    181, 181, 182, 182, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 168, 167, 167, 167, 167,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 189, 189, 189, 173, 173, 173, 173, 173, 173, 143,
+    143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 173, 173, 173, 173, 143,
+    143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 173, 143, 143, 143, 143,
+    143, 143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143, 143,
+    143, 143, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 184, 170, 170, 170, 170, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 174, 158, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 184, 184, 184, 184, 128, 128, 128, 128, 151, 151, 151, 169, 169, 169, 141, 141, 141,
+    142, 142, 142, 142, 142, 142, 174, 174, 174, 158, 158, 158, 158, 158, 158, 158, 158, 143, 143, 143,
+    143, 143, 143, 184, 184, 184, 170, 170, 128, 128, 128, 128, 169, 169, 169, 169, 169, 169, 141, 141,
+    142, 142, 142, 142, 142, 174, 174, 174, 174, 174, 158, 158, 158, 158, 158, 158, 129, 129, 171, 143,
+    143, 143, 143, 170, 170, 170, 170, 170, 170, 128, 128, 128, 169, 169, 169, 169, 169, 169, 141, 185,
+    142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 158, 158, 158, 158, 158, 158, 158, 171, 171, 171,
+    171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 128, 128, 169, 169, 169, 169, 169, 169, 185, 185,
+    142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 158, 158, 158, 152, 171, 171, 171,
+    171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 128, 146, 146, 146, 146, 146, 146, 146, 185, 185,
+    142, 142, 142, 144, 165, 165, 174, 174, 165, 165, 165, 165, 165, 165, 152, 152, 152, 171, 171, 171,
+    171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 185, 185,
+    142, 165, 165, 165, 165, 165, 174, 174, 165, 165, 165, 165, 165, 165, 152, 152, 152, 171, 171, 171,
+    171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 185, 185,
+    165, 165, 165, 165, 165, 165, 174, 174, 165, 165, 165, 165, 165, 165, 152, 152, 152, 152, 171, 171,
+    171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 185, 185,
+    160, 165, 165, 165, 165, 165, 174, 174, 165, 165, 165, 165, 165, 165, 152, 152, 152, 152, 171, 171,
+    171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 185, 186,
+    160, 160, 160, 165, 165, 165, 174, 174, 165, 165, 165, 159, 159, 159, 152, 152, 152, 152, 152, 171,
+    171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 186, 186,
+    160, 160, 160, 160, 165, 165, 159, 159, 165, 165, 159, 159, 159, 159, 159, 152, 152, 152, 152, 152,
+    171, 171, 171, 171, 171, 171, 171, 170, 170, 136, 136, 136, 136, 136, 136, 136, 136, 146, 146, 186,
+    160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 152, 152, 152, 152,
+    171, 171, 171, 171, 171, 171, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 146, 190,
+    160, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 147, 171, 171, 171, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133,
+    175, 175, 160, 160, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 147, 147, 171, 171, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    175, 175, 175, 175, 160, 160, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147,
+    147, 147, 147, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    157, 157, 175, 175, 175, 175, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147,
+    147, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 133, 133, 133, 133,
+    157, 157, 157, 175, 175, 175, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 176, 153,
+    166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 155, 155, 155, 133, 133,
+    157, 157, 157, 157, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 162, 162, 176, 153,
+    166, 166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 133,
+    157, 157, 157, 157, 175, 175, 175, 159, 159, 159, 159, 159, 162, 162, 162, 162, 162, 162, 176, 153,
+    166, 166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 175, 175, 159, 159, 159, 162, 162, 162, 162, 162, 162, 162, 162, 176, 153,
+    166, 166, 166, 166, 166, 166, 154, 154, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 191, 191, 159, 162, 162, 162, 162, 162, 162, 162, 162, 162, 176, 176, 176,
+    153, 166, 166, 166, 166, 154, 154, 154, 136, 136, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 145, 145, 162, 162, 162, 162, 162, 162, 162, 162, 176, 176, 176,
+    153, 166, 166, 166, 166, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 172, 145, 162, 162, 162, 162, 162, 162, 162, 176, 176, 176,
+    176, 166, 166, 154, 154, 154, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 145, 145, 162, 162, 162, 162, 162, 176, 176, 176, 176,
+    176, 166, 154, 154, 154, 154, 154, 177, 177, 177, 177, 177, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 172, 172, 172, 172, 178, 178, 178, 176,
+    176, 166, 154, 154, 177, 177, 177, 177, 177, 177, 177, 177, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 172, 172, 172, 172, 178, 178, 178, 178,
+    178, 178, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 155, 155, 155, 155, 155, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 172, 172, 172, 178, 178, 178, 178, 178,
+    178, 149, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 164, 155, 155, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 178, 178, 178, 178, 178, 178, 178,
+    178, 149, 149, 177, 177, 177, 177, 177, 177, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 178, 178, 178, 178, 178, 178, 178,
+    178, 149, 149, 177, 177, 177, 177, 177, 177, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 178, 178, 178, 178, 178, 178, 149,
+    149, 149, 149, 182, 182, 177, 177, 177, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 178, 178, 178, 178, 178, 178, 149,
+    149, 149, 149, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 157, 138, 138, 149, 149, 149, 149, 149, 149,
+    149, 149, 149, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 163, 163,
+    179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 157, 157, 138, 139, 139, 139, 139, 149, 181,
+    181, 181, 181, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 183,
+    180, 180, 180, 187, 187, 148, 148, 148, 148, 148, 188, 188, 188, 181, 181, 181, 181, 181, 181, 181,
+    181, 181, 182, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 183,
+    180, 180, 180, 187, 188, 188, 188, 188, 188, 188, 188, 188, 188, 181, 181, 181, 181, 181, 181, 181,
+    181, 181, 182, 182, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 168, 167, 167, 167, 167,
+    142, 142, 142, 142, 142, 142, 142, 142, 142, 158, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 189, 189, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 173, 173, 173, 173, 173, 173,
+    173, 143, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 158, 158, 158, 158, 158, 158, 158, 173, 173, 173, 173, 173,
+    173, 192, 192, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141,
+    142, 142, 142, 142, 142, 142, 142, 174, 158, 158, 158, 158, 158, 158, 158, 173, 173, 173, 173, 173,
+    173, 192, 192, 170, 170, 170, 170, 170, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141,
+    142, 142, 142, 142, 142, 142, 174, 174, 174, 158, 158, 158, 158, 158, 158, 158, 173, 173, 173, 143,
+    173, 192, 184, 184, 184, 184, 184, 170, 170, 151, 151, 151, 151, 151, 151, 169, 169, 169, 141, 141,
+    142, 142, 142, 142, 142, 142, 174, 174, 174, 174, 158, 158, 158, 158, 158, 158, 173, 173, 173, 143,
+    143, 192, 184, 184, 184, 184, 184, 170, 170, 170, 128, 169, 169, 169, 169, 169, 169, 169, 141, 185,
+    142, 142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 158, 158, 158, 158, 158, 129, 143, 143, 143,
+    143, 192, 184, 184, 184, 170, 170, 170, 170, 170, 170, 169, 169, 169, 169, 169, 169, 169, 185, 185,
+    142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 158, 158, 158, 158, 171, 171, 171, 171,
+    171, 171, 184, 170, 170, 170, 170, 170, 170, 170, 170, 169, 169, 169, 169, 169, 169, 169, 185, 185,
+    142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 158, 158, 158, 152, 171, 171, 171,
+    171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 169, 185, 185,
+    142, 142, 142, 165, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 152, 152, 171, 171, 171,
+    171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 185, 185,
+    142, 165, 165, 165, 165, 174, 174, 174, 165, 165, 165, 165, 165, 165, 152, 152, 152, 171, 171, 171,
+    171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 146, 185, 185,
+    142, 165, 165, 165, 165, 174, 174, 174, 165, 165, 165, 165, 165, 165, 152, 152, 152, 171, 171, 171,
+    171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 185, 185,
+    160, 165, 165, 165, 165, 174, 174, 174, 165, 165, 165, 165, 165, 165, 152, 152, 152, 152, 171, 171,
+    171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 185, 185,
+    160, 160, 165, 165, 165, 165, 174, 174, 165, 165, 165, 159, 159, 159, 152, 152, 152, 152, 171, 171,
+    171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 185, 185,
+    175, 175, 175, 175, 165, 165, 174, 159, 165, 165, 159, 159, 159, 159, 159, 152, 152, 152, 152, 171,
+    171, 171, 171, 171, 171, 171, 171, 170, 170, 170, 136, 136, 136, 136, 136, 136, 146, 146, 185, 190,
+    175, 175, 175, 175, 175, 165, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 152, 152, 152, 171,
+    171, 171, 171, 171, 171, 171, 171, 170, 136, 136, 136, 136, 136, 136, 136, 136, 193, 193, 193, 190,
+    175, 175, 175, 175, 175, 160, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 152, 147, 171,
+    171, 171, 171, 171, 171, 171, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 193, 193, 193, 193,
+    175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147, 147,
+    147, 171, 171, 171, 171, 171, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 193, 193, 193, 193,
+    175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147,
+    147, 147, 166, 166, 166, 166, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 193, 193, 193, 193,
+    157, 157, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 176, 147,
+    166, 166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 193, 193, 193, 193, 193, 193, 193, 193,
+    157, 157, 157, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 176, 176, 176,
+    166, 166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 193, 193, 193, 193, 193, 193, 193, 193,
+    157, 157, 157, 157, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 162, 176, 176, 176,
+    166, 166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 136, 193, 193, 193, 193, 193, 193, 193, 193,
+    157, 157, 157, 157, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 162, 162, 162, 176, 176, 176,
+    166, 166, 166, 166, 166, 166, 166, 154, 136, 136, 136, 136, 193, 193, 193, 193, 193, 193, 155, 155,
+    157, 157, 157, 157, 157, 175, 175, 175, 159, 159, 162, 162, 162, 162, 162, 162, 162, 176, 176, 176,
+    166, 166, 166, 166, 166, 166, 154, 154, 136, 136, 136, 136, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 191, 191, 191, 159, 162, 162, 162, 162, 162, 162, 162, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 154, 154, 154, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 191, 191, 191, 162, 162, 162, 162, 162, 162, 162, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 162, 162, 162, 162, 162, 162, 162, 176, 176, 176, 176,
+    176, 166, 166, 154, 154, 154, 154, 154, 154, 177, 177, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 162, 162, 162, 162, 162, 176, 176, 176, 176, 176,
+    176, 166, 154, 154, 154, 154, 177, 177, 177, 177, 177, 177, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 172, 172, 172, 172, 178, 178, 178, 176,
+    176, 176, 154, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 155, 155, 155, 155, 155, 155, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 172, 172, 172, 178, 178, 178, 178,
+    178, 178, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 155, 155, 155, 163, 163, 163,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 172, 172, 178, 178, 178, 178, 178,
+    178, 178, 177, 177, 177, 177, 177, 177, 177, 194, 194, 194, 164, 164, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 157, 179, 157, 157, 157, 157, 157, 172, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    178, 178, 178, 177, 177, 177, 177, 177, 194, 194, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    178, 178, 195, 177, 177, 177, 177, 177, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 172, 178, 178, 178, 178, 178, 195,
+    195, 195, 195, 182, 182, 177, 177, 164, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 178, 178, 178, 178, 178, 195,
+    195, 195, 195, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 157, 157, 181, 181, 181, 181, 181, 181, 195,
+    195, 195, 195, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 157, 181, 181, 181, 181, 181, 181, 181,
+    181, 181, 181, 181, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 183,
+    180, 179, 187, 187, 187, 187, 157, 188, 188, 188, 196, 188, 188, 181, 181, 181, 181, 181, 181, 181,
+    181, 181, 182, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 183,
+    180, 180, 187, 187, 188, 188, 188, 188, 188, 188, 196, 188, 188, 181, 181, 181, 181, 181, 181, 181,
+    181, 181, 182, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 168, 167, 167, 167, 167,
+    142, 142, 142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 197,
+    142, 142, 142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 197,
+    142, 142, 142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141,
+    142, 142, 142, 142, 142, 142, 174, 174, 158, 158, 158, 158, 158, 158, 173, 173, 173, 173, 173, 173,
+    173, 192, 192, 151, 151, 151, 151, 170, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141,
+    142, 142, 142, 142, 142, 142, 174, 174, 174, 158, 158, 158, 158, 158, 173, 173, 173, 173, 173, 173,
+    173, 192, 192, 173, 151, 151, 151, 170, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 141, 141,
+    142, 142, 142, 142, 142, 142, 174, 174, 174, 174, 158, 158, 158, 158, 173, 173, 173, 173, 173, 173,
+    173, 192, 192, 184, 184, 184, 170, 170, 170, 151, 151, 151, 151, 151, 151, 151, 169, 169, 169, 185,
+    142, 142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 158, 158, 158, 158, 173, 173, 173, 173, 192,
+    192, 192, 192, 184, 184, 184, 184, 170, 170, 170, 151, 151, 151, 151, 169, 169, 169, 169, 185, 185,
+    142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 158, 158, 158, 158, 192, 192, 192, 192,
+    192, 192, 192, 184, 184, 184, 170, 170, 170, 170, 170, 151, 169, 169, 169, 169, 169, 169, 185, 185,
+    142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 158, 158, 198, 198, 198, 171, 171,
+    171, 192, 192, 184, 170, 170, 170, 170, 170, 170, 170, 170, 169, 169, 169, 169, 169, 169, 185, 185,
+    142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 158, 158, 198, 198, 171, 171,
+    171, 171, 192, 170, 170, 170, 170, 170, 170, 170, 170, 170, 169, 169, 169, 169, 169, 185, 185, 185,
+    142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 198, 198, 198, 171, 171,
+    171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 185, 185, 185,
+    142, 165, 165, 165, 165, 174, 174, 174, 165, 165, 165, 165, 165, 165, 152, 198, 198, 198, 171, 171,
+    171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 185, 185,
+    142, 165, 165, 165, 165, 174, 174, 174, 165, 165, 165, 165, 165, 165, 152, 198, 198, 198, 171, 171,
+    171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 185, 185,
+    160, 165, 165, 165, 165, 174, 174, 174, 165, 165, 165, 159, 165, 165, 152, 198, 198, 198, 171, 171,
+    171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 185, 185,
+    175, 175, 175, 165, 165, 165, 174, 174, 165, 165, 165, 159, 159, 159, 152, 198, 198, 198, 171, 171,
+    171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 146, 146, 146, 146, 146, 146, 185, 185,
+    175, 175, 175, 175, 175, 165, 174, 159, 159, 159, 159, 159, 159, 159, 159, 198, 198, 198, 171, 171,
+    171, 171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 193, 136, 136, 193, 193, 193, 146, 199, 199,
+    175, 175, 175, 175, 175, 165, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 198, 198, 171, 171,
+    171, 171, 171, 171, 171, 171, 171, 170, 170, 136, 193, 193, 136, 136, 193, 193, 193, 193, 199, 199,
+    175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 198, 171, 171,
+    171, 171, 171, 171, 171, 171, 171, 171, 136, 136, 193, 193, 136, 136, 193, 193, 193, 193, 193, 199,
+    175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 171, 171,
+    171, 171, 171, 171, 171, 171, 171, 136, 136, 193, 193, 193, 136, 136, 193, 193, 193, 193, 193, 193,
+    175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 147, 147,
+    147, 171, 171, 200, 200, 200, 200, 136, 136, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+    175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 176, 176, 176,
+    166, 166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+    157, 157, 157, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 176, 176, 176,
+    166, 166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+    157, 157, 157, 157, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 176, 176, 176, 176,
+    166, 166, 166, 166, 166, 166, 166, 136, 136, 136, 136, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+    157, 157, 157, 157, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 162, 162, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 166, 154, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+    157, 157, 157, 157, 157, 175, 175, 191, 159, 159, 159, 159, 162, 162, 162, 162, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 154, 154, 154, 193, 193, 193, 193, 193, 193, 193, 193, 193, 155, 155,
+    157, 157, 157, 157, 157, 191, 191, 191, 191, 162, 162, 162, 162, 162, 162, 176, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 154, 154, 154, 154, 193, 193, 193, 193, 193, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 191, 191, 191, 162, 162, 162, 162, 162, 162, 176, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 154, 154, 154, 154, 154, 193, 193, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 191, 191, 191, 191, 162, 162, 162, 162, 162, 176, 176, 176, 176, 176,
+    176, 176, 166, 154, 154, 154, 154, 154, 177, 177, 177, 177, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 162, 162, 162, 162, 176, 176, 176, 176, 176, 176,
+    176, 176, 154, 154, 154, 177, 177, 177, 177, 177, 177, 177, 155, 155, 155, 155, 155, 155, 155, 155,
+    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 172, 172, 162, 162, 178, 178, 178, 178, 178, 176,
+    176, 176, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 194, 155, 155, 155, 155, 155, 155, 163,
+    179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 172, 172, 172, 162, 178, 178, 178, 178, 178, 178,
+    178, 178, 177, 177, 177, 177, 177, 177, 177, 194, 194, 194, 194, 194, 155, 155, 155, 163, 163, 163,
+    179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 172, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    178, 178, 177, 177, 177, 177, 194, 194, 194, 194, 194, 194, 194, 194, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    178, 178, 177, 177, 177, 177, 194, 194, 194, 194, 194, 194, 194, 164, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    178, 195, 195, 177, 177, 177, 194, 194, 194, 194, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 172, 172, 172, 178, 178, 178, 178, 178, 195,
+    195, 195, 195, 182, 182, 177, 194, 194, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 172, 178, 178, 178, 178, 178, 195, 195,
+    195, 195, 195, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 178, 181, 181, 181, 181, 181, 195,
+    195, 195, 195, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 157, 188, 188, 196, 196, 157, 181, 181, 181, 181, 181, 181, 195,
+    195, 195, 195, 195, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 183, 183, 183, 183,
+    179, 187, 187, 187, 179, 179, 188, 188, 188, 188, 196, 196, 196, 181, 181, 181, 181, 181, 181, 181,
+    181, 181, 181, 181, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 168, 183, 183, 183, 183,
+    180, 180, 179, 187, 187, 179, 188, 188, 188, 188, 196, 196, 196, 181, 181, 181, 181, 181, 181, 181,
+    181, 181, 182, 182, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 168, 168, 167, 167, 167, 183,
+    142, 142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 173, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 197,
+    142, 142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 173, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 197,
+    142, 142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 173, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 197,
+    142, 142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173, 173,
+    173, 192, 192, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 197,
+    142, 142, 142, 142, 142, 174, 174, 174, 174, 158, 158, 158, 158, 173, 173, 173, 173, 173, 173, 173,
+    173, 192, 192, 173, 151, 151, 151, 170, 170, 170, 151, 151, 151, 151, 151, 151, 151, 151, 151, 185,
+    142, 142, 142, 142, 142, 174, 174, 174, 174, 174, 158, 158, 158, 173, 173, 173, 173, 173, 173, 173,
+    173, 192, 192, 184, 184, 184, 151, 170, 170, 170, 151, 151, 151, 151, 151, 151, 151, 169, 169, 185,
+    142, 142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 158, 158, 158, 173, 173, 173, 173, 173, 192,
+    192, 192, 192, 184, 184, 184, 184, 170, 170, 170, 151, 151, 151, 151, 151, 169, 169, 169, 185, 185,
+    142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 158, 158, 173, 173, 201, 201, 201, 192,
+    192, 192, 192, 184, 184, 184, 184, 170, 170, 170, 170, 151, 151, 151, 169, 169, 169, 169, 185, 185,
+    142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 158, 158, 198, 198, 198, 198, 198,
+    192, 192, 192, 184, 184, 170, 170, 170, 170, 170, 170, 170, 169, 169, 169, 169, 169, 185, 185, 185,
+    142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 202, 198, 198, 198, 198, 198,
+    171, 171, 192, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 169, 169, 169, 203, 203, 185, 185,
+    142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 198, 198, 198, 198, 198,
+    171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 146, 146, 203, 203, 203, 185, 185,
+    142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 198, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 203, 203, 185, 185,
+    175, 165, 165, 165, 165, 174, 174, 174, 165, 165, 165, 165, 165, 165, 198, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 203, 203, 185, 185,
+    175, 175, 175, 165, 165, 174, 174, 174, 165, 165, 165, 159, 159, 165, 198, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 203, 203, 199, 199,
+    175, 175, 175, 175, 165, 165, 174, 174, 165, 165, 159, 159, 159, 159, 198, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 146, 146, 146, 203, 203, 199, 199,
+    175, 175, 175, 175, 175, 165, 174, 159, 159, 159, 159, 159, 159, 159, 159, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 193, 193, 193, 193, 199, 199, 199, 199,
+    175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 171, 171, 170, 170, 170, 193, 193, 193, 193, 193, 193, 193, 199, 199, 199,
+    175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 171, 171, 171, 170, 193, 193, 193, 193, 193, 193, 193, 193, 193, 199, 199,
+    175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 198, 198, 198,
+    171, 171, 171, 171, 171, 171, 171, 200, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 199,
+    175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 204, 204, 200,
+    200, 200, 200, 200, 200, 200, 200, 200, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205,
+    175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 176, 204, 200,
+    200, 200, 200, 200, 200, 200, 200, 200, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205,
+    175, 175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 176, 176, 176, 176,
+    200, 200, 200, 200, 200, 200, 200, 200, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205,
+    157, 175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 162, 176, 176, 176, 176, 176,
+    200, 200, 200, 200, 200, 200, 200, 200, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205,
+    157, 175, 175, 175, 175, 175, 175, 191, 191, 159, 159, 159, 159, 159, 162, 176, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 166, 166, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205,
+    175, 175, 175, 175, 175, 175, 191, 191, 191, 159, 159, 162, 162, 162, 162, 176, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 166, 154, 154, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205,
+    175, 175, 175, 175, 175, 191, 191, 191, 191, 162, 162, 162, 162, 162, 176, 176, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 166, 154, 154, 154, 193, 193, 193, 193, 193, 193, 193, 193, 205, 205,
+    175, 175, 175, 175, 191, 191, 191, 191, 191, 191, 162, 162, 162, 162, 176, 176, 176, 176, 176, 176,
+    176, 166, 166, 166, 166, 166, 154, 154, 154, 154, 177, 193, 193, 193, 193, 155, 155, 155, 155, 206,
+    175, 175, 157, 157, 191, 191, 191, 191, 191, 191, 162, 162, 162, 162, 176, 176, 176, 176, 176, 176,
+    176, 176, 166, 166, 154, 154, 154, 177, 177, 177, 177, 194, 193, 155, 155, 155, 155, 155, 206, 206,
+    179, 179, 179, 179, 157, 191, 157, 207, 207, 157, 162, 162, 162, 162, 176, 176, 176, 176, 176, 176,
+    176, 176, 166, 154, 154, 177, 177, 177, 177, 177, 194, 194, 194, 155, 155, 155, 155, 206, 206, 206,
+    179, 179, 179, 179, 157, 157, 157, 207, 207, 157, 172, 172, 162, 162, 178, 178, 178, 178, 178, 176,
+    176, 176, 177, 177, 177, 177, 177, 177, 177, 194, 194, 194, 194, 194, 155, 155, 206, 206, 206, 206,
+    179, 179, 179, 179, 157, 157, 157, 207, 207, 157, 172, 172, 172, 178, 178, 178, 178, 178, 178, 178,
+    178, 178, 208, 177, 177, 177, 194, 194, 194, 194, 194, 194, 194, 194, 209, 163, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 157, 157, 207, 207, 157, 157, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    178, 178, 208, 177, 177, 194, 194, 194, 194, 194, 194, 194, 194, 194, 209, 163, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 157, 157, 157, 207, 157, 157, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    178, 178, 208, 177, 177, 194, 194, 194, 194, 194, 194, 194, 194, 194, 209, 163, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    195, 195, 195, 195, 177, 194, 194, 194, 194, 194, 194, 194, 164, 164, 164, 209, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 172, 178, 178, 178, 178, 178, 178, 195,
+    195, 195, 195, 195, 182, 194, 194, 194, 194, 194, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 172, 178, 178, 178, 178, 195, 195, 195,
+    195, 195, 195, 182, 182, 182, 194, 164, 164, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 157, 157, 157, 157, 157, 157, 178, 178, 181, 181, 195, 195, 195,
+    195, 195, 195, 182, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163, 163,
+    187, 187, 187, 179, 187, 187, 187, 188, 188, 196, 196, 196, 196, 181, 181, 181, 181, 181, 181, 195,
+    195, 195, 195, 195, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 183, 183, 183, 183,
+    180, 187, 187, 187, 187, 187, 188, 188, 188, 196, 196, 196, 196, 181, 181, 181, 181, 181, 181, 181,
+    195, 195, 195, 195, 195, 182, 182, 164, 164, 164, 164, 164, 164, 164, 168, 168, 167, 183, 183, 183,
+    180, 180, 179, 187, 187, 187, 188, 188, 188, 196, 196, 196, 196, 181, 181, 181, 181, 181, 181, 181,
+    181, 181, 181, 195, 195, 210, 164, 164, 164, 164, 164, 164, 164, 164, 168, 168, 167, 167, 167, 183,
+    142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 173, 173, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 211, 211, 211, 211, 211, 197,
+    142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 173, 173, 151, 151, 151, 151, 151, 184, 151, 151, 151, 151, 211, 211, 211, 211, 211, 197,
+    142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173, 173,
+    173, 173, 173, 173, 151, 151, 151, 151, 151, 184, 151, 151, 151, 151, 211, 211, 211, 211, 211, 211,
+    142, 142, 142, 142, 189, 189, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173, 173,
+    173, 192, 192, 173, 151, 151, 151, 151, 151, 184, 151, 151, 151, 151, 151, 151, 151, 211, 211, 211,
+    142, 142, 142, 142, 142, 174, 189, 189, 189, 189, 189, 189, 173, 173, 173, 173, 173, 173, 173, 173,
+    173, 192, 192, 173, 151, 151, 151, 184, 184, 184, 151, 151, 151, 151, 151, 151, 151, 211, 211, 211,
+    142, 142, 142, 142, 174, 174, 189, 189, 174, 189, 189, 212, 173, 173, 173, 173, 173, 173, 173, 173,
+    173, 192, 192, 184, 184, 184, 184, 184, 184, 184, 184, 151, 151, 151, 151, 151, 151, 211, 211, 185,
+    142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 173, 173, 173, 173, 173, 173, 173, 192,
+    192, 192, 192, 184, 184, 184, 184, 184, 184, 184, 184, 213, 151, 151, 151, 151, 203, 203, 203, 185,
+    142, 142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 202, 173, 173, 173, 201, 201, 201, 192,
+    192, 192, 192, 184, 184, 184, 184, 184, 184, 170, 170, 151, 151, 151, 151, 203, 203, 203, 203, 185,
+    142, 142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 202, 202, 201, 201, 201, 201, 192,
+    192, 192, 192, 184, 184, 184, 170, 170, 170, 170, 170, 151, 151, 203, 203, 203, 203, 203, 203, 185,
+    142, 142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 202, 202, 201, 198, 198, 198, 198,
+    198, 192, 192, 184, 170, 170, 170, 170, 170, 170, 170, 170, 203, 203, 203, 203, 203, 203, 203, 185,
+    142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 202, 202, 198, 198, 198, 198, 198,
+    198, 171, 192, 170, 170, 170, 170, 170, 170, 170, 170, 170, 214, 203, 203, 203, 203, 203, 203, 185,
+    142, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 202, 198, 198, 198, 198, 198, 198,
+    198, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 170, 203, 203, 203, 203, 203, 203, 185,
+    175, 175, 174, 174, 174, 174, 174, 174, 174, 174, 174, 165, 165, 202, 198, 198, 198, 198, 198, 198,
+    198, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 170, 215, 203, 203, 203, 203, 203, 203,
+    175, 175, 175, 175, 165, 165, 165, 165, 165, 165, 165, 159, 159, 202, 198, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 170, 215, 203, 203, 203, 203, 199, 199,
+    175, 175, 175, 175, 175, 165, 165, 165, 165, 165, 165, 159, 159, 159, 198, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 170, 170, 215, 203, 203, 203, 203, 199, 199,
+    175, 175, 175, 175, 175, 175, 165, 165, 159, 159, 159, 159, 159, 159, 198, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 171, 171, 170, 170, 170, 170, 170, 193, 193, 215, 203, 199, 199, 199, 199,
+    175, 175, 175, 175, 175, 175, 165, 159, 159, 159, 159, 159, 159, 159, 159, 198, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 171, 171, 170, 170, 170, 193, 193, 193, 193, 193, 193, 199, 199, 199, 199,
+    175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 198, 198, 198, 198,
+    171, 171, 171, 171, 171, 171, 216, 216, 216, 193, 193, 193, 193, 193, 193, 193, 193, 199, 199, 199,
+    175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 159, 159, 204, 204, 198, 198,
+    198, 171, 171, 171, 216, 216, 216, 216, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 199, 199,
+    175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 159, 217, 217, 204, 204, 204, 204,
+    200, 200, 200, 200, 200, 200, 200, 200, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205, 199,
+    175, 175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 217, 217, 204, 204, 204, 200,
+    200, 200, 200, 200, 200, 200, 200, 200, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205, 205,
+    175, 175, 175, 175, 175, 175, 175, 175, 159, 159, 159, 159, 159, 159, 217, 217, 217, 204, 204, 200,
+    200, 200, 200, 200, 200, 200, 200, 200, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205, 205,
+    218, 175, 175, 175, 175, 175, 175, 191, 191, 159, 159, 159, 159, 159, 217, 217, 176, 176, 176, 200,
+    200, 200, 200, 200, 200, 200, 200, 200, 193, 193, 193, 193, 193, 193, 193, 193, 193, 205, 205, 205,
+    218, 175, 175, 175, 175, 175, 191, 191, 191, 159, 159, 159, 159, 159, 176, 176, 176, 176, 176, 176,
+    200, 200, 200, 200, 200, 200, 200, 200, 200, 193, 193, 193, 193, 193, 193, 193, 193, 205, 205, 205,
+    175, 175, 175, 175, 175, 191, 191, 191, 191, 191, 159, 162, 162, 162, 176, 176, 176, 176, 176, 176,
+    176, 200, 200, 200, 200, 200, 200, 200, 154, 193, 193, 193, 193, 193, 193, 193, 193, 205, 205, 219,
+    175, 175, 175, 175, 191, 191, 191, 191, 191, 191, 162, 162, 162, 176, 176, 176, 176, 176, 176, 176,
+    176, 176, 200, 200, 200, 200, 166, 166, 154, 154, 193, 193, 193, 193, 193, 193, 193, 205, 205, 206,
+    179, 179, 179, 175, 191, 191, 191, 191, 191, 191, 162, 162, 162, 176, 176, 176, 176, 176, 176, 176,
+    176, 176, 166, 166, 166, 166, 154, 154, 154, 194, 194, 194, 193, 193, 193, 193, 206, 206, 206, 206,
+    179, 179, 179, 179, 191, 191, 191, 191, 191, 191, 191, 162, 162, 176, 176, 176, 176, 176, 176, 176,
+    176, 176, 166, 166, 154, 154, 177, 177, 194, 194, 194, 194, 194, 193, 193, 206, 206, 206, 206, 206,
+    179, 179, 179, 179, 157, 191, 207, 207, 207, 207, 191, 178, 178, 178, 178, 176, 176, 176, 176, 176,
+    176, 176, 166, 154, 154, 177, 177, 194, 194, 194, 194, 194, 194, 220, 220, 206, 206, 206, 206, 206,
+    179, 179, 179, 179, 157, 157, 207, 207, 207, 207, 207, 172, 178, 178, 178, 178, 178, 178, 178, 176,
+    176, 208, 154, 154, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 209, 206, 206, 206, 206, 206,
+    179, 179, 179, 179, 157, 157, 207, 207, 207, 207, 207, 172, 172, 178, 178, 178, 178, 178, 178, 178,
+    178, 208, 208, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 209, 209, 209, 163, 206, 206,
+    179, 179, 179, 179, 179, 157, 207, 207, 207, 207, 207, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    178, 208, 208, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 209, 209, 209, 163, 163, 163,
+    179, 179, 179, 179, 179, 157, 207, 207, 207, 207, 207, 172, 172, 172, 178, 178, 178, 178, 178, 178,
+    178, 195, 208, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 209, 209, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 157, 157, 207, 207, 207, 207, 207, 172, 178, 178, 178, 178, 178, 195, 195,
+    195, 195, 195, 195, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 209, 209, 163, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 157, 207, 207, 207, 207, 172, 178, 178, 178, 178, 178, 195, 195,
+    195, 195, 195, 195, 194, 194, 194, 194, 194, 194, 194, 194, 164, 164, 164, 209, 209, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 157, 207, 207, 207, 207, 172, 178, 178, 178, 195, 195, 195, 195,
+    195, 195, 195, 195, 182, 194, 194, 194, 194, 194, 164, 164, 164, 164, 164, 164, 164, 163, 163, 163,
+    179, 179, 179, 179, 179, 179, 157, 187, 207, 207, 207, 196, 196, 178, 178, 195, 195, 195, 195, 195,
+    195, 195, 195, 195, 182, 182, 194, 194, 164, 164, 164, 164, 164, 164, 164, 164, 168, 163, 163, 163,
+    187, 187, 187, 187, 187, 187, 187, 187, 196, 196, 196, 196, 196, 181, 181, 181, 181, 195, 195, 195,
+    195, 195, 195, 195, 182, 182, 164, 164, 164, 164, 164, 164, 164, 164, 164, 168, 168, 183, 183, 183,
+    180, 187, 187, 187, 187, 187, 187, 188, 196, 196, 196, 196, 196, 181, 181, 181, 181, 181, 181, 181,
+    195, 195, 195, 195, 195, 210, 164, 164, 164, 164, 164, 164, 164, 164, 168, 168, 167, 167, 183, 183,
+    180, 180, 179, 187, 187, 187, 188, 188, 196, 196, 196, 196, 196, 196, 181, 181, 181, 181, 181, 181,
+    181, 181, 195, 195, 195, 210, 164, 164, 164, 164, 164, 164, 164, 168, 168, 168, 167, 167, 167, 183
+};
+
+static float eccTrafo_volume_ref[64000] = {
+    12.706741f, 11.706741f, 10.706741f,  9.706741f,  8.706742f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f, 
+     5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  9.388905f,  9.071068f,  9.388905f, 10.878315f, 10.560477f, 11.170843f, 10.756630f, 10.342416f,  9.928203f,  9.610365f,  9.292528f,  8.974691f,  8.656854f,  8.974691f, 
+    12.388904f, 11.388904f, 10.388905f,  9.388905f,  8.388905f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  8.071068f,  8.388905f, 10.464102f, 10.878315f, 10.853005f, 10.438792f, 10.024579f,  9.610365f,  9.196152f,  8.878315f,  8.560477f,  8.242640f,  8.560477f, 
+    12.071067f, 11.071067f, 10.071067f,  9.071068f,  8.071068f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f, 
+     5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.706742f,  7.388905f,  7.071068f,  7.388905f,  7.706742f,  8.024579f,  8.342417f, 10.120955f,  9.706741f,  9.292528f,  8.878315f,  8.464102f,  8.146264f,  7.828427f,  8.146264f, 
+    12.388904f, 11.388904f, 10.388905f,  9.388905f,  8.388905f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  8.928204f,  7.928203f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  9.803118f,  9.388905f,  8.974691f,  8.560477f,  8.146264f,  7.732051f,  7.414214f,  7.732051f, 
+    12.706741f, 11.706741f, 10.706741f,  9.706741f,  8.706742f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f, 
+     5.828427f,  6.146264f,  8.610366f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  9.485281f,  9.071068f,  8.656854f,  8.242640f,  7.828427f,  7.414214f,  7.000000f,  7.414214f, 
+    13.024578f, 12.024578f, 11.024578f, 10.024579f,  9.024579f,  8.024579f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  7.196152f,  6.878315f,  6.560478f,  6.242640f, 
+     6.242640f,  6.560478f,  7.196152f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  9.388905f,  8.974691f,  8.560477f,  8.146264f,  7.732051f,  7.414214f,  7.732051f, 
+    13.342416f, 12.342416f, 11.342416f, 10.342416f,  9.342417f,  8.342417f,  7.928203f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  6.196152f,  5.878315f,  5.560478f,  5.242640f, 
+     5.560478f,  5.878315f,  6.196152f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  9.706741f,  9.292528f,  8.878315f,  8.464102f,  8.146264f,  7.828427f,  8.146264f, 
+     8.878315f,  8.464102f,  8.146264f, 10.660254f,  9.660254f,  8.660254f,  8.342417f,  8.024579f,  7.706742f,  7.388905f,  7.071068f,  7.388905f,  7.706742f,  8.024579f,  8.342417f,  8.660254f,  5.196152f,  4.878315f,  4.560478f,  4.242640f, 
+     4.560478f,  4.878315f,  5.196152f,  8.146264f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f, 10.024579f,  9.610366f,  9.196153f,  8.878315f,  8.560477f,  8.242640f,  8.560477f, 
+     8.560477f,  8.146264f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  9.342417f,  9.024579f,  8.706742f,  6.878315f,  6.464102f,  8.388905f,  8.706742f,  9.024579f,  9.342417f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  4.464102f,  4.878315f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  9.928204f,  9.610366f,  9.292528f,  8.974691f,  8.656854f,  8.974691f, 
+     8.242640f,  7.828427f,  7.414214f,  7.000000f,  7.414214f,  7.828427f,  8.242640f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  9.706741f, 10.024579f, 10.342416f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  4.146264f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  7.292529f,  7.706742f,  9.560477f,  9.878315f, 10.024579f,  9.706741f,  9.388905f,  9.071068f,  9.388905f, 
+     8.560477f,  8.146264f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f, 
+     3.414214f,  3.828427f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f,  8.024579f,  8.560477f,  8.878315f,  9.196152f, 10.120955f,  9.803118f,  9.485281f,  9.803118f, 
+     8.878315f,  8.464102f,  8.146264f,  7.828427f,  8.146264f,  8.464102f,  8.878315f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.292529f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  9.878315f,  7.560478f,  7.878315f,  8.196152f, 10.535169f, 10.217332f,  9.899494f, 10.217332f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f,  8.560477f,  8.878315f, 18.217329f, 17.803116f, 17.388905f, 16.974689f, 16.560478f,  6.146264f,  5.828427f,  6.146264f,  5.878315f,  5.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  9.464102f,  6.560478f,  6.878315f,  7.196152f, 11.535169f, 11.217331f,  5.242640f,  5.560478f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f, 17.631544f, 17.217331f, 16.803116f, 16.388905f, 15.974690f, 15.560477f, 15.146264f,  6.242640f,  6.560478f,  5.464102f,  5.146264f,  5.196152f,  4.878315f,  4.560478f,  4.242640f, 
+     4.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  4.242640f,  4.560478f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f, 16.631544f, 16.217331f, 15.803117f, 15.388904f, 14.974690f, 14.560477f, 14.146264f, 14.560477f, 14.974690f,  5.146264f,  4.732051f,  4.414214f,  5.878315f,  5.560478f,  5.242640f, 
+     5.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  3.828427f,  4.146264f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f, 15.631544f, 15.217330f, 14.803117f, 14.388904f, 13.974690f, 13.560477f, 13.146264f, 13.560477f, 13.974690f,  4.828427f,  4.414214f,  4.000000f,  6.878315f,  6.560478f,  6.146264f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.414214f,  3.732051f, 
+     6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f, 14.631544f, 14.217331f, 13.803117f, 13.388904f, 12.974690f, 12.560477f, 12.146264f, 12.560477f,  6.974691f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  6.464102f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 11.024578f, 11.438792f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f, 13.631545f, 13.217331f, 12.803118f, 12.388904f, 11.974690f, 11.560477f, 11.146264f, 11.560477f,  5.974691f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  6.878315f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  9.196152f,  9.610365f, 10.024579f, 10.438792f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f, 13.217331f, 12.217332f, 11.803118f, 11.388905f, 10.974690f, 10.560477f, 10.146264f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.292529f, 
+     6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  7.878315f,  8.196152f,  8.610366f,  9.024579f,  9.438792f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f, 12.803118f, 11.803118f, 10.803119f, 10.388905f,  9.974691f,  9.560477f,  9.146264f,  8.732051f,  5.146264f,  4.828427f,  5.146264f,  6.732051f,  7.146264f,  7.560478f,  7.974691f, 
+     7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f, 13.388904f, 12.388904f, 11.388905f, 10.388905f,  9.388906f,  8.974691f,  8.560478f,  8.146264f,  7.732051f,  4.732051f,  4.414214f,  4.732051f,  5.732051f,  6.146264f,  6.560478f,  6.974691f, 
+     7.388905f,  8.388905f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f, 
+     8.706742f,  8.388905f,  8.071068f,  8.388905f, 12.974690f, 11.974690f, 10.974690f,  9.974691f,  8.974691f,  7.974692f,  7.560478f,  7.146265f,  6.732051f,  4.414214f,  4.000000f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     6.974691f,  7.974691f,  8.974691f,  8.974691f,  8.656854f,  8.146264f,  8.464102f,  8.878315f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f, 
+     9.120955f,  8.803119f,  8.485281f,  8.803119f, 12.560477f, 11.560477f, 10.560477f,  9.560477f,  8.560478f,  7.560478f,  6.560478f,  6.146265f,  5.732051f,  4.732051f,  4.414214f,  4.732051f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.560478f,  7.560478f,  8.560477f,  9.560477f, 10.560477f,  9.878315f,  8.878315f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f, 
+    11.120955f, 10.803118f, 10.485281f, 10.803118f,  6.928203f, 11.146264f, 10.146264f,  9.146264f,  8.146264f,  7.146265f,  6.146265f,  5.146265f,  4.732051f,  5.146264f,  4.828427f,  5.146264f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  7.146264f,  8.146264f,  9.146264f, 10.146264f, 11.146264f, 12.146264f, 13.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f, 
+    10.120955f,  9.803118f,  9.485281f,  9.803118f,  6.610366f,  6.196152f,  5.878315f,  8.732051f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  5.560478f,  5.242640f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.732051f,  6.732051f,  7.732051f,  8.732051f,  9.732051f, 10.732051f, 11.732051f, 12.732051f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  7.292529f,  7.610366f,  5.828427f,  6.242641f,  7.242641f, 
+     9.120955f,  8.803119f,  8.485281f,  8.803119f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.414214f,  6.414214f,  7.414214f,  8.414213f,  9.414213f, 10.414213f, 11.414213f, 12.414213f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  6.878315f,  7.196153f,  8.196153f,  6.560478f,  7.560478f, 
+     8.706742f,  8.388905f,  8.071068f,  8.388905f,  8.803119f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.732051f,  6.732051f,  7.732051f,  8.732051f,  9.732051f, 10.732051f, 11.732051f, 12.732051f, 13.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  5.560478f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  7.878315f, 
+     9.656854f,  8.656854f,  7.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  7.146264f,  8.146264f,  9.146264f, 10.146264f, 11.146264f, 12.146264f, 13.146264f, 14.146264f,  4.146265f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560478f,  9.560477f, 
+     9.974690f,  8.974691f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.560478f,  7.560478f,  8.560477f,  9.560477f, 10.560477f, 11.560477f, 12.560477f, 13.560477f, 14.560477f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  8.242640f,  9.242640f, 
+     7.464102f,  7.146264f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     6.974691f,  7.974691f,  8.974691f,  9.974690f, 10.974690f, 11.974690f, 12.974690f, 13.974690f, 14.974690f, 15.974690f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  9.560477f, 
+     7.146264f,  6.732051f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f, 
+     7.388905f,  8.388905f,  9.388905f, 10.388905f, 11.388904f, 12.388904f, 13.388904f, 14.388904f, 15.388904f, 16.388903f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  9.878315f, 
+     6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  6.292529f,  5.974691f,  5.656854f,  8.803119f,  8.388905f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f, 
+     8.388905f,  8.803119f,  9.803118f, 10.803118f, 11.803118f, 12.803117f, 13.803117f, 14.803117f, 15.803117f, 16.803116f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  9.196152f, 10.196152f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  6.974691f,  6.656854f,  9.803118f,  9.388905f,  8.974691f,  8.560477f,  8.146264f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  8.974691f, 
+     9.388905f,  9.803118f, 10.217332f, 11.217331f, 12.217331f, 13.217331f, 14.217330f, 15.217330f, 16.217331f, 17.217329f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  9.610365f, 10.610365f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  7.656854f, 10.803118f, 10.388905f,  9.974690f,  9.560477f,  9.146264f,  8.732051f,  8.414213f,  8.732051f,  9.146264f,  9.560477f,  9.974690f, 
+    10.388905f, 10.803118f, 11.217331f, 11.631545f, 12.631544f, 13.631544f, 14.631544f, 15.631543f, 16.631542f, 17.631542f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  7.610366f,  8.024579f,  9.024579f, 10.024579f, 11.024578f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  5.146264f,  8.610366f,  9.024579f,  8.656854f, 11.803118f, 11.388904f, 10.974690f, 10.560477f, 10.146264f,  9.732051f,  9.414213f,  9.732051f, 10.146264f, 10.560477f,  4.000000f, 
+     4.414214f,  4.828427f, 12.217331f, 12.631544f, 13.045758f, 14.045757f, 15.045757f, 16.045757f, 17.045757f, 18.045755f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.560478f,  5.878315f, 
+     8.560477f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  9.656854f, 12.803117f, 12.388904f, 11.974690f, 11.560477f, 11.146264f, 10.732051f, 10.414213f, 10.732051f, 11.146264f, 11.560477f,  4.414214f, 
+     4.732051f,  5.560478f,  5.146264f,  4.732051f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  8.071068f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  4.560478f,  4.878315f, 
+     8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 12.974690f, 12.560477f, 12.146264f, 11.732051f, 11.414213f, 11.732051f, 12.146264f,  5.146264f,  4.828427f, 
+     5.146264f,  5.878315f,  5.464102f,  5.146264f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  4.146264f,  3.828427f,  4.146264f,  1.000000f, 
+     7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  5.000000f,  5.414214f,  5.828427f, 13.146264f,  5.560478f,  5.242640f, 
+     5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  5.560478f,  5.828427f,  6.146265f,  6.464102f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.974691f,  6.414214f, 
+     5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.560478f,  6.878315f,  7.196152f,  6.878315f,  6.560478f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+     7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  6.146264f,  6.464102f,  6.878315f,  6.974691f,  6.732051f, 
+     5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  7.610366f,  7.292529f,  6.974691f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+    12.292528f, 11.292528f, 10.292528f,  9.292528f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.974691f,  8.656854f,  8.974691f,  9.878315f,  9.560477f, 10.756630f,  9.756630f,  9.342417f,  8.928203f,  8.610366f,  8.292528f,  7.974691f,  7.656854f,  7.974691f, 
+    11.974690f, 10.974690f,  9.974690f,  8.974691f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  7.656854f,  7.974691f,  9.464102f,  8.610366f, 10.438792f,  9.438792f,  9.024579f,  8.610366f,  8.196152f,  7.878315f,  7.560478f,  7.242640f,  7.560478f, 
+    11.656854f, 10.656854f,  9.656854f,  8.656854f,  7.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f, 
+     4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  9.120955f,  8.706742f,  8.292528f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f, 
+    11.974690f, 10.974690f,  9.974690f,  8.974691f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  8.803119f,  8.388905f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f, 
+    12.292528f, 11.292528f, 10.292528f,  9.292528f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  8.485281f,  8.071068f,  7.656854f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f, 
+    12.610365f, 11.610365f, 10.610365f,  9.610365f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  6.878315f,  6.464102f,  5.878315f,  5.560478f, 
+     5.242640f,  5.560478f,  5.878315f,  6.196152f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.388905f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f, 
+    12.928203f, 11.928203f, 10.928203f,  9.928203f,  8.928203f,  7.928203f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  5.878315f,  5.464102f,  5.146264f,  4.828427f, 
+     5.146264f,  5.974691f,  6.292529f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  8.706742f,  8.292528f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f, 
+     7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.928203f,  7.610366f,  6.610366f,  6.196152f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  4.464102f,  4.878315f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  9.610366f,  8.610366f,  8.196153f,  7.878315f,  7.560478f,  7.242640f,  7.560478f, 
+     7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  6.292529f,  5.878315f,  5.464102f,  7.974691f,  8.292528f,  8.610366f,  8.928203f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  3.464102f,  4.464102f,  6.732051f,  6.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.928204f,  8.610366f,  8.292528f,  7.974691f,  7.656854f,  7.974691f, 
+     7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  9.292528f,  9.610365f,  9.928203f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  6.292529f,  7.292529f,  9.146264f,  9.464102f,  9.024579f,  8.706742f,  8.388905f,  8.071068f,  8.388905f, 
+     7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  2.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  7.292529f,  7.610366f,  8.146264f,  8.464102f,  8.878315f,  9.120955f,  8.803119f,  8.485281f,  8.803119f, 
+     7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  8.610366f,  7.146264f,  7.464102f,  7.878315f, 10.120955f,  9.803118f,  9.485281f,  6.146264f, 
+     7.292529f,  6.974691f,  6.656854f,  7.242640f,  7.560478f,  7.878315f,  8.196152f, 17.485279f, 17.071068f, 16.656853f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  4.878315f,  4.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  4.828427f,  5.146264f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f, 16.899494f, 16.485279f, 16.071068f, 15.656854f, 15.242640f,  5.560478f,  5.242640f,  5.560478f,  4.464102f,  4.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  3.828427f,  4.146264f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f, 16.313705f, 15.899493f, 15.485280f, 15.071067f, 14.656854f, 14.242640f, 13.828427f, 14.242640f,  5.974691f,  4.146264f,  3.732051f,  3.414214f,  5.464102f,  5.146264f,  4.828427f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  2.828427f,  3.146264f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f, 15.313706f, 14.899493f, 14.485280f, 14.071067f, 13.656854f, 13.242640f, 12.828427f, 13.242640f, 13.656854f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  6.146264f,  5.732051f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  2.414214f,  2.732051f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f, 13.899493f, 13.485280f, 13.071067f, 12.656854f, 12.242640f, 11.828427f, 12.242640f,  6.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.146264f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.000000f,  2.414214f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f, 13.313707f, 12.899494f, 12.485280f, 12.071067f, 11.656854f, 11.242640f, 10.828427f, 11.242640f,  5.560478f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.560478f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  9.706741f, 10.120955f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f, 12.899494f, 11.899494f, 11.485281f, 11.071067f, 10.656854f, 10.242640f,  9.828427f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  6.974691f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.878315f,  8.292528f,  8.706742f,  9.120955f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f, 12.485280f, 11.485281f, 10.485281f, 10.071068f,  9.656854f,  9.242640f,  8.828427f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  6.414214f,  6.828427f,  7.242640f,  7.656854f, 
+     6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f, 12.071067f, 11.071067f, 10.071068f,  9.071068f,  8.656855f,  8.242640f,  7.828427f,  7.414214f,  3.732051f,  3.414214f,  3.732051f,  5.414214f,  5.828427f,  6.242640f,  6.656854f, 
+     7.071068f,  9.024579f,  8.706742f,  8.388905f,  8.071068f,  6.732051f,  7.146264f,  9.024579f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f, 
+     7.706742f,  7.388905f,  7.071068f,  7.388905f, 12.656854f, 11.656854f, 10.656854f,  9.656854f,  8.656855f,  7.656855f,  7.242641f,  6.828427f,  6.414214f,  3.414214f,  3.000000f,  3.414214f,  4.414214f,  4.828427f,  5.242640f,  5.656854f, 
+     6.656854f,  7.656854f,  8.292528f,  7.974691f,  7.656854f,  7.732051f,  8.146264f,  8.560477f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f, 
+     8.706742f,  8.388905f,  8.071068f,  8.388905f, 12.242640f, 11.242640f, 10.242640f,  9.242640f,  8.242640f,  7.242641f,  6.242641f,  5.828427f,  5.414214f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     6.242640f,  7.242640f,  8.242640f,  7.560478f,  7.242640f,  8.732051f,  8.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f, 
+    10.706741f, 10.388905f, 10.071067f, 10.388905f,  6.610366f,  6.196152f,  5.878315f,  8.828427f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  4.414214f,  4.146264f,  3.828427f,  4.146264f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.828427f,  6.828427f,  7.828427f,  8.828427f,  9.828426f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f, 
+     9.706741f,  9.388905f,  9.071068f,  9.388905f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  4.560478f,  4.242640f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.414214f,  6.414214f,  7.414214f,  8.414213f,  9.414213f,  8.828427f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  6.878315f,  7.292529f,  4.828427f,  5.828427f,  6.828427f, 
+     8.706742f,  8.388905f,  8.071068f,  8.388905f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f, 
+     5.000000f,  6.000000f,  7.000000f,  8.000000f,  9.000000f, 10.000000f, 11.000000f, 12.000000f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.878315f,  6.878315f,  7.878315f,  6.146265f,  7.146265f, 
+     7.706742f,  7.388905f,  7.071068f,  7.388905f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.414214f,  6.414214f,  7.414214f,  8.414213f,  9.414213f, 10.414213f, 11.414213f, 12.414213f, 13.414213f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  5.146265f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  7.464102f, 
+     9.242640f,  8.242640f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.828427f,  6.828427f,  7.828427f,  8.828427f,  9.828426f, 10.828426f, 11.828426f, 12.828426f, 13.828426f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146265f,  5.146265f,  6.146265f,  7.146265f,  8.146264f,  9.146264f, 
+     9.560477f,  8.560477f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     6.242640f,  7.242640f,  8.242640f,  9.242640f, 10.242640f, 11.242640f, 12.242640f, 13.242640f, 14.242640f, 15.242640f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f, 
+     6.464102f,  6.146264f,  5.828427f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f, 
+     6.656854f,  7.656854f,  8.656854f,  9.656854f, 10.656854f, 11.656854f, 12.656853f, 13.656853f, 14.656853f, 15.656853f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f, 
+     7.071068f,  8.071068f,  9.071068f, 10.071067f, 11.071067f, 12.071067f, 13.071067f, 14.071066f, 15.071066f, 16.071066f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  9.464102f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  8.071068f,  7.656854f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f, 
+     8.071068f,  8.485281f,  9.485281f, 10.485281f, 11.485280f, 12.485280f, 13.485280f, 14.485280f, 15.485279f, 16.485279f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  9.878315f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.560478f,  6.242640f,  6.560478f,  9.071068f,  8.656854f,  8.242640f,  7.828427f,  7.414214f,  7.000000f,  7.414214f,  7.828427f,  8.242640f,  8.656854f, 
+     9.071068f,  9.485281f,  9.899494f, 10.899494f, 11.899494f, 12.899493f, 13.899493f, 14.899493f, 15.899493f, 16.899492f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f, 10.292528f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  7.242640f,  7.560478f, 10.071067f,  9.656854f,  9.242640f,  8.828427f,  8.414213f,  8.000000f,  8.414213f,  8.828427f,  9.242640f,  9.656854f, 
+    10.071067f, 10.485281f, 10.899494f, 11.313707f, 12.313707f, 13.313707f, 14.313706f, 15.313706f, 16.313705f, 17.313705f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  7.706742f,  8.706742f,  9.706741f, 10.706741f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f,  8.560477f, 11.071067f, 10.656854f, 10.242640f,  9.828426f,  9.414213f,  9.000000f,  9.414213f,  9.828426f, 10.242640f,  3.000000f, 
+     3.414214f,  3.828427f, 11.899494f, 12.313707f, 12.727921f, 13.727921f, 14.727921f, 15.727920f, 16.727921f, 17.727919f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  5.464102f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.878315f, 11.242640f, 10.828426f, 10.414213f, 10.000000f, 10.414213f, 10.828426f, 11.242640f,  3.414214f, 
+     3.732051f,  4.560478f,  4.146264f,  3.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 17.142134f, 18.142134f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.146264f,  4.464102f, 
+     7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.732051f,  4.414214f,  4.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  4.878315f,  4.464102f,  4.146264f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.146264f,  2.828427f,  3.146264f,  0.000000f, 
+     7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.878315f,  4.560478f,  4.242640f, 
+     5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  4.878315f,  4.560478f,  4.828427f,  5.146265f,  5.464102f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     7.000000f,  6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  4.414214f,  4.732051f,  5.146264f,  5.878315f,  5.560478f,  5.242640f, 
+     5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  5.560478f,  5.878315f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  4.828427f,  5.146264f,  5.464102f,  6.878315f,  6.560478f,  6.414214f, 
+     5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.610366f,  6.292529f,  5.974691f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+    11.878315f, 10.878315f,  9.878315f,  8.878315f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  8.560477f,  8.242640f,  8.560477f,  8.878315f,  8.560477f, 10.342416f,  9.342417f,  8.342417f,  7.928203f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f, 
+    11.560477f, 10.560477f,  9.560477f,  8.560477f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  7.242640f,  7.560478f,  8.464102f,  8.196152f,  7.828427f,  9.024579f,  8.024579f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f, 
+    11.242640f, 10.242640f,  9.242640f,  8.242640f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.414214f,  8.706742f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f, 
+    11.560477f, 10.560477f,  9.560477f,  8.560477f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  8.388905f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f, 
+    11.878315f, 10.878315f,  9.878315f,  8.878315f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  8.071068f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f, 
+    12.196152f, 11.196152f, 10.196152f,  9.196152f,  8.196152f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f, 
+     4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  6.196152f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  5.560478f,  5.146264f,  4.732051f,  5.560478f, 
+     5.242640f,  5.560478f,  5.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.878315f,  5.464102f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  6.196152f,  5.196152f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  6.560478f,  6.878315f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  5.146264f,  7.196153f,  6.878315f,  6.560478f,  6.242640f,  6.560478f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  5.878315f,  4.878315f,  4.464102f,  7.560478f,  7.878315f,  8.196152f,  8.610366f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  4.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  4.828427f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f, 
+     6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  8.071068f,  5.878315f,  6.878315f,  7.878315f,  9.146264f,  9.560477f,  7.706742f,  7.388905f,  7.071068f,  7.388905f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  6.878315f,  7.196153f,  8.196153f,  8.146264f,  8.560477f,  8.706742f,  8.388905f,  8.071068f,  8.388905f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.464102f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  7.292529f,  7.610366f,  8.610366f,  7.146264f,  7.560478f,  9.706741f,  9.388905f,  9.071068f,  5.732051f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  4.732051f,  4.414214f,  4.732051f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f, 17.217331f, 16.803116f, 16.388905f, 15.974690f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  3.464102f,  3.146264f,  2.828427f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  3.732051f,  3.414214f,  3.732051f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f, 16.217331f, 15.803117f, 15.388904f, 14.974690f, 14.560477f,  5.560478f,  5.242640f,  5.560478f,  3.146264f,  2.732051f,  2.414214f,  5.146264f,  4.732051f,  4.414214f, 
+     4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  7.000000f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  2.732051f,  2.414214f,  2.732051f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 15.217331f, 14.803117f, 14.388904f, 13.974690f, 13.560477f, 13.146264f, 13.560477f,  7.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.414214f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  1.732051f,  1.414214f,  1.732051f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f, 14.217331f, 13.803118f, 13.388904f, 12.974690f, 12.560477f, 12.146264f, 12.560477f,  6.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.828427f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  1.000000f,  1.414214f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 13.217331f, 12.803118f, 12.388905f, 11.974690f, 11.560477f, 11.146264f, 11.560477f,  5.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.242640f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  1.414214f,  1.732051f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 13.217331f, 12.217332f, 11.803118f, 11.388905f, 10.974691f, 10.560477f, 10.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.656854f, 
+     5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  2.414214f,  2.732051f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f, 12.803118f, 11.803118f, 10.803119f, 10.388905f,  9.974691f,  9.560478f,  9.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f, 
+     6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.414214f,  3.732051f, 
+     6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f, 12.388905f, 11.388905f, 10.388905f,  9.388906f,  8.974691f,  8.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     6.828427f,  8.024579f,  7.706742f,  7.388905f,  7.071068f,  7.388905f,  6.828427f,  8.024579f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.414214f,  4.732051f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f, 11.974691f, 10.974691f,  9.974691f,  8.974691f,  7.974692f,  7.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f, 
+     7.928203f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  8.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f,  8.292528f, 11.560478f, 10.560478f,  9.560478f,  8.560478f,  7.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.560478f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f, 
+    10.292528f,  9.974690f,  9.656854f,  9.974691f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  7.146265f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  6.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f, 
+     9.292528f,  8.974691f,  8.656854f,  8.974691f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  3.828427f,  4.146264f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.732051f,  6.732051f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.974691f,  5.974691f,  5.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.414214f,  6.414214f,  7.414214f,  9.560477f,  8.560477f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  5.560478f,  6.560478f,  4.732051f,  5.732051f,  6.732051f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.732051f,  6.732051f,  7.732051f,  8.732051f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  4.146265f,  5.146265f,  6.146265f,  7.146265f,  6.146265f,  7.146265f, 
+     6.292529f,  5.974691f,  5.656854f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  7.146264f,  8.146264f,  9.146264f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  7.560478f, 
+     5.878315f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.560478f,  7.560478f,  8.560477f,  9.560477f, 10.560477f, 11.560477f, 12.560477f, 13.560477f, 14.560477f, 15.560477f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f, 
+     5.464102f,  5.146264f,  4.828427f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     6.974691f,  7.974691f,  8.974691f,  9.974690f, 10.974690f, 11.974690f, 12.974690f, 13.974690f, 14.974690f, 15.974690f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f, 
+     7.388905f,  8.388905f,  9.388905f, 10.388905f, 11.388904f, 12.388904f, 13.388904f, 14.388904f, 15.388904f, 16.388903f, 17.388903f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f, 
+     8.388905f,  8.803119f,  9.803118f, 10.803118f, 11.803118f, 12.803117f, 13.803117f, 14.803117f, 15.803117f, 16.803116f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  9.560477f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  8.974691f, 
+     9.388905f,  9.803118f, 10.217332f, 11.217331f, 12.217331f, 13.217331f, 14.217330f, 15.217330f, 16.217331f, 17.217329f,  6.196152f,  5.196152f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  9.974690f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  9.120955f,  8.414213f,  8.732051f,  9.146264f,  9.560477f,  9.974690f, 
+    10.388905f, 10.803118f, 11.217331f, 11.631545f, 12.631544f, 13.631544f, 14.631544f, 15.631543f, 16.631542f, 17.631542f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  7.388905f,  8.388905f,  9.388905f, 10.388905f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  9.610365f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  2.828427f, 12.217331f, 12.631544f, 13.045758f, 14.045757f, 15.045757f, 16.045757f, 17.045757f, 18.045755f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.732051f,  5.146264f, 
+     6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  3.732051f,  4.146264f,  4.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  4.146264f,  3.146264f,  2.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 17.459970f, 18.459970f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.732051f,  4.146264f, 
+     7.292529f,  6.974691f,  6.656854f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  4.464102f,  3.464102f,  3.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.414214f,  2.732051f,  3.146264f, 
+     8.292528f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.464102f,  4.146264f,  3.828427f, 
+     5.878315f,  4.878315f,  3.732051f,  2.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146265f,  4.464102f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     9.292528f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.464102f,  5.146264f,  4.828427f, 
+     5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.828427f,  5.146265f,  5.464102f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.146264f,  5.828427f, 
+     5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+    11.464102f, 10.464102f,  9.464102f,  8.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  9.024579f,  8.610366f,  8.196152f,  7.878315f,  7.560478f,  7.242640f,  8.928203f,  7.928203f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f, 
+    11.146264f, 10.146264f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.146264f,  6.828427f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f, 
+    10.828426f,  9.828426f,  8.828427f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  6.414214f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f, 
+    11.146264f, 10.146264f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.000000f,  6.414214f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+    11.464102f, 10.464102f,  9.464102f,  8.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.732051f,  6.196152f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  7.146264f,  5.196152f,  4.878315f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.242640f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.878315f,  4.464102f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  4.878315f,  4.464102f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  4.242640f,  3.828427f,  3.414214f,  6.146264f, 
+     5.828427f,  6.146264f,  6.464102f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  8.292528f,  4.146264f,  6.196153f,  5.878315f,  5.560478f,  5.242640f,  5.560478f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  3.464102f,  3.146264f,  2.828427f,  7.878315f,  8.292528f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  2.828427f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  3.828427f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f, 
+     5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  5.464102f,  6.464102f,  7.464102f,  8.828427f,  9.242640f,  7.292529f,  6.974691f,  6.656854f,  6.974691f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f, 
+     1.000000f,  2.000000f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  5.878315f,  6.878315f,  7.878315f,  7.828427f,  8.242640f,  8.292528f,  7.974691f,  7.656854f,  6.414214f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  6.878315f,  7.292529f,  8.292528f,  6.828427f,  7.242640f,  7.656854f,  5.414214f,  5.000000f,  5.414214f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  4.146264f,  3.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  7.388905f,  7.706742f,  5.414214f,  5.828427f,  6.242640f,  4.560478f,  4.414214f,  4.000000f,  4.414214f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  3.828427f,  3.414214f,  3.000000f, 
+     3.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  4.414214f,  4.828427f,  5.242640f,  4.146264f,  3.414214f,  3.000000f,  3.414214f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.414214f,  4.000000f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.732051f,  2.414214f,  2.000000f,  2.414214f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 15.120955f, 14.706741f, 14.292528f, 13.878315f, 13.560477f, 13.878315f,  6.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.732051f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 14.535169f, 14.120955f, 13.706741f, 13.292528f, 12.878315f, 12.560477f, 12.878315f,  5.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.146264f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.732051f,  4.146264f,  0.000000f,  1.000000f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 13.535169f, 13.120955f, 12.706742f, 12.292528f, 11.878315f, 11.560477f, 11.878315f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.560478f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  1.414214f,  1.000000f,  1.414214f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 12.535169f, 12.120955f, 11.706742f, 11.292529f, 10.878315f, 10.560477f,  4.146264f,  3.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.974691f, 
+     6.656854f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  2.000000f,  2.414214f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f, 12.120955f, 11.120955f, 10.706742f, 10.292529f,  9.974691f, 10.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     6.242640f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  3.000000f,  3.414214f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f, 12.706741f, 11.706741f, 10.706742f,  9.706742f,  9.292529f,  8.974691f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.146264f, 
+     5.828427f,  6.146264f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.000000f,  4.414214f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f, 12.292528f, 11.292528f, 10.292528f,  9.292529f,  8.974691f,  8.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.732051f, 
+     5.414214f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  5.656854f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f, 11.878315f, 10.878315f,  9.878315f,  8.878315f,  8.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.414214f, 
+     6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.656854f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f, 
+     9.878315f,  9.560477f,  9.242640f,  9.560477f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.732051f, 
+     6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  7.656854f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f, 
+     8.878315f,  8.560477f,  8.242640f,  8.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  3.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.242641f,  6.242641f,  4.414214f,  5.414214f,  6.414214f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  2.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  5.828427f,  6.828427f, 
+     5.878315f,  5.560478f,  5.242640f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     6.464102f,  7.464102f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  7.242641f, 
+     4.878315f,  4.560478f,  4.242640f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     6.878315f,  7.878315f,  7.560478f,  6.732051f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  7.000000f,  8.000000f, 
+     4.464102f,  4.146264f,  3.828427f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146265f,  7.146265f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f, 
+     7.292529f,  8.292528f,  6.560478f,  5.732051f,  5.414214f,  5.732051f,  6.146265f,  6.560478f,  6.974692f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.146265f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f, 
+     7.706742f,  8.706742f,  5.560478f,  4.732051f,  4.414214f,  4.732051f,  5.146265f,  5.560478f,  6.560478f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.146265f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f, 
+     8.706742f,  9.120955f,  4.560478f,  3.732051f,  3.414214f,  3.732051f,  4.146265f,  5.146265f,  6.146265f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  8.242640f,  9.242640f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  4.146264f,  2.732051f,  2.414214f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  8.656854f,  9.656854f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  2.732051f,  1.732051f, 12.949382f, 13.949382f, 14.949382f, 15.949381f, 16.949381f, 17.949381f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  9.071068f, 10.071067f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  9.196152f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  2.414214f, 12.949382f, 13.363596f, 14.363595f, 15.363595f, 16.363594f, 17.363594f, 18.363592f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.828427f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  9.610365f,  4.878315f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  3.732051f,  2.732051f,  1.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 17.777807f, 18.777807f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  3.828427f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  4.146264f,  3.146264f,  2.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.414214f,  2.828427f, 
+     7.878315f,  7.560478f,  7.242640f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.146264f,  3.732051f,  3.414214f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  1.000000f,  1.414214f,  2.414214f, 
+     8.878315f,  8.560477f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.732051f,  4.414214f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.732051f,  5.414214f, 
+     6.974691f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.732051f,  6.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+    11.146264f, 10.146264f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  9.024579f,  8.024579f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f, 
+    10.732051f,  9.732051f,  8.732051f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f, 
+    10.414213f,  9.414213f,  8.414213f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+    10.732051f,  9.732051f,  8.732051f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.000000f,  5.414214f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.414214f,  5.732051f,  6.146264f,  5.464102f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.464102f,  4.464102f,  4.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  5.146264f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.878315f,  3.464102f,  3.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  4.146264f,  3.732051f,  3.414214f,  6.560478f,  6.974691f,  7.388905f,  4.560478f,  6.560478f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  6.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  7.292529f,  3.146264f,  2.732051f,  4.878315f,  4.560478f,  4.242640f,  4.560478f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     6.414214f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  7.706742f,  2.828427f,  2.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  8.706742f,  9.024579f,  7.292529f,  6.878315f,  6.560478f,  6.242640f,  6.560478f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  5.464102f,  5.146264f,  4.560478f,  4.146264f,  3.732051f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  5.560478f,  6.560478f,  7.560478f,  8.706742f,  8.292528f,  7.878315f,  7.560478f,  6.414214f,  4.464102f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.732051f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  5.974691f,  6.974691f,  7.974691f,  7.146265f,  7.560478f,  5.146264f,  5.464102f,  5.414214f,  5.732051f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.828427f,  3.414214f,  3.000000f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  6.974691f,  7.388905f,  5.732051f,  4.146265f,  3.828427f,  4.146264f,  4.464102f,  4.414214f,  4.732051f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  3.732051f,  3.414214f, 
+     3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  7.974691f,  4.414214f,  4.732051f,  5.146264f,  2.828427f,  3.146264f,  3.464102f,  3.414214f,  3.732051f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.414214f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.414214f,  2.732051f,  3.146264f,  2.414214f,  2.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 15.438792f, 15.024579f, 14.610366f,  6.146264f,  5.732051f,  5.414214f,  6.414214f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  6.146264f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.414214f,  2.828427f,  1.414214f,  1.732051f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 14.438793f, 14.024579f, 13.610366f, 13.292528f, 12.974690f, 13.292528f,  5.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.464102f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  2.732051f,  3.146264f,  1.000000f,  1.414214f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 13.438793f, 13.024580f, 12.610366f, 12.292528f, 11.974690f, 12.292528f,  4.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.974691f, 
+     6.656854f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.146264f,  1.732051f,  1.414214f,  1.732051f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 12.853006f, 12.438793f, 12.024580f, 11.706742f, 11.388905f, 11.560477f,  3.828427f,  3.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.974691f, 
+     5.656854f,  5.974691f,  6.292529f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  2.732051f,  2.414214f,  2.732051f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 12.438793f, 11.438793f, 11.024580f, 10.706742f, 10.388905f, 10.706742f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.000000f,  4.414214f,  4.828427f,  5.560478f, 
+     5.242640f,  5.560478f,  5.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  6.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f, 12.024579f, 11.024580f, 10.706742f, 10.292529f,  9.974691f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.828427f,  5.146264f, 
+     4.828427f,  5.146264f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.414214f,  4.732051f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f, 11.610366f, 10.610366f, 10.292528f,  9.974691f,  9.560478f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  5.974691f,  5.560478f,  5.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f, 12.292528f, 11.292528f, 10.292528f,  9.878315f,  9.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.828427f,  4.414214f, 
+     4.000000f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  6.560478f,  6.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f, 
+     9.464102f,  9.146264f,  8.828427f,  9.146264f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.732051f,  5.146264f,  4.732051f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  7.560478f,  7.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f, 
+     8.464102f,  8.146264f,  7.828427f,  8.146264f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  3.414214f,  3.828427f,  4.732051f,  5.146264f,  6.560478f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  8.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146265f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f,  3.732051f,  4.146264f,  4.560478f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  9.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146265f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f,  2.732051f,  3.146264f,  4.146264f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146265f,  6.146265f,  7.146265f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146265f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  7.000000f,  4.146264f,  1.732051f,  2.732051f,  3.732051f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  6.560478f,  7.560478f, 
+     4.464102f,  4.146264f,  3.828427f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  7.974692f, 
+     3.464102f,  3.146264f,  2.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  5.878315f,  6.196153f,  5.000000f, 
+     5.414214f,  5.828427f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  5.828427f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  6.878315f,  7.196153f,  4.000000f, 
+     4.414214f,  4.828427f,  5.242640f,  6.560478f,  6.242640f,  6.560478f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.000000f, 
+     3.414214f,  3.828427f,  4.242640f,  3.414214f,  3.000000f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  9.560477f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  4.732051f,  4.414214f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  2.828427f,  3.828427f,  2.414214f,  2.000000f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.560478f,  4.146264f,  3.732051f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  9.974690f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  3.414214f,  1.414214f,  1.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 10.388905f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.000000f,  1.000000f,  0.000000f, 
+     1.000000f,  2.000000f,  2.000000f,  1.000000f,  0.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.146264f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  9.706741f, 10.706741f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  2.732051f,  3.146264f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.414214f,  3.000000f, 
+     3.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  1.732051f,  2.732051f, 
+     8.464102f,  8.146264f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.414214f,  4.000000f, 
+     4.414214f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  1.000000f,  1.414214f,  2.414214f, 
+     8.560477f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.414214f,  5.000000f, 
+     6.656854f,  6.242640f,  5.828427f,  5.414214f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+    10.828426f,  9.828426f,  8.828427f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f, 
+    10.414213f,  9.414213f,  8.414213f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+    10.828426f,  9.828426f,  8.828427f,  7.828427f,  8.146264f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f, 
+     0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.000000f,  4.414214f,  4.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.414214f,  4.732051f,  5.146264f,  5.146265f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.146264f,  5.464102f,  4.146265f,  3.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f, 
+     4.000000f,  4.414214f,  4.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.878315f,  6.196152f,  2.732051f,  2.414214f,  3.146264f,  2.828427f,  3.146264f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  3.828427f,  3.414214f,  3.000000f,  6.242640f,  6.656854f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f, 
+     5.000000f,  5.414214f,  5.828427f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.292529f,  6.610366f,  1.732051f,  1.414214f,  4.146264f,  3.828427f,  4.146264f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.464102f,  4.464102f,  3.464102f,  6.828427f,  6.414214f, 
+     6.000000f,  6.414214f,  6.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  7.292529f,  7.610366f,  1.414214f,  1.000000f,  5.146264f,  4.828427f,  5.146264f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     7.000000f,  7.414214f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  8.292528f,  8.610366f,  7.560478f,  6.560478f,  6.146264f,  2.732051f,  3.732051f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  2.828427f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  9.292528f,  9.610365f,  7.974691f,  7.560478f,  2.732051f,  3.146264f,  4.146264f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  4.878315f,  4.560478f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  6.196153f,  7.196153f,  5.242640f,  5.656854f,  6.656854f, 10.292528f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.828427f,  6.146264f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.732051f,  3.414214f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.000000f,  5.878315f,  6.878315f,  6.242640f,  6.656854f,  7.071068f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.828427f,  5.146264f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.828427f, 
+     4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.242640f,  7.656854f,  4.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.828427f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.828427f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.828427f,  3.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  6.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  7.560478f,  6.560478f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.414214f,  2.732051f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 14.756631f, 14.342417f, 14.024579f, 13.706741f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  7.878315f,  7.560478f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.000000f,  2.414214f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 13.756631f, 13.438793f, 13.120955f, 12.803118f, 12.974690f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  6.878315f,  6.560478f, 
+     6.242640f,  6.560478f,  6.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.414214f,  2.732051f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 12.756631f, 12.438793f, 12.120955f, 11.803118f, 12.120955f,  4.146264f,  3.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.878315f,  5.560478f, 
+     5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  5.560478f,  5.878315f,  6.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  3.732051f,  4.146265f,  2.828427f,  3.146264f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 12.756631f, 12.438793f, 12.024580f, 11.706742f, 11.388905f, 11.706742f,  3.146264f,  2.732051f,  2.414214f,  4.732051f,  4.414214f,  4.732051f,  4.878315f,  4.560478f, 
+     4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.732051f,  5.146265f,  3.828427f,  4.146264f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 12.342417f, 12.024579f, 11.706741f, 11.292529f, 10.974691f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.732051f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.146265f,  4.828427f,  5.146264f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f, 12.024579f, 11.610366f, 11.292528f, 10.974691f, 10.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.828427f,  6.146264f, 
+    10.146264f,  9.732051f,  9.414213f,  6.732051f,  7.146264f,  7.560478f, 11.706741f, 11.292528f, 10.878315f, 10.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f, 
+     9.146264f,  8.732051f,  8.414213f,  8.732051f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.000000f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  7.146264f,  6.828427f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f, 
+     8.146264f,  7.732051f,  7.414214f,  7.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  3.732051f,  4.000000f,  4.414214f,  4.464102f,  4.146264f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  8.464102f,  8.146264f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  3.000000f,  3.414214f,  3.828427f,  5.828427f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  2.000000f,  2.414214f,  2.828427f,  6.146264f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  5.464102f,  6.464102f,  7.464102f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  6.878315f,  7.878315f, 
+     4.146264f,  3.732051f,  3.414214f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.292529f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     4.732051f,  5.146264f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  5.146264f,  5.560478f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  9.464102f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.732051f,  3.414214f, 
+     3.732051f,  4.146264f,  4.560478f,  3.732051f,  3.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  9.878315f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  4.146264f,  2.732051f,  2.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  3.414214f,  3.000000f,  6.292529f,  7.292529f,  4.242640f,  5.242640f, 10.292528f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  3.732051f,  1.732051f,  1.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  3.414214f,  4.414214f,  1.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  9.974690f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  9.388905f, 10.388905f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.732051f,  2.414214f, 
+     2.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.464102f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  8.803119f,  9.803118f,  5.560478f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  3.732051f,  3.414214f, 
+     3.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  2.732051f,  3.146264f, 
+     8.146264f,  7.732051f,  7.414214f,  7.732051f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.732051f,  4.414214f, 
+     4.732051f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  2.414214f,  2.828427f, 
+     9.146264f,  8.732051f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.732051f,  5.414214f, 
+     5.974691f,  6.560478f,  5.146264f,  4.732051f,  4.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  2.414214f,  2.732051f,  3.146264f, 
+    11.146264f, 10.146264f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f, 13.706741f,  8.196152f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+    10.732051f,  9.732051f,  8.732051f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     8.560477f,  8.146264f,  7.732051f,  7.414214f,  7.732051f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.146264f,  5.732051f,  5.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  4.464102f,  4.878315f,  3.414214f,  3.000000f,  1.732051f,  1.414214f,  1.732051f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  5.146264f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.878315f,  5.196152f,  2.414214f,  2.000000f,  2.732051f,  2.414214f,  2.732051f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.146264f,  3.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  6.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.878315f,  6.196152f,  1.414214f,  1.000000f,  3.732051f,  3.414214f,  3.732051f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  7.974691f,  8.388905f,  7.974691f,  7.560478f,  7.146264f,  6.732051f, 
+     6.414214f,  6.732051f,  7.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.878315f,  7.196152f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146264f,  8.146264f,  7.732051f, 
+     7.414214f,  7.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.878315f,  8.196152f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.828427f,  3.414214f,  3.000000f, 
+     3.414214f,  8.732051f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  8.878315f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.242640f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  4.146264f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.242640f,  3.828427f,  4.000000f,  4.414214f,  4.828427f,  6.242640f,  6.560478f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  4.146264f,  4.146264f,  3.828427f, 
+     4.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.732051f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.242640f,  5.560478f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.242640f, 
+     4.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  6.000000f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.242640f,  4.560478f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.242640f, 
+     5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  5.196152f,  4.878315f,  4.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.828427f,  4.146264f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  7.974691f,  6.974691f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.414214f,  3.732051f, 
+     2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f, 14.853006f, 14.535169f,  7.146264f,  6.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  7.464102f,  7.146264f, 
+     6.828427f,  7.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.000000f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 14.170844f, 13.853006f, 13.535169f, 13.217331f, 13.535169f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  6.464102f,  6.146264f, 
+     5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  5.560478f,  5.878315f,  6.196152f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.414214f,  3.732051f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 13.756631f, 13.438793f, 13.120955f, 12.803118f, 13.120955f,  4.464102f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.732051f,  8.146264f,  6.610366f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  3.828427f,  4.146264f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 13.438792f, 13.024580f, 12.706742f, 12.388905f, 12.706742f,  3.464102f,  3.146264f,  2.828427f,  5.146264f,  4.828427f,  5.146264f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.732051f,  7.146264f,  7.560478f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.242640f,  4.560478f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f, 13.024579f, 12.706741f, 12.292529f, 11.974691f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.000000f,  5.414214f,  5.828427f,  5.242640f,  5.560478f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f, 13.024579f, 12.610366f, 12.292528f, 11.974691f, 11.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.560478f, 
+     9.828426f,  9.414213f,  9.000000f,  6.414214f,  6.828427f,  7.242640f, 12.706741f, 12.292528f, 11.878315f, 11.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.732051f,  6.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  7.878315f, 
+     8.828427f,  8.414213f,  8.000000f,  8.414213f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.242640f,  5.242640f,  4.242640f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f, 
+     7.828427f,  7.414214f,  7.000000f,  7.414214f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  4.732051f,  4.414214f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.560478f,  5.560478f,  4.560478f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f, 
+     6.828427f,  6.414214f,  6.000000f,  6.414214f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  3.732051f,  3.414214f,  3.732051f,  4.464102f,  4.146264f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  5.878315f,  4.878315f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  2.732051f,  2.414214f,  2.732051f,  5.464102f,  5.732051f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.878315f,  5.878315f,  6.878315f,  7.878315f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.146264f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.292529f,  7.196153f,  8.196153f, 
+     3.828427f,  3.414214f,  3.000000f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  7.706742f,  8.610366f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  8.560477f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  9.120955f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  8.146264f,  8.464102f,  8.878315f,  5.878315f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  9.878315f, 
+     2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  5.146264f,  5.464102f,  6.414214f,  7.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  4.464102f,  4.464102f,  4.146264f,  6.414214f,  6.732051f,  7.146264f,  8.242640f,  8.560477f,  8.878315f,  9.196152f,  4.878315f,  4.560478f,  4.878315f,  5.196152f,  4.732051f,  5.146264f,  5.560478f,  9.196153f, 10.196153f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  7.146264f,  6.732051f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  3.464102f,  3.464102f,  3.146264f,  2.828427f,  4.464102f,  3.464102f,  3.146264f,  8.974691f,  9.292528f,  3.464102f,  4.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  7.464102f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  8.242640f,  9.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  4.414214f,  3.414214f,  2.414214f,  2.000000f,  3.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  8.656854f,  9.656854f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  4.146265f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  8.071068f,  9.071068f, 10.071067f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.146264f,  2.828427f, 
+     3.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  4.464102f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f, 
+     6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  8.071068f,  8.485281f,  9.485281f, 10.485281f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.146264f,  3.828427f, 
+     4.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     7.828427f,  7.414214f,  7.000000f,  7.414214f,  7.828427f,  8.242640f,  8.656854f,  9.071068f,  5.414214f,  5.828427f,  6.242640f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.146264f,  4.828427f, 
+     5.146264f,  5.878315f,  5.464102f,  3.414214f,  3.000000f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  6.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.414214f,  3.828427f, 
+     8.828427f,  8.414213f,  8.000000f,  8.414213f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.828427f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.000000f,  3.414214f,  6.414214f,  6.000000f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  3.732051f,  4.146264f, 
+    11.464102f, 10.464102f,  9.464102f,  8.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f, 13.120955f, 12.706741f, 12.292528f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     9.242640f,  8.828427f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f, 12.388904f, 11.974690f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     8.242640f,  7.828427f,  7.414214f,  7.000000f,  7.414214f,  7.828427f,  8.242640f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.464102f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  5.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.732051f,  4.414214f,  1.000000f,  0.000000f,  1.000000f, 
+     5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  6.242640f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.732051f,  3.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  5.464102f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.464102f,  4.878315f,  2.732051f,  2.414214f,  2.414214f,  2.000000f,  2.414214f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  4.464102f,  4.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  6.878315f,  6.464102f,  6.146264f, 
+     5.828427f,  6.146264f,  6.464102f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.464102f,  5.878315f,  1.732051f,  1.414214f,  3.414214f,  3.000000f,  3.414214f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  8.292528f,  8.706742f,  9.120955f,  7.878315f,  7.464102f,  7.146264f, 
+     6.828427f,  7.146264f,  7.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.464102f,  6.878315f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 10.120955f,  8.878315f,  8.464102f,  8.146264f, 
+     7.828427f,  8.146264f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  7.878315f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.414214f,  9.146264f, 
+     8.828427f,  9.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  8.464102f,  3.146264f,  2.732051f,  2.414214f,  6.146264f,  4.146265f,  3.828427f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.560478f,  4.732051f,  4.414214f, 
+     4.732051f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  6.464102f,  6.878315f,  7.292529f,  4.732051f,  5.146264f,  6.656854f,  2.828427f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.560478f,  4.878315f,  4.828427f, 
+     5.146264f,  6.878315f,  6.464102f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  3.414214f,  3.732051f,  4.146264f,  5.656854f,  5.974691f, 
+     5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  4.464102f,  5.242640f, 
+     6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.242640f,  5.560478f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.878315f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  3.732051f,  4.146264f,  5.656854f, 
+     6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.414214f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.828427f,  5.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.464102f,  4.878315f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  8.146264f,  7.732051f, 
+     7.414214f,  7.732051f,  8.146264f,  8.560477f,  5.414214f,  5.732051f,  6.146264f,  6.732051f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.414214f,  4.732051f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.146264f,  4.560478f,  5.560478f,  7.878315f,  7.464102f,  7.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  7.146264f,  6.732051f, 
+     6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  6.464102f,  7.146264f,  7.464102f,  6.878315f,  5.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.000000f,  4.414214f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.828427f,  4.242640f, 14.853006f, 14.535169f, 14.217331f, 14.535169f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  6.878315f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.414214f,  4.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  4.560478f, 14.438793f, 14.120955f, 13.803118f, 14.120955f,  4.878315f,  4.560478f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.828427f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.828427f,  5.146264f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.464102f,  4.878315f, 14.024580f, 13.706742f, 13.388905f, 13.706742f,  4.464102f,  4.146264f,  5.878315f,  5.560478f,  5.242640f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.414214f,  6.828427f,  7.242640f,  6.464102f,  6.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.242640f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.878315f, 14.024579f, 13.706741f, 13.292529f, 12.974691f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.414214f,  5.828427f,  6.242640f,  6.146264f,  5.732051f,  5.878315f,  5.560478f,  5.242640f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.656854f,  5.974691f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.878315f, 13.610366f, 13.292528f, 12.974691f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  5.414214f,  6.292529f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+    10.146264f,  9.732051f,  9.414213f,  6.732051f,  7.146264f,  6.560478f, 13.706741f, 13.292528f, 12.878315f, 12.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     9.146264f,  8.732051f,  8.414213f,  8.732051f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  4.146264f,  3.828427f,  4.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     8.146264f,  7.732051f,  7.414214f,  7.732051f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  5.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.656854f,  7.656854f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  4.146264f,  3.828427f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  5.974691f,  6.974691f,  7.974691f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  3.146264f,  2.828427f,  3.146264f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  5.878315f,  6.292529f,  7.292529f,  8.292528f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  2.732051f,  2.414214f,  2.732051f,  6.146264f,  5.828427f, 
+     4.828427f,  3.828427f,  2.828427f,  7.974691f,  7.560478f,  2.414214f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  5.878315f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  6.610366f,  7.610366f,  8.610366f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.242640f, 
+     5.242640f,  4.242640f,  3.828427f,  7.656854f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  8.024579f,  8.928204f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.656854f,  5.242640f,  4.828427f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  9.438792f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.242640f,  5.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     5.560478f,  6.242640f,  5.828427f,  8.292528f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f, 10.292528f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  7.146264f,  6.828427f,  4.146264f,  3.828427f,  4.878315f,  4.560478f,  4.242640f, 
+     4.560478f,  4.878315f,  6.828427f,  8.610366f,  8.196152f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  8.610366f,  5.464102f,  5.878315f,  6.196152f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  6.146264f,  5.732051f,  5.414214f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  4.464102f,  4.464102f,  4.146264f,  8.610366f,  8.292528f,  7.974691f,  7.656854f,  7.974691f,  8.292528f,  8.610366f,  5.974691f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  6.464102f,  6.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.732051f,  3.414214f,  8.388905f,  8.706742f,  4.560478f,  5.560478f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  9.560477f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.414214f,  3.000000f, 
+     3.414214f,  4.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  9.974690f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.732051f,  3.414214f, 
+     3.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  9.388905f, 10.388905f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.828427f, 
+     4.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146265f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  8.803119f,  9.803118f, 10.803118f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.560478f,  4.242640f, 
+     4.560478f,  5.196152f,  4.878315f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.464102f,  6.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f, 
+     8.146264f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  8.974691f,  9.388905f,  9.803118f, 10.217332f, 11.217331f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.560478f,  5.242640f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.146264f,  5.732051f,  5.414214f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.828427f, 
+     9.146264f,  8.732051f,  8.414213f,  8.732051f,  9.146264f,  9.560477f,  9.974690f, 10.388905f,  6.732051f,  7.146264f,  7.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.878315f,  6.242640f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.732051f,  4.146264f, 
+    10.560477f, 10.146264f,  9.732051f,  8.878315f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f, 12.535168f, 12.120955f, 11.706741f, 11.292528f, 10.878315f, 10.464102f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     9.560477f,  9.146264f,  8.732051f,  8.414213f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f, 11.803118f, 11.388904f, 10.974690f, 10.560477f, 10.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     8.560477f,  8.146264f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  8.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f, 11.071067f, 10.656854f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.878315f,  5.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  5.656854f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.196152f,  4.878315f,  4.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.146265f,  4.828427f,  1.414214f,  1.000000f,  1.414214f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.242640f,  5.560478f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  9.196152f,  4.878315f,  4.560478f, 
+     4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  9.610365f,  5.878315f,  5.560478f, 
+     5.242640f,  5.560478f,  5.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.732051f,  2.414214f,  2.732051f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.414214f,  4.878315f,  4.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f, 10.024579f,  6.878315f,  6.560478f, 
+     6.242640f,  6.560478f,  6.878315f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  5.146264f,  4.732051f,  4.414214f,  6.242641f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  3.732051f,  3.414214f,  4.146265f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.000000f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  8.610366f,  9.024579f,  9.438792f, 10.438792f,  7.878315f,  7.560478f, 
+     7.242640f,  7.560478f,  7.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.146264f,  6.560478f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  9.610366f, 10.024579f, 10.438792f, 10.853005f,  8.878315f,  8.560477f, 
+     8.242640f,  8.560477f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.146264f,  3.146264f,  2.732051f,  2.414214f,  8.928203f,  4.732051f,  4.414214f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.878315f,  6.560478f,  9.560477f, 
+     9.242640f,  9.560477f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  4.464102f,  3.464102f,  6.610366f,  7.610366f,  8.610366f,  3.732051f,  3.414214f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.974691f,  6.656854f, 
+     9.610366f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  2.732051f,  2.414214f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.878315f,  6.196153f, 
+     8.706742f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.464102f,  4.878315f,  1.414214f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  5.464102f,  5.878315f, 
+     8.388905f,  7.560478f,  7.146264f,  6.732051f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  3.146264f,  3.464102f,  4.464102f,  1.000000f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.828427f,  4.146264f,  4.464102f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  5.146264f,  6.656854f, 
+     7.656854f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  7.414214f, 
+     7.000000f,  7.414214f,  7.828427f,  8.242640f,  6.414214f,  6.732051f,  5.414214f,  5.732051f,  6.146264f,  5.464102f,  5.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.732051f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  8.196152f,  7.878315f,  7.560478f,  7.242640f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  6.828427f,  6.414214f, 
+     6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  8.071068f,  5.828427f,  6.146264f,  6.464102f,  5.878315f,  5.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.414214f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 15.535169f,  8.878315f,  8.560477f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.828427f,  5.414214f, 
+     5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  6.242640f,  6.560478f,  6.878315f,  5.974691f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.732051f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 15.120955f, 14.803118f, 15.120955f,  6.610366f,  6.196153f,  5.878315f,  5.560478f,  5.242640f,  5.242640f,  4.828427f,  4.414214f, 
+     4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  6.196152f,  5.878315f,  5.560478f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.146264f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 15.024580f, 14.706742f, 14.388905f, 14.706742f,  5.464102f,  5.146264f,  6.292529f,  5.974691f,  5.656854f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.146264f,  7.560478f,  5.464102f,  5.146264f,  4.828427f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 14.706741f, 14.292529f, 13.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.146264f,  6.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  4.828427f,  5.146264f,  5.464102f,  5.146264f, 14.292528f, 13.974691f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.146264f,  5.560478f,  5.974691f,  4.414214f,  4.000000f,  4.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+    10.464102f, 10.146264f,  9.828426f,  7.242640f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  6.656854f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f, 
+     0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  4.146264f,  4.560478f,  5.560478f,  4.732051f,  4.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     9.464102f,  9.146264f,  8.828427f,  9.146264f,  6.928203f,  7.464102f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  5.146264f,  4.828427f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.146264f,  7.071068f,  7.388905f,  7.706742f,  4.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     8.464102f,  8.146264f,  7.828427f,  8.146264f,  6.610366f,  7.146264f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  5.196152f,  5.560478f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.656854f,  6.974691f,  7.292529f,  5.242640f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  4.878315f,  4.560478f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  8.388905f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.560478f,  4.146264f,  3.828427f,  5.242640f,  4.828427f,  4.414214f, 
+     4.000000f,  4.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  7.706742f,  8.706742f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.732051f,  3.414214f,  3.732051f,  5.828427f,  5.414214f, 
+     5.000000f,  5.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  5.878315f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  7.610366f,  8.024579f,  9.024579f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.974691f,  5.560478f,  5.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.414214f,  3.000000f,  3.414214f,  6.828427f,  6.414214f, 
+     6.000000f,  6.414214f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  5.560478f,  5.146264f,  4.732051f,  6.656854f,  7.071068f,  8.024579f,  8.342417f,  9.342417f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146265f,  3.828427f,  4.146264f,  4.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  7.414214f, 
+     7.000000f,  7.414214f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  5.242640f,  4.828427f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  9.388905f,  9.756630f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.656854f, 
+     6.878315f,  8.706742f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  5.560478f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  9.706741f, 10.706741f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  7.242640f,  7.560478f,  7.560478f,  5.878315f,  5.560478f,  5.242640f, 
+     5.560478f,  9.024579f,  8.024579f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  5.560478f,  7.196152f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  6.242640f,  6.560478f,  6.560478f,  6.878315f,  5.146264f,  4.828427f, 
+     5.146264f,  5.464102f,  5.464102f,  7.928203f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.560478f,  5.242640f,  5.560478f,  5.560478f,  5.878315f,  4.732051f,  4.414214f, 
+     4.732051f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  7.706742f,  7.388905f,  7.071068f,  7.388905f,  7.706742f,  8.024579f,  5.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  5.878315f,  5.560478f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.560478f,  4.878315f,  4.414214f,  4.000000f, 
+     4.414214f,  5.242641f,  4.828427f,  4.414214f,  4.000000f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f, 10.292528f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.146264f,  4.464102f,  4.878315f,  4.414214f, 
+     4.732051f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  9.706741f, 10.706741f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.732051f,  4.146264f,  4.560478f,  4.828427f, 
+     5.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  2.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  9.120955f, 10.120955f, 11.120955f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.464102f,  5.146264f,  4.828427f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f, 
+     8.464102f,  8.146264f,  7.828427f,  8.146264f,  8.464102f,  8.878315f,  9.292528f,  9.706741f, 10.120955f, 10.535169f, 11.535169f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.732051f,  4.146264f,  4.560478f,  5.414214f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f, 
+     9.464102f,  9.146264f,  8.828427f,  9.146264f,  9.464102f,  9.878315f, 10.292528f, 10.706741f, 11.120955f, 11.535169f, 11.949382f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.146264f,  4.464102f,  4.878315f,  5.732051f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  3.414214f,  3.146264f, 
+    10.878315f, 10.464102f,  7.292529f,  6.878315f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f,  5.464102f,  5.146264f, 
+    12.949382f, 11.949382f, 11.535169f, 11.120955f, 10.706741f, 10.292528f,  9.878315f,  9.464102f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.464102f,  5.146264f,  4.828427f,  5.146264f, 
+     9.878315f,  9.464102f,  9.146264f,  6.560478f,  6.146264f,  5.732051f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  5.146264f,  4.732051f, 
+    12.631544f, 11.631545f, 11.217331f, 10.803118f, 10.388905f,  9.974690f,  9.560477f,  9.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     8.878315f,  8.464102f,  8.146264f,  7.828427f,  8.146264f,  5.414214f,  5.000000f,  5.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  8.656854f,  4.828427f,  4.414214f, 
+     4.000000f,  4.414214f,  4.828427f,  5.242640f, 10.071067f,  9.656854f,  9.242640f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  5.414214f,  5.732051f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  5.560478f, 10.388905f,  9.974690f,  9.560477f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  6.146264f,  6.464102f,  5.242640f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.196152f,  5.878315f,  9.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  2.414214f,  2.000000f,  2.414214f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  4.242640f,  4.560478f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  9.610365f, 10.610365f,  5.560478f, 
+     5.242640f,  5.560478f,  5.878315f,  6.196152f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.732051f,  2.414214f,  2.732051f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.828427f,  4.146264f,  4.464102f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  8.928203f,  9.928203f, 10.928203f,  5.974691f, 
+     5.656854f,  5.974691f,  6.292529f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  3.146264f,  2.828427f,  5.560478f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  9.342417f, 10.342416f, 11.342416f,  6.974691f, 
+     6.656854f,  6.974691f,  7.292529f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  4.146264f,  4.146265f,  4.560478f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  6.878315f,  8.928203f,  9.342417f,  9.756630f, 10.756630f,  4.732051f,  7.974691f, 
+     7.656854f,  7.974691f,  8.292528f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.732051f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.878315f,  9.928203f, 10.342416f, 10.756630f,  5.464102f,  5.146264f,  4.828427f, 
+     8.656854f,  8.974691f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  4.146264f,  3.732051f,  7.610366f,  8.610366f,  4.000000f,  4.000000f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  6.196152f,  5.878315f,  5.560478f,  5.242640f, 
+     5.560478f,  9.974690f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  7.828427f,  7.414214f,  7.000000f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  3.414214f,  3.000000f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.292529f,  5.974691f,  5.656854f, 
+     5.974691f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  2.414214f,  2.000000f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  6.974691f,  6.656854f, 
+     8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  1.414214f,  1.000000f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  7.146264f,  6.828427f, 
+     7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.878315f,  6.196152f,  0.000000f, 
+     4.464102f,  4.146264f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  8.928203f,  6.560478f, 
+     7.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.560478f,  4.878315f,  5.196152f,  1.000000f, 
+     4.146264f,  3.732051f,  3.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.928203f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242641f, 
+     7.414214f,  7.732051f,  8.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.146265f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     3.828427f,  3.414214f,  3.000000f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  7.974691f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146265f,  6.732051f, 
+     6.414214f,  6.732051f,  7.146264f,  7.560478f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.878315f,  4.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     4.146264f,  3.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.560478f,  5.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     4.464102f,  4.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.560478f,  6.560478f,  6.242640f,  7.610366f,  7.196153f,  6.878315f,  6.560478f,  6.242640f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     4.878315f,  4.560478f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  3.828427f,  4.242640f, 15.388905f, 15.706742f,  6.464102f,  6.146264f,  7.292529f,  6.974691f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     5.878315f,  5.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 15.292529f, 14.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.560478f,  6.878315f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     7.610366f,  7.292529f,  6.974691f,  4.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 14.974691f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.560478f,  5.878315f,  6.292529f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  6.878315f,  6.464102f,  7.706742f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  4.878315f,  5.878315f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     9.878315f,  9.560477f,  9.242640f,  9.560477f,  6.146264f,  6.464102f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  7.292529f,  7.610366f,  7.928203f,  5.464102f,  5.878315f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  6.656854f,  6.974691f,  7.292529f,  3.828427f,  4.146264f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f, 
+     8.878315f,  8.560477f,  8.242640f,  8.560477f,  7.610366f,  6.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.656854f,  5.974691f,  6.292529f,  4.242640f,  4.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  5.828427f,  6.464102f,  6.146264f,  5.828427f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  6.146265f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.242640f,  5.196152f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.464102f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.414214f,  6.560478f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  3.464102f,  3.146264f,  2.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.414214f,  4.828427f,  5.242640f,  9.438792f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  6.878315f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  4.000000f,  4.414214f,  7.146264f,  6.732051f, 
+     6.414214f,  4.732051f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  9.342417f,  9.756630f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.464102f,  5.464102f,  5.878315f,  4.878315f,  4.464102f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.878315f, 
+     5.464102f,  5.146265f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  8.803119f,  9.756630f, 10.074468f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  6.196152f, 
+     5.878315f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  8.706742f,  9.120955f, 10.120955f,  8.342417f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  6.828427f,  7.146264f,  7.464102f,  6.560478f,  6.242640f, 
+     6.292529f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  4.464102f,  4.146264f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  5.828427f, 
+     6.146264f,  6.464102f,  7.928203f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.414214f, 
+     5.732051f,  6.560478f,  6.146264f,  5.732051f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.000000f, 
+     5.414214f,  6.242641f,  5.828427f,  5.414214f,  5.000000f,  4.464102f,  4.146264f,  7.656854f,  7.974691f,  8.292528f,  4.878315f,  5.878315f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  9.610365f,  5.878315f,  5.560478f,  5.242640f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     5.732051f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f, 10.024579f,  6.878315f,  6.560478f,  5.146264f,  4.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  8.610366f,  9.024579f,  9.438792f, 10.438792f, 11.438792f,  5.242640f,  4.828427f,  4.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146265f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  1.414214f, 
+     8.878315f,  8.560477f,  8.242640f,  8.560477f,  8.878315f,  9.196152f,  9.610365f, 10.024579f, 10.438792f, 10.853005f, 11.853005f,  5.560478f,  5.146264f,  4.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.828427f, 
+     5.414214f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  1.732051f, 
+     9.878315f,  9.560477f,  9.242640f,  9.560477f,  9.878315f, 10.196152f, 10.610365f, 11.024578f, 11.438792f, 11.853005f, 12.267219f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.146264f,  3.464102f,  6.560478f,  6.146264f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.656854f,  5.974691f,  6.292529f,  2.732051f,  2.414214f,  2.732051f, 
+     8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  9.706741f,  6.464102f,  6.146264f, 
+    12.535168f, 11.535169f, 10.535169f, 10.120955f,  9.706741f,  9.292528f,  8.878315f,  8.464102f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.878315f,  5.560478f,  5.242640f,  5.560478f, 
+    10.196152f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  9.388905f,  6.146264f,  5.732051f, 
+    12.217331f, 11.217331f, 10.217332f,  9.803118f,  9.388905f,  8.974691f,  8.560477f,  8.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.560478f,  4.242640f,  4.560478f, 
+     9.196152f,  8.878315f,  8.560477f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  8.071068f,  9.071068f,  5.828427f,  5.414214f, 
+    11.899494f, 10.899494f,  9.899494f,  9.485281f,  9.071068f,  8.656854f,  8.242640f,  7.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.146264f,  3.828427f,  4.146264f, 
+     8.196152f,  7.878315f,  7.560478f,  7.242640f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  9.388905f, 10.388905f,  5.732051f, 
+    12.217331f,  5.732051f,  6.146264f,  9.803118f,  9.388905f,  8.974691f,  8.560477f,  8.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.732051f,  3.414214f,  3.732051f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  4.828427f,  5.146264f,  5.464102f,  4.828427f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  9.706741f, 10.706741f,  6.146264f, 
+     5.828427f,  6.146264f,  6.464102f, 10.120955f,  9.706741f,  9.292528f,  8.878315f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  3.414214f,  3.000000f,  3.414214f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  3.828427f,  4.146264f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f, 10.024579f, 11.024578f,  6.560478f, 
+     6.242640f,  6.560478f,  6.878315f,  7.196152f, 10.024579f,  9.610365f,  9.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  3.414214f,  3.732051f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  2.828427f,  3.146264f,  3.464102f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  9.342417f, 10.342416f, 11.342416f, 12.342416f, 
+     6.656854f,  6.974691f,  7.292529f,  6.974691f,  6.560478f,  6.146264f,  9.610365f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  3.828427f,  5.878315f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  7.706742f,  8.024579f,  8.342417f,  8.660254f,  9.660254f, 10.660254f,  3.414214f,  3.000000f, 
+     7.071068f,  7.388905f,  7.706742f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.732051f,  5.146265f,  5.560478f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  9.342417f,  9.660254f, 10.074467f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  8.388905f,  8.706742f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  4.414214f,  4.000000f,  4.414214f,  3.414214f,  3.732051f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.464102f, 10.342416f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  9.388905f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  5.464102f,  5.146264f,  6.292529f,  7.292529f,  3.414214f,  3.000000f,  3.414214f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.464102f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f, 
+     4.560478f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  8.146264f,  7.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  3.414214f,  3.414214f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.974691f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f, 
+     5.560478f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  2.732051f,  2.414214f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  7.196152f,  6.878315f,  6.560478f,  5.414214f, 
+     7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  1.732051f,  1.414214f, 
+     5.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  4.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.464102f,  6.146264f,  5.828427f, 
+     7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  5.878315f,  1.000000f, 
+     5.732051f,  5.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  6.560478f,  6.242640f, 
+     7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  4.464102f,  4.878315f,  1.414214f, 
+     5.146264f,  4.732051f,  4.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  6.828427f,  6.656854f, 
+     7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     4.828427f,  4.414214f,  4.000000f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.414214f,  6.732051f,  7.146265f,  7.146264f, 
+     6.828427f,  7.146264f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     5.146264f,  4.732051f,  4.414214f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  3.464102f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  7.146264f,  6.828427f,  7.146264f,  6.464102f,  6.146264f, 
+     5.828427f,  6.146264f,  6.464102f,  6.878315f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.146264f,  4.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.464102f,  5.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.560478f,  7.242640f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.560478f,  5.242640f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.828427f,  7.146264f,  7.464102f,  8.292528f,  7.974691f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     5.242640f,  4.242640f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.610366f,  6.292529f,  5.974691f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  7.146264f,  7.656854f,  7.242640f,  6.828427f,  6.414214f,  5.878315f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.560478f,  6.292529f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  6.560478f,  6.146264f,  8.706742f,  7.560478f,  7.146264f,  4.560478f,  4.878315f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  5.878315f,  6.292529f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  8.292528f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  6.242640f,  6.560478f,  6.878315f,  2.828427f,  3.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.414214f,  3.732051f,  4.146264f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.414214f,  3.732051f,  4.146264f,  5.242640f,  5.560478f,  5.878315f,  3.828427f,  4.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f,  8.292528f,  4.828427f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  5.146265f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.292529f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  5.464102f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.878315f,  6.464102f,  6.146264f, 
+     3.828427f,  3.414214f,  4.464102f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.878315f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.000000f,  6.560478f,  5.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  9.196153f,  6.146265f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.414214f,  5.732051f,  5.878315f,  4.878315f, 
+     4.464102f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  8.878315f,  9.292528f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.732051f,  8.146264f,  6.196152f,  5.196152f, 
+     4.878315f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 10.535169f,  2.000000f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  8.560477f,  8.974691f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.732051f,  7.146264f,  7.560478f,  7.242640f, 
+     5.878315f,  8.196152f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  7.610366f,  7.928203f,  1.000000f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  8.242640f,  8.656854f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.732051f,  6.146264f,  6.560478f,  6.974691f, 
+     7.146264f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  7.196152f,  7.610366f,  0.000000f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  8.560477f,  8.974691f,  9.388905f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     6.732051f,  7.560478f,  7.146264f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  6.878315f,  7.292529f,  1.000000f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  8.878315f,  9.292528f,  7.610366f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.414214f,  7.242641f,  6.828427f,  6.414214f,  6.000000f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  6.000000f,  5.146265f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  6.560478f,  3.000000f,  3.414214f, 
+     6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  8.928203f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     5.560478f,  5.242640f,  5.560478f,  3.732051f,  3.414214f,  3.732051f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.414214f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  2.414214f,  2.000000f,  2.414214f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  9.342417f, 10.342416f,  6.464102f,  6.146264f,  5.828427f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.146264f,  4.828427f,  5.146264f,  2.732051f,  2.414214f,  2.732051f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.828427f,  4.146265f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  1.414214f,  1.000000f,  1.414214f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f,  8.292528f,  8.610366f,  8.928203f,  9.342417f,  9.756630f, 10.756630f,  7.464102f,  7.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.146264f, 
+     4.732051f,  4.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.464102f,  3.146264f,  2.828427f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  1.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     9.292528f,  8.974691f,  8.656854f,  8.974691f,  9.292528f,  9.610365f,  9.928203f, 10.342416f, 10.756630f, 11.170843f, 12.170843f,  6.560478f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.242640f,  4.828427f, 
+     4.414214f,  4.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.560478f,  6.242640f,  6.560478f,  0.000000f,  1.000000f,  1.000000f,  1.414214f, 
+    10.292528f,  9.974690f,  9.656854f,  9.974690f, 10.292528f, 10.610365f, 10.928203f, 11.342416f, 11.756629f, 12.170843f, 12.585056f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  2.732051f,  3.146264f,  5.560478f,  5.146264f, 
+     4.732051f,  4.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.974691f,  1.000000f,  1.414214f,  2.000000f,  2.414214f, 
+     7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  9.120955f, 10.120955f,  7.464102f,  7.146264f, 
+    12.120955f, 11.120955f, 10.120955f,  9.120955f,  8.706742f,  8.292528f,  7.878315f,  7.464102f,  7.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  8.706742f,  5.878315f,  6.878315f,  5.974691f,  5.656854f,  5.974691f, 
+    16.045757f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  8.803119f,  9.803118f, 10.803118f,  6.732051f, 
+    11.803118f, 10.803118f,  9.803118f,  8.803119f,  8.388905f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  5.560478f,  5.242640f,  5.560478f, 
+    15.631543f, 15.313706f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  8.071068f,  8.485281f,  9.485281f, 10.485281f,  6.414214f, 
+    11.485280f, 10.485281f,  9.485281f,  8.485281f,  8.071068f,  7.656854f,  7.242640f,  6.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.828427f,  5.146264f, 
+     8.610366f,  8.292528f,  7.974691f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  8.803119f,  9.803118f, 10.803118f,  6.732051f, 
+    11.803118f, 10.803118f,  9.803118f,  8.803119f,  8.388905f,  7.974691f,  7.560478f,  7.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  4.414214f,  4.732051f, 
+     7.610366f,  7.292529f,  6.974691f,  6.656854f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.414214f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  9.120955f, 10.120955f, 11.120955f,  7.146264f, 
+     6.828427f, 11.120955f, 10.120955f,  9.120955f,  8.706742f,  8.292528f,  7.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.000000f,  4.414214f, 
+     6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  3.414214f,  3.732051f,  7.560478f,  7.878315f,  8.196152f,  8.610366f,  9.024579f,  9.438792f, 10.438792f, 11.438792f, 12.438791f, 
+     7.242640f,  7.560478f,  7.878315f,  8.196152f,  9.024579f,  8.610366f,  8.196152f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  4.414214f,  5.146264f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  2.414214f,  2.732051f,  3.146264f,  8.292528f,  8.610366f,  8.928203f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  7.974691f,  8.292528f,  7.974691f,  7.560478f,  8.928203f,  8.610366f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  3.828427f,  4.146264f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  8.706742f,  9.024579f,  9.342417f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  2.828427f,  8.706742f, 10.074467f,  9.660254f,  9.342417f,  9.024579f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.414214f,  5.732051f,  2.828427f,  3.146264f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  9.438792f,  9.756630f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  4.146264f,  7.974691f, 10.074467f,  9.756630f,  9.438792f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  5.828427f,  5.414214f,  5.000000f,  2.732051f,  2.414214f,  2.732051f, 
+     5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.146264f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  3.464102f,  7.292529f,  6.878315f,  6.464102f,  7.464102f,  7.146264f,  8.292528f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  2.414214f,  2.000000f,  2.414214f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  6.560478f,  6.242640f,  6.560478f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.732051f,  2.414214f,  2.732051f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.146264f,  3.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f, 
+     5.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  6.146264f,  5.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  2.828427f,  2.828427f, 
+     4.732051f,  4.414214f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.878315f,  5.146264f,  4.732051f,  4.414214f, 
+     7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  2.732051f,  2.414214f, 
+     4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.732051f,  5.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.878315f,  5.464102f,  5.146264f,  4.828427f, 
+     7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  2.414214f,  2.000000f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  3.732051f,  4.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.878315f,  5.560478f,  5.242640f, 
+     6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.146264f,  4.560478f,  2.414214f, 
+     6.146264f,  5.732051f,  5.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.292529f,  5.974691f,  5.656854f, 
+     7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     5.828427f,  5.414214f,  5.000000f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.292529f,  6.974691f,  6.656854f, 
+     7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     6.146264f,  5.732051f,  5.414214f,  1.414214f,  1.000000f,  2.732051f,  2.414214f,  2.732051f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  6.878315f,  6.560478f, 
+     6.242640f,  6.560478f,  6.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     6.464102f,  6.146264f,  2.732051f,  1.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.610366f,  6.196152f,  5.878315f,  5.560478f, 
+     5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  3.414214f,  3.732051f,  4.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  6.196152f,  5.196152f,  4.878315f,  4.560478f, 
+     4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.146264f,  2.732051f,  2.414214f,  5.146264f,  5.464102f,  4.146265f,  5.146265f, 
+     6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     6.196152f,  5.878315f,  5.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  7.292529f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  6.878315f,  7.292529f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.656854f,  5.656854f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.146264f,  5.828427f,  6.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.242640f,  5.242640f,  4.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  5.146264f,  5.464102f,  5.878315f,  4.732051f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     8.706742f,  8.388905f,  8.071068f,  8.388905f,  8.706742f,  3.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.196152f,  5.196152f,  4.878315f,  4.560478f, 
+     4.242640f,  5.242640f,  5.560478f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.414214f,  4.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     7.706742f,  7.388905f,  7.071068f,  7.388905f,  7.706742f,  4.146265f,  5.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.196152f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  4.146264f,  4.464102f,  5.732051f,  5.878315f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  4.464102f,  5.464102f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  6.828427f,  5.828427f,  4.828427f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  5.146264f,  5.464102f,  4.732051f,  5.146265f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  8.414213f,  8.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.146264f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  6.146264f,  6.464102f,  3.732051f,  4.732051f, 
+     6.464102f,  6.146264f,  7.242640f,  7.560478f,  7.878315f,  8.196153f,  8.414213f,  4.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.464102f,  5.464102f,  4.464102f, 
+     3.464102f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     6.146264f,  5.732051f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  7.828427f,  5.878315f,  4.878315f, 
+     4.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.828427f,  5.414214f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.414214f,  6.828427f,  7.242640f,  5.878315f, 
+     5.464102f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.878315f,  1.414214f, 
+     6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  8.071068f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.414214f,  5.828427f,  6.242640f,  6.656854f, 
+     7.071068f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  4.828427f,  5.242640f,  5.656854f, 
+     6.656854f,  6.242640f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  5.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     5.560478f,  5.242640f,  5.560478f,  5.878315f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  5.000000f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  8.610366f,  9.024579f,  9.438792f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.878315f, 
+     4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.146264f,  8.146264f,  5.414214f,  8.146264f,  6.146264f,  5.732051f,  5.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f,  8.292528f,  8.610366f,  8.928203f,  9.342417f,  9.756630f,  5.464102f,  6.146264f,  5.732051f,  5.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.464102f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.828427f,  3.146264f,  3.464102f,  5.000000f,  5.414214f,  3.732051f,  3.414214f,  5.828427f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  1.732051f, 
+     8.706742f,  8.388905f,  8.071068f,  8.388905f,  8.706742f,  9.024579f,  6.732051f,  7.146264f,  6.196152f,  5.878315f,  7.146264f,  6.732051f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  6.196153f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  1.000000f,  1.414214f, 
+     9.706741f,  9.388905f,  9.071068f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  6.292529f,  5.974691f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.242640f,  4.242640f,  3.828427f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  1.414214f,  1.732051f, 
+    10.706741f, 10.388905f, 10.071068f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  6.974691f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  5.560478f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  1.732051f,  1.414214f,  1.732051f,  2.414214f,  2.732051f, 
+    15.459970f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  8.146264f,  7.828427f,  8.146264f,  8.464102f,  8.878315f,  9.292528f,  9.706741f, 10.120955f, 10.535169f, 11.535169f, 12.706741f, 
+    11.706741f, 10.706741f,  9.706741f,  8.706742f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  7.706742f,  6.196153f,  7.196153f,  8.196153f,  6.656854f,  6.974691f, 
+    15.045757f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  8.974691f,  9.388905f,  9.803118f, 10.217332f, 11.217331f, 12.388904f, 
+    11.388904f, 10.388905f,  9.388905f,  8.388905f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  6.242640f,  6.560478f, 
+    14.631544f, 14.313706f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  7.000000f,  7.414214f,  7.828427f,  8.242640f,  8.656854f,  9.071068f,  9.485281f,  9.899494f, 10.899494f, 12.071067f, 
+    11.071067f, 10.071067f,  9.071068f,  8.071068f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  5.828427f,  6.146264f, 
+    14.217330f, 13.899493f, 14.217331f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  8.974691f,  9.388905f,  9.803118f, 10.217332f, 11.217331f, 12.217331f, 
+    11.388904f, 10.388905f,  9.388905f,  8.388905f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  5.414214f,  5.732051f, 
+     8.024579f, 13.485280f, 13.803118f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.000000f,  7.828427f,  8.146264f,  8.464102f,  8.878315f,  9.292528f,  9.706741f, 10.120955f, 10.535169f, 11.535169f, 12.535168f, 
+    11.706741f, 10.706741f,  9.706741f,  8.706742f,  7.706742f,  7.292529f,  6.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  5.414214f, 
+     7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  3.414214f,  3.000000f,  3.414214f,  8.560477f,  8.878315f,  9.196152f,  9.610365f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f, 11.024578f, 10.024579f,  9.024579f,  8.024579f,  7.610366f,  7.196152f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  4.732051f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  9.292528f,  9.610365f,  9.928203f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f, 10.342416f,  9.342417f,  8.342417f,  7.928203f,  7.610366f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  3.414214f,  3.732051f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  9.706741f, 10.024579f, 10.342416f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f, 10.660254f,  9.660254f,  8.660254f,  8.342417f,  8.024579f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 10.438792f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  3.732051f, 10.074467f,  9.660254f,  9.342417f,  9.024579f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  6.242640f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  8.610366f,  8.196152f,  7.878315f,  5.974691f,  6.292529f,  6.610366f,  4.828427f,  5.242640f,  5.656854f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.414214f,  3.828427f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  1.732051f,  1.414214f,  1.732051f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.146264f,  6.464102f,  4.242640f,  3.828427f,  3.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  3.000000f, 
+     7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.146264f,  4.828427f,  5.146264f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.732051f,  2.414214f,  2.732051f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  3.414214f,  3.732051f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  3.414214f,  3.000000f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.464102f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.196152f,  4.878315f,  4.560478f,  4.242640f, 
+     6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.828427f,  4.242640f,  3.414214f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.414214f,  4.000000f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.196152f,  5.878315f,  5.560478f,  5.242640f, 
+     6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     6.828427f,  6.414214f,  6.000000f,  2.732051f,  2.414214f,  3.414214f,  3.000000f,  3.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.560478f,  5.560478f,  6.878315f,  6.560478f,  6.242640f, 
+     7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.414214f,  3.828427f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     7.146264f,  6.732051f,  6.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.560478f,  6.974691f, 
+     7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.414214f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f, 
+     7.464102f,  7.146264f,  3.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.610366f,  6.292529f,  5.974691f, 
+     5.656854f,  5.974691f,  6.292529f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  3.000000f,  3.414214f,  3.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  6.000000f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.610366f,  6.196152f,  5.878315f,  5.560478f, 
+     5.242640f,  5.560478f,  4.560478f,  4.878315f,  5.196152f,  5.732051f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f, 
+     5.878315f,  5.464102f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.146264f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.656854f,  5.242640f,  4.828427f,  4.414214f, 
+     4.000000f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.974691f,  5.974691f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.974691f,  5.732051f,  5.414214f,  5.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.560478f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.292529f,  5.878315f,  5.464102f,  5.146264f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     3.828427f,  2.828427f,  8.485281f,  8.803119f,  9.120955f,  2.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.196152f,  5.878315f,  5.560478f, 
+     4.560478f,  4.242640f,  4.560478f,  4.878315f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.000000f,  4.414214f,  4.828427f,  4.464102f,  4.146264f,  3.828427f,  4.414214f,  4.828427f,  5.828427f,  5.878315f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.732051f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.414214f,  5.414214f,  5.828427f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  7.828427f,  4.464102f,  4.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.414214f,  5.414214f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  5.560478f,  5.878315f,  4.414214f,  4.828427f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  7.414214f,  7.732051f,  8.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.560478f,  5.560478f,  5.732051f,  4.732051f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  6.560478f,  6.878315f,  3.414214f,  4.414214f, 
+     6.878315f,  6.560478f,  6.242640f,  4.828427f,  7.414214f,  7.000000f,  7.414214f,  7.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  6.610366f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  8.146264f,  5.560478f,  4.560478f, 
+     4.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.196152f,  5.196152f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  6.732051f,  7.146264f,  7.560478f,  5.560478f, 
+     5.146264f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.464102f,  6.464102f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  5.878315f,  4.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f, 
+     6.146264f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  4.560478f,  4.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     6.146264f,  5.828427f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  4.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  4.242640f,  3.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     5.146264f,  4.828427f,  5.146264f,  5.464102f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  4.000000f,  4.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  4.560478f,  4.146264f,  3.732051f,  4.414214f,  4.000000f,  4.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.464102f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  7.732051f,  7.414214f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  9.342417f,  4.464102f,  4.146264f,  5.414214f,  5.000000f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.464102f,  3.464102f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.464102f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f, 
+     7.388905f,  6.974691f,  6.560478f,  6.146264f,  7.706742f,  8.024579f,  5.732051f,  6.146264f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  6.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  4.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  5.242640f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  2.414214f, 
+     7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  5.878315f,  5.560478f,  5.242640f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.828427f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  3.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  2.732051f, 
+     7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.560478f,  6.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  4.146264f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  2.828427f,  3.146264f, 
+    14.459971f, 14.142134f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  9.146264f,  9.464102f,  9.878315f, 10.292528f, 10.706741f, 11.120955f, 11.535169f, 11.949382f, 12.292528f, 
+    11.292528f, 10.292528f,  9.292528f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.560478f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f, 10.292528f,  7.656854f,  7.974691f, 
+    14.045757f, 13.727921f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  8.732051f,  9.146264f,  9.560477f,  9.974690f, 10.388905f, 10.803118f, 11.217331f, 11.631545f, 11.974690f, 
+    10.974690f,  9.974690f,  8.974691f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  7.974691f,  8.974691f,  9.974690f,  7.242640f,  7.560478f, 
+    13.631544f, 13.313707f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  9.242640f,  9.656854f, 10.071067f, 10.485281f, 10.899494f, 11.313707f, 12.313707f, 
+    10.656854f,  9.656854f,  8.656854f,  7.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  8.242641f,  8.656855f,  9.656854f,  6.828427f,  7.146264f, 
+    13.217331f, 12.899493f, 13.217331f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  9.560477f,  9.974690f, 10.388905f, 10.803118f, 11.217331f, 11.631545f, 12.631544f, 
+    10.974690f,  9.974690f,  8.974691f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  8.560478f,  8.974691f,  9.974691f, 10.974690f, 11.974690f, 
+    12.803117f, 12.485280f, 12.803118f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  9.878315f, 10.292528f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f, 
+     3.414214f, 10.292528f,  9.292528f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  8.878315f,  9.292529f, 10.292528f, 11.292528f, 12.292528f, 
+    12.388904f, 12.071067f, 12.388905f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  9.878315f, 10.196152f, 10.610365f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f, 10.610365f,  9.610365f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f,  4.414214f, 
+     8.196152f,  7.878315f,  7.560478f,  5.560478f,  5.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 10.292528f, 10.610365f, 10.928203f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  9.928203f,  8.928203f,  7.928203f,  6.928203f,  6.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  3.414214f,  3.000000f,  3.414214f, 
+     7.878315f,  7.464102f,  7.146264f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 10.706741f, 11.024578f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f, 
+     1.000000f,  2.000000f,  3.000000f,  9.342417f,  8.342417f,  7.928203f,  7.610366f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     7.560478f,  7.146264f,  6.732051f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  3.414214f,  7.242640f,  9.342417f,  8.928203f,  8.610366f,  7.928203f,  7.610366f,  7.292529f,  6.974691f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     7.242640f,  6.828427f,  6.414214f,  6.000000f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  2.828427f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  6.196153f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  5.560478f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     7.560478f,  7.146264f,  6.732051f,  4.464102f,  4.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.732051f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f, 
+     7.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.146264f,  4.560478f,  5.560478f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.656854f,  5.656854f,  5.242640f,  2.828427f,  2.414214f,  2.000000f, 
+     7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.414214f,  2.000000f,  2.414214f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.560478f,  5.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  3.414214f,  3.000000f,  3.414214f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  4.000000f,  4.414214f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.464102f,  4.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  5.000000f,  4.414214f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.732051f,  4.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.464102f,  4.464102f,  5.878315f,  5.464102f,  5.146264f,  4.828427f, 
+     6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.146265f,  5.146265f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.464102f,  6.146264f,  5.828427f, 
+     6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  3.732051f,  4.732051f, 
+     5.146264f,  4.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.560478f,  5.146264f,  4.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  7.146264f,  6.828427f, 
+     7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.732051f,  5.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     6.146264f,  5.828427f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  6.560478f,  6.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.878315f,  5.464102f, 
+     5.146264f,  4.828427f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  7.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.878315f,  4.878315f,  4.464102f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.828427f,  5.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.464102f, 
+     6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146264f,  3.828427f,  5.414214f,  5.828427f,  6.242640f,  6.464102f,  5.464102f,  4.464102f,  3.464102f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.242640f,  5.560478f,  5.878315f,  3.146264f,  3.464102f, 
+     5.560478f,  5.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  6.146264f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.828427f,  5.146264f,  5.464102f,  2.732051f,  3.146264f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.828427f,  4.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.828427f,  4.828427f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  2.414214f,  2.828427f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.146265f,  6.560478f,  6.146264f,  5.732051f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.000000f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  6.414214f,  4.414214f,  4.828427f,  5.242640f,  3.146264f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.464102f,  6.878315f,  6.464102f,  6.146264f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.732051f,  5.414214f,  5.732051f,  6.146265f,  6.560478f,  5.560478f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  7.196152f,  6.878315f,  6.560478f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.414214f,  4.732051f,  5.146264f,  5.464102f,  5.146264f,  4.414214f,  4.732051f,  5.146265f,  5.560478f,  5.146264f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146265f,  5.146265f,  4.732051f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  6.828427f,  7.146264f,  3.146264f,  2.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.000000f,  5.000000f,  4.000000f,  3.000000f, 
+     2.000000f,  1.000000f,  0.000000f,  1.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.732051f,  4.146265f,  4.414214f, 
+     6.292529f,  5.974691f,  5.656854f,  3.414214f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  3.146264f,  2.732051f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.414214f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  6.974691f,  2.732051f,  3.732051f,  4.732051f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.828427f,  5.242640f,  5.656854f,  5.828427f,  4.828427f,  3.828427f, 
+     2.828427f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.414214f,  2.414214f,  4.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.732051f,  7.146264f,  5.878315f,  5.464102f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  8.464102f,  5.242640f,  4.242640f, 
+     3.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.732051f,  2.732051f,  3.414214f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.878315f,  4.878315f,  4.464102f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.464102f,  7.878315f,  5.242640f, 
+     4.828427f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  5.464102f,  4.464102f,  3.464102f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.146264f,  6.464102f,  6.878315f,  7.292529f, 
+     5.828427f,  7.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  3.828427f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.146264f,  4.146264f,  3.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  5.878315f,  6.292529f, 
+     5.732051f,  5.414214f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  3.414214f,  3.732051f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  4.464102f,  4.878315f,  5.146264f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146264f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  3.414214f,  3.000000f,  3.414214f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  4.414214f,  4.732051f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  7.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     7.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  5.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.732051f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  5.146265f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f, 
+     6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  5.242640f,  6.146265f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f, 
+     6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.146264f,  5.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.732051f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  6.560478f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f, 
+    14.045757f, 13.727921f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 10.146264f, 10.464102f, 10.878315f, 11.292528f, 11.706741f,  8.560477f, 12.535168f, 12.949382f, 11.878315f, 
+    10.878315f,  9.878315f,  8.878315f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  9.878315f,  8.656854f,  8.974691f, 
+    13.045758f, 12.727921f, 13.045758f, 13.363595f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  9.732051f, 10.146264f, 10.560477f, 10.974690f, 11.388904f, 11.803118f, 12.217331f, 12.631544f, 13.045758f, 
+    10.560477f,  9.560477f,  8.560477f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.828427f,  6.146264f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  9.560477f, 10.560477f,  8.560477f, 
+    12.631544f, 12.313707f, 12.631544f, 12.949382f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  7.000000f, 10.656854f, 11.071067f, 11.485280f, 11.899494f, 12.313707f, 12.727921f, 
+    10.242640f,  9.242640f,  8.242640f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  7.242641f,  8.242640f,  9.242640f, 10.242640f,  8.146264f, 
+    12.217331f, 11.899494f, 12.217331f, 12.535168f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f, 10.974690f, 11.388904f, 11.803118f, 12.217331f, 12.631544f,  4.414214f, 
+    10.560477f,  9.560477f,  8.560477f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  7.560478f,  8.560478f,  9.560477f, 10.560477f, 11.560477f, 
+    11.803118f, 11.485280f, 11.803118f, 12.120955f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f, 10.878315f, 11.292528f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  9.878315f,  8.878315f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  7.878315f,  8.878315f,  9.878315f, 10.878315f, 11.878315f, 
+    11.388904f, 11.071067f, 11.388905f, 11.706741f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  6.414214f, 11.196152f, 11.610365f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  9.196152f,  8.196152f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  4.414214f,  4.732051f, 
+    10.974690f, 10.656854f, 10.974691f, 11.292528f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 11.610365f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  3.732051f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     8.878315f,  8.464102f, 10.560478f, 10.974691f, 11.388905f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  3.414214f,  4.414214f,  8.024579f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.974691f,  6.656854f,  7.878315f,  8.292528f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     8.560477f,  8.146264f,  5.732051f, 10.656854f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  3.732051f,  7.560478f,  7.146264f,  6.732051f,  8.196152f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     8.242640f,  7.828427f,  4.732051f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     8.560477f,  8.146264f,  3.732051f,  4.146264f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  2.828427f,  3.146264f,  3.464102f,  6.974691f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.464102f,  5.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  2.732051f,  2.414214f,  2.732051f,  5.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  4.414214f,  4.732051f,  5.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  4.414214f,  4.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.414214f,  5.732051f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.828427f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f, 
+     4.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  5.146265f,  5.464102f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  3.828427f,  4.146264f,  4.878315f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f, 
+     5.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  4.146265f,  5.146265f, 
+     4.732051f,  4.414214f,  4.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.146264f,  6.732051f,  6.414214f, 
+     7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.146264f,  5.464102f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.146264f, 
+     5.732051f,  5.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.560478f,  5.146264f, 
+     4.732051f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.146264f,  4.464102f,  4.878315f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.414214f,  2.828427f, 
+     6.732051f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.560478f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  7.878315f,  7.464102f,  7.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  2.828427f,  3.146264f,  2.414214f,  2.732051f,  3.146264f, 
+     7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.560478f,  4.560478f,  6.292529f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.146264f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  7.878315f,  7.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.242640f,  6.560478f,  2.414214f,  2.732051f,  3.146264f, 
+     7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.732051f,  4.732051f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.146264f,  1.414214f,  1.732051f,  2.732051f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  4.464102f,  4.414214f,  4.000000f,  4.414214f,  3.414214f,  3.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.414214f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  7.828427f,  5.732051f,  1.000000f,  1.414214f,  2.414214f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.732051f,  4.732051f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  7.146264f,  6.828427f,  7.146264f,  1.414214f,  1.732051f,  2.732051f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  4.242640f,  4.560478f, 
+     3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.560478f,  5.560478f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  3.828427f,  4.146264f, 
+     7.878315f,  7.560478f,  7.242640f,  1.000000f,  1.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.464102f,  3.732051f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.414214f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  4.146264f,  4.464102f,  3.414214f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.732051f,  4.732051f,  3.732051f, 
+     2.732051f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.146264f,  4.146264f,  3.146264f,  5.000000f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  5.732051f,  3.146264f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.146264f,  4.146264f, 
+     3.146264f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.828427f,  3.828427f,  4.414214f,  4.000000f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.146264f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.146264f,  4.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.560478f,  4.560478f, 
+     4.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146265f,  3.414214f,  3.000000f,  3.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.146264f,  6.464102f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  7.878315f,  8.196153f,  5.560478f, 
+     5.146264f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.828427f,  4.146264f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.878315f,  7.196153f,  7.610366f, 
+     6.146264f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  2.828427f,  3.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  3.146264f,  3.464102f,  4.464102f,  5.560478f,  5.878315f,  6.196153f,  5.828427f, 
+     5.414214f,  5.000000f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  2.732051f,  2.414214f,  2.732051f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  4.146264f,  4.464102f,  4.878315f,  4.560478f,  4.878315f,  5.242640f,  4.828427f, 
+     4.414214f,  4.000000f,  4.414214f,  4.828427f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.464102f,  3.828427f,  4.146264f,  4.464102f,  4.242640f,  3.828427f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  7.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f, 
+     6.878315f,  5.878315f,  4.878315f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.732051f,  3.414214f,  3.732051f,  4.828427f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f, 
+     6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.414214f,  3.000000f,  3.414214f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f, 
+     6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  3.732051f,  3.414214f,  5.000000f,  4.000000f,  3.000000f,  2.000000f, 
+     1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  3.146264f,  5.464102f,  5.146264f,  4.828427f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f, 
+     6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.732051f,  5.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  5.828427f,  6.146265f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  8.071068f, 
+    13.631544f, 13.313707f, 13.631544f, 13.949381f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 11.464102f, 11.878315f, 12.292528f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  8.803119f, 
+    10.464102f,  9.464102f,  8.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  9.464102f, 10.464102f,  9.974690f, 
+    12.631544f, 12.313707f, 12.631544f, 12.949382f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f, 11.146264f,  7.388905f, 11.974690f, 12.388904f,  7.242640f,  7.656854f,  8.071068f,  8.485281f, 
+    10.146264f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 10.146264f,  9.560477f, 
+    11.631545f, 11.313707f, 11.631545f, 11.949382f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  6.974691f, 11.656854f, 12.071067f, 12.485280f, 12.899493f, 13.313707f,  8.803119f, 
+     9.828426f,  8.828427f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f,  9.828426f,  9.146264f, 
+    11.217331f, 10.899494f, 11.217331f, 11.535169f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  6.560478f, 11.974690f, 12.388904f, 12.803117f,  5.464102f,  5.146264f,  4.828427f, 
+     5.146264f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  6.000000f,  6.414214f,  5.146265f,  6.146265f,  7.146265f,  8.146264f,  9.146264f, 10.146264f, 11.146264f, 
+    10.803118f, 10.485281f, 10.803118f, 11.120955f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  6.146264f,  6.464102f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  4.464102f,  8.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  6.414214f,  6.732051f,  7.146264f,  6.464102f,  7.464102f,  8.464102f,  9.464102f, 10.464102f,  3.828427f, 
+    10.388905f, 10.071067f, 10.388905f, 10.706741f, 11.024579f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.414214f,  5.732051f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  3.464102f,  4.464102f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  9.120955f,  4.828427f,  5.146264f, 
+     9.974690f,  9.656854f,  9.974691f, 10.292528f, 10.706741f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.146264f,  4.464102f,  5.000000f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  4.146264f,  5.146264f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  7.242640f,  7.560478f,  7.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     9.560477f,  9.242640f,  9.560478f,  9.974691f, 10.388905f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.414214f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  2.828427f,  3.828427f,  4.828427f,  8.464102f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     9.560477f,  5.000000f,  9.242640f,  9.656854f, 10.071067f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.146264f,  4.146264f,  7.878315f,  7.464102f,  7.146264f,  6.560478f,  6.146265f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     9.242640f,  4.000000f,  4.414214f,  9.974691f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  5.146265f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     9.560477f,  3.000000f,  3.414214f,  3.828427f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  6.414214f,  6.000000f,  6.414214f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f, 
+     1.000000f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.878315f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  1.414214f,  1.732051f,  6.560478f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  5.242640f,  4.242640f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  2.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  1.000000f,  1.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.146264f,  4.828427f,  5.146264f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.560478f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f, 
+     3.414214f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  1.414214f,  1.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  5.828427f,  6.146264f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.242640f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f, 
+     4.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.414214f,  2.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  5.560478f,  5.878315f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.560478f,  4.242640f,  4.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f, 
+     5.414214f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.732051f,  4.146265f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  4.560478f,  3.146264f, 
+     4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+     5.878315f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242641f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  3.414214f,  3.000000f,  3.414214f,  1.414214f,  1.732051f,  2.732051f, 
+     5.414214f,  5.000000f,  5.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  5.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.242640f,  5.560478f,  5.878315f, 
+     8.388905f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  5.464102f,  5.878315f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  3.414214f,  3.732051f,  1.000000f,  1.414214f,  2.414214f, 
+     6.414214f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  4.242640f,  4.560478f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.656854f,  4.242640f,  3.828427f, 
+     3.414214f,  3.000000f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  5.464102f,  5.146265f,  4.828427f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.828427f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     9.196152f,  8.878315f,  5.560478f,  4.560478f,  4.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.828427f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  7.196152f,  6.878315f,  6.560478f,  5.560478f,  5.146265f,  4.732051f,  4.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     8.878315f,  8.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.414214f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     4.560478f,  4.146264f,  3.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  3.414214f,  3.828427f,  4.146264f,  3.828427f,  4.146264f,  7.464102f,  4.878315f,  5.000000f,  4.000000f,  3.000000f,  2.000000f, 
+     1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  8.242640f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  4.146264f,  3.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.414214f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.464102f,  5.146264f,  4.828427f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  7.560478f,  7.242640f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.828427f,  4.828427f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.828427f,  5.560478f,  5.242640f,  4.242640f,  4.560478f,  4.878315f,  6.878315f,  6.560478f,  6.242640f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     8.464102f,  8.146264f,  7.828427f,  1.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.242640f,  5.242640f,  4.242640f,  3.828427f, 
+     3.414214f,  3.146264f,  2.828427f,  3.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.656854f,  5.242640f,  5.560478f,  5.878315f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  3.146264f,  2.828427f,  3.146264f, 
+     7.464102f,  7.146264f,  6.828427f,  1.414214f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  1.000000f,  1.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  2.732051f,  2.414214f,  2.732051f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  2.414214f,  2.828427f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.828427f,  4.828427f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.000000f,  2.414214f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.560478f,  4.560478f,  5.732051f,  5.414214f,  3.414214f,  3.732051f,  4.146264f,  2.414214f,  2.732051f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.464102f,  4.464102f, 
+     4.146264f,  3.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.242641f,  5.732051f,  4.732051f,  4.414214f,  3.000000f,  3.414214f,  3.828427f,  2.828427f,  3.146264f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.414214f,  4.000000f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.414214f,  6.000000f,  4.878315f, 
+     4.560478f,  4.732051f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.560478f,  4.732051f,  3.732051f,  3.414214f,  3.732051f,  3.732051f,  4.146264f,  4.560478f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.732051f,  6.414214f,  6.732051f, 
+     5.560478f,  5.732051f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.414214f,  3.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.146264f,  4.560478f,  5.560478f,  7.292529f,  7.610366f,  7.146264f, 
+     6.732051f,  6.732051f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  2.732051f,  2.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.464102f,  4.878315f,  5.974691f,  6.292529f,  6.560478f,  6.146264f, 
+     5.732051f,  5.414214f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  4.878315f,  5.196152f,  5.560478f,  5.878315f,  5.560478f,  5.146264f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146265f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.878315f,  4.828427f,  5.146264f,  5.560478f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146265f,  5.828427f,  6.146264f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  6.292529f,  7.292529f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.414214f,  4.732051f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.000000f,  5.732051f,  4.732051f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  5.146265f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f, 
+     5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.732051f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  6.146265f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f, 
+     6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.828427f,  5.414214f,  5.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  4.732051f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f, 
+    13.217331f, 12.899493f, 13.217331f, 13.535168f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.656854f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f, 
+    10.146264f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 10.146264f, 11.146264f, 
+    12.217331f, 11.899494f, 12.217331f, 12.535168f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.656854f,  6.974691f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  8.071068f, 
+     9.732051f,  8.732051f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  9.732051f, 10.732051f, 
+    11.217331f, 10.899494f, 11.217331f, 11.535169f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.656854f,  5.974691f,  6.292529f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f, 
+     9.388905f,  8.414213f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f,  9.414213f, 10.414213f, 
+    10.217332f,  9.899494f, 10.217332f, 10.535169f, 10.853005f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.878315f,  7.292529f,  7.706742f,  8.706742f, 
+     9.706741f,  5.732051f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  9.732051f, 10.560477f, 
+     9.803118f,  9.485281f,  9.803118f, 10.120955f, 10.438792f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.196152f,  4.878315f,  4.560478f,  4.242640f, 
+     4.560478f,  5.414214f,  5.000000f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 10.146264f,  2.828427f, 
+     9.388905f,  9.071068f,  9.388905f,  9.706741f, 10.024579f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  4.464102f,  5.414214f,  5.732051f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  8.146264f,  8.464102f,  8.878315f,  9.292528f,  9.706741f,  5.560478f,  5.242640f,  2.414214f, 
+     8.974691f,  8.656854f,  8.974691f,  9.292528f,  9.706741f, 10.120955f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  4.146264f,  5.828427f,  6.146264f,  6.464102f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.732051f,  6.146264f,  6.560478f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f, 
+     8.560477f,  8.242640f,  8.560478f,  8.974691f,  9.388905f,  9.803118f,  5.828427f,  6.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.414214f,  4.732051f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f, 
+     3.414214f,  3.828427f,  4.242640f,  6.560478f,  6.878315f,  7.196152f,  6.560478f,  6.146264f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     8.146264f,  7.828427f,  8.242640f,  8.656854f,  9.071068f,  9.485281f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.828427f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  4.146264f,  4.560478f,  8.196152f,  7.878315f,  7.560478f,  6.242641f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     8.560477f,  8.242640f,  8.560478f,  8.974691f,  9.388905f,  9.803118f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.242640f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  2.414214f, 
+     2.732051f,  4.464102f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     3.732051f,  3.414214f,  3.732051f,  6.414214f,  6.000000f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  8.196153f,  7.196153f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  4.828427f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.414214f,  6.732051f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.732051f,  6.732051f,  6.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.414214f,  2.414214f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  7.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  7.146264f,  7.464102f,  6.292529f,  6.146264f,  5.828427f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     1.732051f,  2.732051f,  4.414214f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  7.464102f,  7.146264f,  4.560478f,  4.242640f,  4.560478f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  7.560478f,  7.878315f,  6.878315f,  6.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  4.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  1.000000f,  0.000000f,  1.000000f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  7.560478f,  5.560478f,  5.242640f,  5.560478f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  8.292528f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.732051f,  4.828427f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  1.414214f,  1.000000f,  1.414214f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  6.560478f,  6.242640f,  6.560478f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f, 
+     4.732051f,  5.242640f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  2.000000f,  2.414214f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  5.974691f,  3.828427f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.242640f,  6.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     4.560478f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  3.414214f,  3.828427f,  4.828427f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  2.000000f,  2.414214f,  2.828427f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.464102f,  6.146264f,  5.828427f,  6.146264f,  5.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     4.878315f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  4.414214f,  5.560478f,  5.146264f,  1.000000f,  1.414214f,  2.414214f, 
+     5.732051f,  5.414214f,  5.732051f,  5.560478f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.000000f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f, 
+     7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  6.610366f,  5.878315f,  5.464102f,  0.000000f,  1.000000f,  2.000000f, 
+     8.610366f,  8.292528f,  5.656854f,  5.242640f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.242640f,  5.560478f,  5.878315f, 
+     3.732051f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.292529f,  6.196152f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     8.196152f,  7.878315f,  7.560478f,  5.560478f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.878315f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.242640f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  4.560478f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.974691f,  6.610366f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     7.878315f,  7.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.610366f,  4.732051f,  5.146264f,  6.560478f,  6.242640f,  4.732051f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.292529f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.656854f,  6.146264f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+     4.878315f,  7.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.146264f,  4.560478f,  4.242640f,  4.560478f,  6.464102f,  6.146264f,  5.828427f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.974691f,  6.464102f,  4.414214f,  4.000000f,  4.414214f,  4.828427f, 
+     4.464102f,  3.464102f,  3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  4.146264f,  6.146264f,  4.878315f,  5.878315f,  4.732051f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  7.974691f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  3.464102f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  7.292529f,  6.974691f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     8.146264f,  7.732051f,  7.414214f,  2.000000f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.560478f,  4.560478f,  4.146264f, 
+     3.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.464102f,  4.560478f,  4.242640f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.292529f,  5.974691f,  5.656854f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     7.146264f,  6.732051f,  6.414214f,  2.414214f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146265f,  5.146265f,  4.146264f,  3.828427f,  4.146264f,  6.242640f,  6.560478f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.242640f,  4.242640f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  1.414214f,  1.000000f,  1.414214f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  5.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  6.000000f,  6.414214f,  6.146264f,  5.828427f,  4.414214f,  4.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  5.732051f,  5.414214f,  4.878315f, 
+     4.464102f,  4.146265f,  4.414214f,  4.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.000000f,  5.414214f,  5.146264f,  4.828427f,  4.000000f,  4.414214f,  4.828427f,  2.414214f,  2.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.414214f,  4.732051f,  4.732051f,  5.146264f,  7.196152f,  5.828427f,  5.414214f,  5.000000f,  5.878315f, 
+     5.464102f,  5.146265f,  5.414214f,  5.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.414214f,  4.000000f,  4.414214f,  4.146264f,  3.828427f,  4.146264f,  4.732051f,  5.146264f,  3.414214f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.828427f,  4.146264f,  4.464102f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.242640f,  6.146264f,  5.732051f,  5.414214f,  5.732051f, 
+     5.974691f,  6.146265f,  6.414214f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  3.414214f,  3.000000f,  3.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.732051f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.464102f,  6.146264f,  5.828427f,  6.146264f, 
+     6.464102f,  6.878315f,  7.414214f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.974691f,  6.560478f,  6.878315f,  6.560478f, 
+     6.146264f,  6.610366f,  6.292529f,  5.974691f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.560478f,  6.292529f,  5.878315f,  5.464102f, 
+     5.146264f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.146264f,  5.878315f,  4.878315f,  4.464102f, 
+     4.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f, 
+     6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  6.974691f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.732051f,  5.464102f,  4.464102f,  3.464102f, 
+     3.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f, 
+     5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.000000f,  5.414214f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f, 
+     5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.974691f,  5.560478f,  5.146264f,  4.828427f,  3.828427f,  2.828427f, 
+     2.414214f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  6.146265f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f, 
+     5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f, 
+    12.803117f, 12.485280f, 12.803118f, 13.120955f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  7.560478f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f, 
+     8.974691f,  5.974691f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f,  9.828426f, 10.828426f, 
+    11.803118f, 11.485280f, 11.803118f, 12.120955f, 12.438792f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.242640f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f, 
+     8.656854f,  5.560478f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f,  9.414213f, 10.414213f, 
+    10.803118f, 10.485281f, 10.803118f, 11.120955f, 11.438792f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f, 
+     8.974691f,  5.146264f,  7.000000f,  6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  7.000000f,  8.000000f,  9.000000f, 10.000000f, 
+     9.803118f,  9.485281f,  9.803118f, 10.120955f, 10.438792f, 10.756630f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  5.878315f,  6.292529f,  7.292529f,  8.292528f, 
+     5.146264f,  4.732051f,  4.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f,  9.414213f, 11.560477f, 
+     8.803119f,  8.485281f,  8.803119f,  9.120955f,  9.438792f,  9.756630f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.610366f,  7.610366f,  8.610366f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f,  9.828426f,  2.414214f, 
+     8.388905f,  8.071068f,  8.388905f,  8.706742f,  9.024579f,  9.438792f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.464102f,  5.146264f,  4.828427f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.656854f,  6.610366f,  6.292529f,  5.974691f,  1.732051f,  1.414214f, 
+     7.974691f,  7.656854f,  7.974691f,  8.292528f,  8.706742f,  9.120955f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.560478f,  5.146264f,  4.732051f,  4.414214f, 
+     4.732051f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  1.000000f, 
+     7.560478f,  7.242640f,  7.560478f,  7.974691f,  8.388905f,  8.803119f,  9.803118f,  6.560478f,  5.732051f,  5.414214f,  5.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f, 
+     4.414214f,  4.828427f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  7.560478f,  7.146264f,  6.732051f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  1.414214f, 
+     7.146264f,  6.828427f,  7.242640f,  7.656854f,  8.071068f,  8.485281f,  9.485281f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f, 
+     4.732051f,  4.464102f,  4.878315f,  5.878315f,  5.828427f,  6.242640f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.196152f,  6.610366f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     7.560478f,  7.242641f,  7.560478f,  7.974691f,  8.388905f,  8.803119f,  9.803119f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  5.146264f,  4.242640f,  4.560478f,  7.292529f,  6.292529f,  5.878315f,  3.464102f,  3.146264f,  2.828427f, 
+     3.146264f,  3.464102f,  4.464102f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.610366f,  6.928203f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     4.146264f,  3.828427f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.464102f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.560478f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.732051f,  3.828427f,  4.146264f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  4.414214f,  4.732051f, 
+     3.146264f,  2.828427f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     2.414214f,  3.414214f,  3.732051f,  4.146264f,  5.878315f,  5.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.828427f,  6.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.464102f,  5.146264f,  4.828427f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.242640f,  6.560478f,  6.878315f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.146264f,  4.828427f,  5.146264f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.878315f,  4.732051f,  4.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.974691f,  7.292529f,  6.292529f,  5.974691f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146264f,  3.828427f,  4.146264f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  1.732051f,  1.414214f,  1.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.974691f,  6.656854f,  6.974691f,  7.292529f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.878315f,  5.560478f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     4.560478f,  4.242640f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.292529f,  7.388905f,  7.071068f,  3.414214f,  3.732051f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.732051f,  5.464102f,  5.146264f,  4.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.146264f,  4.560478f,  5.560478f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     5.146264f,  4.828427f,  5.146264f,  5.464102f,  6.146264f,  5.732051f,  5.414214f,  4.732051f,  4.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     4.464102f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.732051f, 
+     6.146264f,  5.828427f,  7.388905f,  7.071068f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.000000f,  4.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.828427f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  2.414214f, 
+     7.610366f,  7.292529f,  6.974691f,  6.656854f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.732051f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+     7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.414214f,  4.732051f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.464102f,  5.878315f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.146264f,  5.828427f,  6.146264f,  6.464102f, 
+     3.146264f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.000000f,  4.414214f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f, 
+     6.878315f,  6.464102f,  6.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.196152f,  6.610366f,  5.146264f,  5.464102f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  6.196152f,  5.878315f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.414214f,  4.732051f,  5.146264f,  6.878315f,  3.414214f,  3.732051f,  4.146265f, 
+     6.560478f,  6.146264f,  5.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.878315f,  5.878315f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.146264f,  5.464102f,  4.732051f,  4.414214f,  4.732051f,  5.146265f, 
+     9.828427f,  5.828427f,  5.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.146264f,  3.464102f,  4.464102f,  4.828427f,  5.146264f,  5.146264f,  4.732051f,  4.414214f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.560478f,  5.878315f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     8.828427f,  4.146264f,  3.732051f,  3.414214f,  3.146264f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  4.732051f,  5.146264f,  4.414214f,  4.000000f,  5.464102f,  4.464102f,  3.464102f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  7.706742f,  5.974691f,  6.292529f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     7.828427f,  7.414214f,  7.000000f,  3.000000f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.414214f,  5.878315f,  4.878315f,  4.464102f, 
+     4.146264f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  7.292529f,  7.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     6.828427f,  6.414214f,  6.000000f,  3.414214f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.828427f,  5.146264f,  5.974691f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146265f,  5.560478f,  5.146264f,  4.828427f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  7.196152f,  6.878315f,  6.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.464102f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.242640f,  5.560478f,  5.656854f,  5.242640f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.828427f,  4.732051f,  4.414214f,  7.146264f,  6.828427f,  7.146264f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  5.464102f,  5.146264f,  5.974691f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146265f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  6.146264f,  6.464102f,  6.414214f,  6.732051f,  7.146264f,  5.732051f,  5.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  5.974691f,  6.292529f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.878315f, 
+     5.464102f,  5.146265f,  4.828427f,  5.146265f,  5.464102f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.732051f,  6.146264f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.000000f,  5.414214f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.146264f,  5.464102f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     5.878315f,  5.560478f,  5.828427f,  6.146265f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.000000f,  5.414214f,  5.828427f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.560478f,  5.732051f,  3.414214f,  3.000000f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     5.146264f,  6.560478f,  6.828427f,  7.146265f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.414214f,  5.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  4.464102f,  4.878315f,  4.000000f,  4.414214f, 
+     2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.464102f,  5.146264f,  4.828427f,  5.146264f, 
+     5.464102f,  5.878315f,  6.878315f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.878315f,  5.560478f,  5.242640f,  5.560478f, 
+     5.878315f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  6.878315f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.560478f,  4.242640f,  4.560478f, 
+     4.878315f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f, 
+     3.828427f,  3.414214f,  4.242640f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.146264f,  3.828427f,  4.146264f, 
+     4.464102f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f, 
+     5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.732051f,  5.878315f,  3.414214f,  3.732051f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f, 
+     5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.242640f,  5.878315f,  6.414214f,  5.560478f,  3.000000f,  3.414214f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f, 
+     5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  6.242641f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f, 
+     5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  2.414214f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  1.000000f, 
+    12.388904f, 12.071067f, 12.388904f, 12.706741f, 13.024579f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f, 
+     8.560477f,  5.560478f,  5.242640f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 10.146264f, 11.146264f, 
+    11.388904f, 11.071067f, 11.388905f, 11.706741f, 12.024579f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.146264f,  5.828427f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f, 
+     8.242640f,  4.560478f,  4.242640f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  9.732051f, 10.732051f, 
+    10.388905f, 10.071067f, 10.388905f, 10.706741f, 11.024579f, 11.342417f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  5.146264f,  4.828427f,  5.146264f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f,  9.414213f, 10.414213f, 
+     9.388905f,  9.071068f,  9.388905f,  9.706741f, 10.024579f, 10.342417f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  9.732051f, 12.560477f, 
+     8.388905f,  8.071068f,  8.388905f,  8.706742f,  9.024579f,  9.342417f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.196152f,  6.196152f,  7.196152f,  4.242640f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 10.146264f,  2.000000f, 
+     7.388905f,  7.071068f,  7.388905f,  7.706742f,  8.024579f,  9.024579f, 10.024579f,  5.560478f,  5.878315f,  6.196152f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.610366f,  7.610366f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.560478f,  4.560478f,  4.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.292529f,  2.414214f,  1.414214f,  1.000000f, 
+     6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.706742f,  8.706742f,  9.706741f,  5.974691f,  6.292529f,  6.610366f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  8.024579f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.878315f,  6.560478f,  1.000000f,  0.000000f, 
+     6.560478f,  6.242640f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  9.388905f,  6.974691f,  7.292529f,  7.610366f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.828427f,  5.414214f,  5.000000f, 
+     5.414214f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  6.464102f,  6.146264f,  1.414214f,  1.000000f, 
+     6.146264f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  8.071068f,  9.071068f,  7.974691f,  8.292528f,  3.828427f,  4.146264f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.560478f,  6.146264f,  5.732051f,  4.242640f, 
+     5.146264f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  6.878315f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  5.464102f,  5.146264f,  5.732051f,  5.414214f,  2.000000f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     4.146264f,  3.828427f,  4.146264f,  4.732051f,  5.146264f,  5.560478f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.414214f, 
+     4.560478f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.878315f,  6.656854f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  7.196152f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f, 
+     4.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.242640f,  5.242640f,  4.732051f,  4.414214f,  3.414214f,  3.000000f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+     3.732051f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.560478f,  6.560478f,  5.560478f,  3.732051f,  3.414214f,  3.732051f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.146264f,  5.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+     3.414214f,  3.000000f,  3.414214f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.242640f,  5.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  2.414214f,  2.000000f,  2.414214f,  6.000000f,  6.414214f,  6.828427f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.656854f,  5.974691f,  6.292529f,  5.878315f,  5.560478f,  5.242640f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     3.146264f,  2.828427f,  3.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.414214f,  2.732051f,  6.414214f,  6.732051f,  7.146264f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.656854f,  6.974691f,  7.292529f,  4.560478f,  4.242640f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  7.610366f,  7.292529f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     5.146264f,  4.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.464102f,  4.878315f,  5.242640f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146264f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.732051f,  5.146264f,  5.560478f,  4.242640f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.560478f,  6.242640f,  6.974691f,  6.656854f,  4.828427f,  4.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.414214f,  3.732051f,  4.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     4.560478f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  3.732051f,  4.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     6.610366f,  6.292529f,  5.974691f,  5.656854f,  3.828427f,  3.414214f,  3.000000f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.828427f,  4.146264f,  4.464102f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+     7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.732051f,  3.414214f,  3.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.732051f,  7.560478f, 
+     7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.464102f,  5.146264f,  4.828427f,  5.146264f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  7.242640f, 
+     6.828427f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.414214f,  3.732051f,  4.146264f,  6.464102f,  6.146264f,  5.828427f,  5.146265f, 
+     5.560478f,  5.146264f,  4.732051f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  5.878315f,  6.196152f,  6.610366f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.828427f, 
+     3.414214f,  3.000000f,  3.414214f,  6.878315f,  6.464102f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.828427f,  4.146264f,  4.464102f,  7.464102f,  7.146264f,  6.828427f,  5.464102f, 
+    10.146264f,  4.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.464102f,  4.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.242640f,  4.560478f,  4.878315f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     9.146264f,  8.732051f,  8.414213f,  4.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.878315f,  4.464102f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.242640f,  5.560478f,  5.878315f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     8.146264f,  7.732051f,  7.414214f,  4.000000f,  4.732051f,  4.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.196152f,  4.878315f, 
+     4.560478f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.414214f,  6.828427f,  7.242640f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     7.146264f,  6.732051f,  6.414214f,  4.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  6.974691f,  6.560478f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146265f,  6.560478f,  6.292529f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.828427f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.242640f,  6.242640f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242641f,  5.732051f,  5.560478f,  5.242640f,  5.560478f,  7.464102f,  6.196153f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  6.560478f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146265f,  5.828427f,  5.414214f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.560478f,  7.878315f,  8.196152f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  9.120955f,  9.438792f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     6.464102f,  6.146265f,  5.828427f,  6.146265f,  6.464102f,  6.146264f,  5.732051f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.828427f,  6.146264f,  6.464102f,  8.292528f,  8.610366f,  8.928203f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  8.388905f,  8.706742f,  9.024579f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     3.828427f,  4.242640f,  6.242641f,  6.560478f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  9.024579f,  6.732051f,  3.732051f,  3.414214f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.974691f,  7.656854f,  7.974691f,  8.292528f,  8.610366f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  5.560478f,  6.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.146264f,  5.464102f,  5.878315f,  4.414214f,  4.732051f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  8.610366f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     4.464102f,  4.878315f,  5.878315f,  6.146264f,  6.242640f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.732051f,  5.146264f,  5.560478f,  4.242640f,  4.560478f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.560478f,  5.560478f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  6.414214f,  4.878315f,  4.560478f,  4.242640f,  4.560478f, 
+     4.878315f,  5.196152f,  5.464102f,  5.146264f,  4.828427f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  4.828427f,  5.242640f,  3.828427f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.242640f,  4.242640f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  6.414214f,  6.000000f,  6.414214f,  4.146264f,  3.828427f,  4.146264f, 
+     4.464102f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.732051f,  5.146264f,  5.560478f,  3.414214f,  3.732051f, 
+     4.146264f,  3.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  5.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  6.828427f,  7.242640f,  6.732051f,  6.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  5.878315f,  3.000000f,  3.414214f, 
+     6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  7.560478f,  7.146264f,  6.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.560478f,  5.878315f,  6.196152f,  3.414214f,  3.732051f, 
+     5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.974691f,  6.292529f,  6.610366f,  3.828427f,  4.146264f, 
+     5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.974691f,  7.292529f,  7.610366f,  4.242640f,  4.560478f, 
+     5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.414214f,  3.000000f,  3.414214f,  5.828427f,  6.146264f,  6.464102f,  0.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  0.000000f, 
+    11.974690f, 11.656854f, 11.974690f, 12.292528f, 12.610366f, 12.928204f,  5.828427f,  6.146264f,  6.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f, 
+     8.146264f,  5.146264f,  4.828427f,  5.146264f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  9.464102f, 10.464102f, 11.464102f, 
+    10.974690f, 10.656854f, 10.974690f, 11.292528f, 11.610366f, 11.928204f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 10.146264f, 11.146264f, 
+     9.974690f,  9.656854f,  9.974691f, 10.292528f, 10.610366f, 10.928204f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  5.146264f,  4.732051f,  4.414214f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f,  9.828426f, 10.828426f, 
+     8.974691f,  8.656854f,  8.974691f,  9.292528f,  9.610366f,  9.928204f, 10.342417f,  5.732051f,  6.146264f,  6.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f, 10.146264f, 11.146264f, 
+     7.974691f,  7.656854f,  7.974691f,  8.292528f,  8.610366f,  8.928204f,  9.928204f,  6.146264f,  6.464102f,  6.878315f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  9.464102f,  2.732051f,  2.414214f, 
+     6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  8.610366f,  9.610366f,  6.560478f,  6.878315f,  7.196152f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.878315f,  6.292529f,  7.292529f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  2.732051f,  1.732051f,  1.414214f, 
+     5.974691f,  5.656854f,  5.974691f,  6.292529f,  7.292529f,  8.292528f,  9.292528f, 10.292528f,  7.292529f,  7.610366f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.292529f,  7.706742f,  4.464102f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.560478f,  2.414214f,  1.414214f,  1.000000f, 
+     5.560478f,  5.242640f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  9.974691f,  7.706742f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.560478f,  4.242640f,  1.732051f,  1.414214f, 
+     5.146264f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  8.656854f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.878315f,  5.560478f,  5.146264f, 
+     4.732051f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  2.414214f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.878315f,  5.464102f,  5.146264f,  4.146264f, 
+     3.732051f,  3.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.878315f,  5.560478f,  5.242640f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.732051f,  5.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  6.146264f,  6.464102f,  6.878315f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+     5.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.196152f,  6.196152f,  6.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  7.878315f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.146264f,  5.732051f,  5.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.414214f,  4.732051f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  5.878315f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f, 
+     4.732051f,  4.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.242640f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.196153f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f, 
+     5.146264f,  4.828427f,  5.146264f,  5.464102f,  6.242640f,  6.560478f,  6.878315f,  4.146264f,  3.828427f,  5.828427f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.464102f,  4.878315f,  5.878315f,  7.196152f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.732051f,  4.414214f,  4.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     4.732051f,  4.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.146264f,  4.828427f,  5.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     5.974691f,  5.656854f,  5.974691f,  7.242640f,  7.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.000000f,  4.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     5.732051f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.828427f,  4.146264f,  3.828427f,  4.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+     4.242640f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.000000f,  3.414214f,  3.828427f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  3.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.146264f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f, 
+     6.464102f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  3.146264f,  2.732051f,  2.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  6.560478f, 
+     6.146264f,  5.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.242640f, 
+     5.828427f,  5.414214f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.732051f,  5.414214f,  5.732051f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.146264f,  5.464102f,  5.878315f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     6.146264f,  5.732051f,  5.414214f,  6.560478f,  6.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.732051f,  6.414214f,  6.732051f, 
+    10.464102f,  3.828427f,  3.414214f,  3.000000f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.464102f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     4.732051f,  4.414214f,  4.732051f,  6.146264f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  7.732051f,  7.414214f,  5.146264f, 
+     9.464102f,  9.146264f,  8.828427f,  3.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.414214f,  4.732051f,  5.146264f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     5.146264f,  4.828427f,  5.146264f,  5.464102f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.146264f,  3.828427f,  4.146264f, 
+     8.464102f,  8.146264f,  7.828427f,  5.000000f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.560478f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  3.146264f,  2.828427f,  3.146264f, 
+     7.464102f,  7.146264f,  6.828427f,  5.414214f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.146264f,  5.560478f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146265f,  6.196152f,  5.878315f,  5.828427f,  5.414214f,  5.000000f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  2.732051f,  2.414214f,  2.732051f, 
+     6.464102f,  6.146264f,  5.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.828427f,  4.146264f, 
+     6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  2.414214f,  2.000000f,  2.414214f, 
+     5.464102f,  5.146264f,  4.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  9.706741f,  5.878315f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  4.464102f,  6.414214f,  4.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  2.732051f,  2.414214f,  2.732051f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  8.071068f,  8.388905f,  8.706742f,  9.024579f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  4.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  7.388905f,  7.071068f,  7.388905f,  7.706742f,  8.024579f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  4.828427f,  4.732051f,  4.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.706742f,  8.024579f,  8.342417f,  6.414214f,  3.828427f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  5.146264f,  4.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  9.024579f,  6.414214f,  6.732051f,  7.146264f,  5.146264f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  3.414214f,  3.000000f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  4.464102f,  5.464102f,  6.464102f,  5.242640f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.146264f,  4.146264f,  3.828427f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  5.732051f,  5.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     4.464102f,  4.878315f,  5.146264f,  4.732051f,  4.414214f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.828427f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.878315f,  5.560478f,  5.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.732051f,  6.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     4.464102f,  4.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  5.732051f,  5.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.464102f,  2.414214f,  2.000000f,  2.414214f, 
+     6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.146264f,  5.828427f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.878315f,  4.464102f,  6.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  2.732051f,  2.414214f,  2.732051f, 
+     6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  5.414214f,  4.414214f,  6.242641f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.196152f,  4.878315f,  7.146264f,  6.828427f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.292529f,  3.146264f,  2.828427f,  3.146264f, 
+     5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.560478f,  5.878315f,  6.196152f,  3.732051f,  7.706742f,  4.146264f,  3.828427f,  4.146264f, 
+     6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.292529f,  6.974691f,  6.974691f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.828427f,  3.414214f,  3.000000f,  1.414214f,  4.828427f,  5.146264f, 
+    11.560477f, 11.242640f, 11.560477f, 11.878315f, 12.196153f, 12.610366f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  9.878315f, 10.878315f, 11.878315f, 
+    10.560477f, 10.242640f, 10.560477f, 10.878315f, 11.196153f, 11.610366f, 12.024579f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  9.560477f, 10.560477f, 11.560477f, 
+     9.560477f,  9.242640f,  9.560477f,  9.878315f, 10.196153f, 10.610366f, 11.024579f,  6.414214f,  6.828427f,  5.242640f,  4.828427f,  4.414214f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  8.242640f,  9.242640f, 10.242640f, 11.242640f, 
+     8.560477f,  8.242640f,  8.560478f,  8.878315f,  9.196153f,  9.610366f, 10.024579f,  6.732051f,  7.146264f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  9.560477f, 10.560477f, 11.560477f, 
+     7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196153f,  8.610366f,  9.610366f,  7.146264f,  7.464102f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  3.146264f,  2.828427f, 
+     6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196153f,  8.196153f,  9.196153f, 10.196153f,  7.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.560478f,  5.974691f,  6.974691f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  5.828427f,  2.732051f,  2.414214f, 
+     5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  9.878315f,  8.292528f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  6.974691f,  7.388905f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  4.828427f,  2.414214f,  2.000000f, 
+     4.560478f,  4.242640f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560478f,  9.560477f,  3.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  8.388905f,  4.560478f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.146264f,  3.828427f,  4.146264f,  2.414214f, 
+     4.146264f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  8.242640f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.828427f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  6.878315f,  6.464102f,  4.242640f,  3.828427f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.974691f,  5.974691f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.828427f,  6.146264f,  5.732051f,  5.414214f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.560478f,  5.242640f,  5.242640f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.146264f,  6.732051f,  7.146264f,  7.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.000000f,  2.000000f, 
+     1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.146264f,  8.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.000000f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+     9.878315f,  9.464102f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  3.732051f,  3.414214f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.828427f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.464102f,  5.732051f,  5.414214f,  6.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     8.878315f,  8.464102f,  8.146264f,  7.828427f,  8.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.242640f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.828427f, 
+     4.414214f,  4.000000f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.560478f,  4.560478f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     5.414214f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.878315f,  4.464102f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     5.878315f,  5.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.196152f,  4.878315f,  4.560478f,  4.414214f,  6.292529f,  5.878315f, 
+     5.464102f,  5.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.974691f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  2.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.242640f, 
+     4.828427f,  4.414214f,  4.000000f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.414214f,  5.000000f,  5.414214f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.000000f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.414214f,  5.000000f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.414214f,  6.000000f,  6.414214f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.414214f,  5.732051f,  6.146264f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  7.000000f,  7.414214f, 
+     9.878315f,  9.560477f,  9.242640f,  2.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.732051f,  7.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.242640f,  4.560478f, 
+     8.878315f,  8.560477f,  8.242640f,  6.000000f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.000000f,  5.414214f,  7.464102f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.732051f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  3.828427f,  4.146264f, 
+     7.878315f,  7.560478f,  7.242640f,  6.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  7.878315f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  5.560478f,  4.878315f,  4.560478f,  4.242640f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  3.414214f,  3.732051f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  4.464102f,  4.146264f,  3.828427f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  3.000000f,  3.414214f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  8.656854f,  8.974691f,  9.292528f,  5.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  4.146264f,  3.732051f,  3.414214f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  6.146264f,  3.414214f,  3.732051f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  8.292528f,  7.974691f,  7.656854f,  7.974691f,  8.292528f,  8.610366f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  3.828427f,  3.414214f,  3.000000f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  5.732051f,  3.828427f,  4.146264f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  3.732051f,  3.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.974691f,  7.292529f,  7.610366f,  5.000000f,  5.414214f,  5.828427f,  2.828427f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.732051f,  2.414214f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  4.732051f,  4.146264f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  8.292528f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.732051f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.828427f,  5.414214f,  4.242640f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  6.878315f,  6.560478f,  6.242640f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.828427f,  6.146264f,  6.464102f,  6.878315f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.732051f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.732051f,  4.414214f,  4.732051f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  4.828427f,  4.414214f,  4.000000f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  5.560478f,  5.974691f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     4.464102f,  4.146264f,  3.828427f,  5.878315f,  5.560478f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  3.414214f, 
+     3.828427f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  5.464102f,  5.146264f,  4.828427f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.242640f,  5.656854f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.732051f,  4.414214f,  4.732051f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.146264f,  5.828427f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  5.560478f,  5.974691f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  4.828427f,  5.146264f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.828427f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.292529f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     2.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  2.732051f,  2.414214f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  6.610366f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  1.732051f,  1.414214f,  1.732051f,  6.242640f,  6.560478f,  6.878315f,  3.146264f,  2.732051f,  2.414214f,  3.732051f,  3.414214f,  3.732051f, 
+     6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.974691f,  5.656854f,  5.974691f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  6.656854f,  6.974691f,  7.292529f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.414214f,  4.732051f, 
+    11.146264f, 10.828426f, 11.146264f, 11.464102f, 11.878315f,  8.414213f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f, 10.292528f, 11.292528f, 12.292528f, 
+    10.146264f,  9.828426f, 10.146264f, 10.464102f, 10.878315f,  8.000000f,  7.000000f,  6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  9.974690f, 10.974690f, 11.974690f, 
+     9.146264f,  8.828427f,  9.146264f,  9.464102f,  9.878315f, 10.292528f, 10.706742f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  8.656854f,  9.656854f, 10.656854f, 11.656854f, 
+     8.146264f,  7.828427f,  8.146264f,  8.464102f,  8.878315f,  9.292529f,  9.706742f,  7.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.974691f,  9.974690f, 10.974690f,  4.242640f, 
+     7.146264f,  6.828427f,  7.146265f,  7.464102f,  7.878315f,  8.292529f,  9.292529f,  8.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  3.000000f, 
+     2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  4.146264f,  3.828427f, 
+     6.146264f,  5.828427f,  6.146265f,  6.464102f,  6.878315f,  7.878315f,  8.878315f,  9.878315f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  5.414214f,  3.732051f,  3.414214f, 
+     5.146264f,  4.828427f,  5.146265f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  9.464102f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.242640f,  6.656854f,  7.071068f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  4.414214f,  3.414214f,  3.000000f, 
+     4.146264f,  3.828427f,  4.146265f,  5.146265f,  6.146265f,  7.146265f,  8.146264f,  9.146264f,  3.414214f,  3.000000f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  7.656854f,  8.071068f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  3.732051f,  3.414214f,  3.732051f,  3.414214f, 
+     3.146264f,  2.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  7.146264f,  6.828427f,  4.732051f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.560478f,  5.242640f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.146264f,  6.464102f,  6.146264f,  5.828427f,  4.146264f,  3.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.414214f,  6.828427f,  7.242640f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.974691f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.414214f,  5.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146265f,  4.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.242640f,  5.656854f,  4.878315f,  3.464102f,  3.146264f,  2.828427f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.000000f,  5.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     5.146265f,  4.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  5.146264f,  5.560478f,  5.464102f,  4.464102f,  3.464102f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.414214f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  2.732051f, 
+     9.560477f,  9.146264f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  3.828427f,  3.414214f,  3.000000f,  5.000000f,  5.146264f,  5.464102f,  5.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.000000f,  2.414214f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.464102f,  4.878315f,  5.414214f,  5.000000f,  6.560478f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     8.560477f,  8.146264f,  7.732051f,  7.414214f,  7.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.196152f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.732051f,  5.146264f, 
+     4.732051f,  4.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.464102f, 
+     5.732051f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  7.196152f,  6.196152f,  5.196152f, 
+     4.878315f,  4.560478f,  4.242640f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.878315f,  4.464102f,  4.146264f,  6.878315f,  5.878315f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  5.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.732051f,  3.414214f,  3.146264f,  2.732051f,  2.414214f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.732051f,  4.414214f,  4.732051f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.732051f,  4.414214f,  2.828427f,  2.414214f,  2.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.732051f,  5.414214f,  5.732051f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  3.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  6.146264f,  6.560478f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.414214f,  3.146264f,  2.732051f,  2.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.414214f,  6.732051f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.732051f,  3.414214f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.414214f,  3.464102f,  3.146264f,  2.828427f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  7.414214f,  7.732051f, 
+    10.292528f,  9.974690f,  1.732051f,  1.414214f,  1.732051f,  4.146264f,  3.828427f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 
+     4.000000f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  5.560478f, 
+     9.292528f,  8.974691f,  8.656854f,  2.414214f,  2.732051f,  4.560478f,  4.242640f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.560478f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.828427f,  5.146264f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     4.828427f,  5.242640f,  4.464102f,  4.146264f,  3.828427f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.414214f,  4.732051f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.974691f,  7.292529f,  7.610366f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.000000f,  3.414214f, 
+     3.828427f,  4.242640f,  3.464102f,  3.146264f,  2.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.878315f,  1.414214f, 
+     6.292529f,  5.974691f,  5.656854f,  5.974691f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  8.878315f,  8.560477f,  8.242640f,  8.560477f,  8.878315f,  5.242640f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  3.146264f,  2.732051f,  2.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  5.146264f,  5.464102f,  1.000000f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  2.414214f,  2.000000f,  8.610366f,  8.196152f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  2.828427f,  2.414214f,  2.000000f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  4.414214f,  4.732051f,  5.146264f,  1.414214f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  2.732051f,  8.024579f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     2.000000f,  3.000000f,  4.000000f,  2.732051f,  2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  4.000000f,  4.414214f,  4.828427f,  5.242640f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.146264f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  4.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  3.146264f,  2.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  7.560478f,  7.878315f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.146264f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  4.828427f,  5.828427f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196153f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.000000f,  3.414214f, 
+     3.828427f,  5.560478f,  5.146264f,  4.732051f,  4.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.242640f,  2.414214f,  2.000000f,  2.414214f, 
+     7.928203f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     4.828427f,  4.560478f,  4.146264f,  3.732051f,  5.828427f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  6.146264f,  5.732051f,  5.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  3.828427f,  4.146264f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.414214f,  2.000000f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  4.828427f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  1.732051f,  1.414214f,  3.414214f,  3.000000f,  3.414214f, 
+     8.024579f,  7.706742f,  7.388905f,  7.071068f,  7.388905f,  7.706742f,  1.414214f,  1.000000f,  5.560478f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.146265f,  5.146265f,  4.146265f,  5.242640f,  4.242640f,  3.828427f,  2.732051f, 
+     3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  1.414214f,  1.000000f,  1.414214f,  4.000000f,  4.414214f, 
+    10.732051f, 10.414213f, 10.732051f, 11.146264f,  9.732051f,  8.732051f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  9.706741f, 10.706741f, 11.706741f, 12.706741f, 
+     9.732051f,  9.414213f,  9.732051f, 10.146264f, 10.560477f, 10.974690f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.146264f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  9.388905f, 10.388905f, 11.388904f, 12.388904f, 
+     8.732051f,  8.414213f,  8.732051f,  9.146264f,  9.560477f,  9.974691f, 10.388905f,  7.292529f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  6.242640f,  6.656854f,  7.071068f,  8.071068f,  9.071068f, 10.071067f, 11.071067f, 12.071067f, 
+     7.732051f,  7.414214f,  7.732051f,  8.146264f,  8.560478f,  8.974691f,  9.388906f,  8.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.388905f,  8.388905f,  9.388905f, 10.388905f,  7.071068f,  5.242640f, 
+     6.732051f,  6.414214f,  6.732051f,  7.146265f,  7.560478f,  7.974692f,  8.974691f,  9.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  5.146264f,  4.828427f, 
+     5.732051f,  5.414214f,  5.732051f,  6.146265f,  6.560478f,  7.560478f,  8.560478f,  9.560477f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  5.000000f,  4.732051f,  4.414214f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146265f,  6.146265f,  7.146265f,  8.146264f,  5.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146265f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  4.000000f,  4.414214f,  4.000000f, 
+     3.732051f,  3.414214f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  4.146264f,  3.732051f,  3.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.560478f,  7.974691f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.828427f,  4.878315f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.414214f,  3.000000f,  3.414214f,  4.414214f, 
+     2.732051f,  2.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.000000f,  4.000000f,  3.000000f, 
+     2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  6.146264f,  4.560478f,  4.146264f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     1.732051f,  1.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.414214f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.146264f,  4.828427f,  4.464102f,  4.146264f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.464102f,  7.146264f,  6.560478f,  5.464102f,  4.464102f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.560478f,  5.560478f,  5.242640f,  6.560478f,  6.974691f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.878315f,  6.878315f,  6.146264f,  5.732051f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.146264f,  4.828427f,  5.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     2.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.560478f,  5.560478f,  5.560478f,  5.146264f,  4.732051f,  4.242640f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  4.414214f,  4.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  4.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     3.732051f,  3.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.828427f,  4.242640f,  5.242640f,  4.560478f,  4.146264f,  3.732051f,  3.828427f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.000000f,  4.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+     4.732051f,  4.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.146264f,  4.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.464102f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  4.732051f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  3.146264f, 
+     5.732051f,  5.414214f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  4.146264f,  3.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.464102f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.464102f,  3.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.828427f,  5.414214f,  6.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.732051f,  6.414214f,  7.414214f,  7.000000f,  7.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.196152f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     5.146264f,  4.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.464102f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     7.732051f,  7.414214f,  6.414214f,  6.000000f,  6.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.196152f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     5.464102f,  5.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     8.732051f,  8.414213f,  5.414214f,  5.000000f,  5.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  6.878315f,  5.878315f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     9.732051f,  9.414213f,  4.414214f,  4.000000f,  4.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  6.464102f,  5.464102f,  4.464102f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.146264f,  3.828427f,  4.146264f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  4.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.146264f,  4.828427f,  5.146264f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.878315f,  6.292529f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.828427f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.828427f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.828427f,  6.146264f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.828427f,  7.146264f, 
+     3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  6.146264f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.464102f,  4.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  8.146264f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.878315f,  4.560478f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  9.146264f, 
+     9.706741f,  9.388905f,  9.071068f,  2.000000f,  2.414214f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.732051f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.732051f,  5.828427f,  5.414214f,  5.000000f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  3.000000f, 
+     8.706742f,  8.388905f,  8.071068f,  8.388905f,  4.560478f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.828427f,  4.414214f,  4.000000f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  2.000000f, 
+     7.706742f,  7.388905f,  7.071068f,  7.388905f,  4.146264f,  3.828427f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.878315f,  1.000000f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  3.732051f,  3.414214f,  9.292528f,  8.878315f,  8.464102f,  8.146264f,  7.828427f,  8.146264f,  8.464102f,  5.560478f,  5.146264f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  4.464102f,  0.000000f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  3.414214f,  8.706742f,  8.292528f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  3.732051f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  5.828427f,  6.146264f,  6.464102f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  4.146264f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  4.560478f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.146264f,  2.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.828427f,  2.414214f,  2.000000f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     6.146264f,  7.878315f,  6.878315f,  5.878315f,  5.560478f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     4.146264f,  4.560478f,  5.560478f,  4.732051f,  4.414214f,  4.732051f,  3.828427f,  3.414214f,  3.000000f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  2.414214f,  2.732051f, 
+     8.342417f,  7.928203f,  7.610366f,  7.292529f,  6.974691f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.828427f,  4.878315f,  5.878315f,  5.732051f,  5.414214f,  5.732051f,  4.828427f,  4.414214f,  4.000000f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     8.024579f,  7.610366f,  7.196152f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f, 
+     3.464102f,  4.464102f,  5.464102f,  3.146264f,  2.828427f,  3.146264f,  5.828427f,  5.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f,  2.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  4.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.146264f,  2.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  1.414214f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  1.414214f,  1.000000f,  3.732051f,  3.414214f,  3.732051f, 
+     7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  0.000000f,  1.000000f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.146264f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.146264f,  2.828427f,  3.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.560478f,  5.878315f,  6.196152f,  1.000000f,  0.000000f,  1.000000f,  4.414214f,  4.732051f, 
+    10.414213f, 10.000000f, 10.414213f, 10.828426f, 11.242640f, 11.656854f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  9.120955f, 10.120955f, 11.120955f, 12.120955f, 13.120955f, 
+     9.414213f,  9.000000f,  9.414213f,  9.828426f, 10.242640f, 10.656854f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.828427f,  6.146264f,  6.464102f,  4.828427f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  8.803119f,  9.803118f, 10.803118f, 11.803118f, 12.803117f, 
+     8.414213f,  8.000000f,  8.414213f,  8.828427f,  9.242640f,  9.656854f, 10.071068f,  7.610366f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.464102f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.414214f,  5.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  7.656854f,  8.071068f,  8.485281f,  9.485281f, 10.485281f, 11.485280f,  7.974691f, 
+     7.414214f,  7.000000f,  7.414214f,  7.828427f,  8.242640f,  8.656855f,  9.071068f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.414214f,  5.828427f,  6.146265f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  9.803118f,  6.974691f,  6.656854f,  6.974691f, 
+     6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242641f,  7.656855f,  8.656855f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.732051f,  7.878315f,  7.464102f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.974691f,  5.656854f,  5.974691f, 
+     5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242641f,  7.242641f,  8.242640f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.828427f,  7.146264f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  5.560478f,  5.242640f,  5.560478f, 
+     4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  4.464102f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.146265f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.146264f,  4.828427f,  5.146264f, 
+     3.414214f,  3.000000f,  3.414214f,  4.414214f,  3.414214f,  3.732051f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  7.464102f,  7.878315f,  8.292528f,  4.732051f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.828427f,  4.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  3.414214f,  4.414214f,  4.732051f, 
+     2.414214f,  2.000000f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  8.878315f,  5.414214f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.732051f,  4.146264f,  3.146264f,  2.732051f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  2.732051f,  2.414214f,  2.732051f,  4.414214f, 
+     1.414214f,  1.000000f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.878315f,  6.292529f,  4.878315f,  8.414213f,  8.732051f,  5.732051f,  4.732051f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.146264f,  4.732051f,  4.414214f,  3.464102f,  3.146264f,  2.828427f,  5.464102f,  5.878315f,  6.292529f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     1.000000f,  0.000000f,  1.000000f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  6.828427f,  8.414213f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.878315f,  4.560478f,  4.242640f,  6.878315f,  7.292529f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  5.828427f,  5.414214f,  5.000000f,  4.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  4.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     2.414214f,  2.000000f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  3.828427f, 
+     3.414214f,  4.732051f,  4.414214f,  4.732051f,  5.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     3.414214f,  3.000000f,  3.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  5.414214f,  5.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     4.414214f,  4.000000f,  5.146265f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.146264f,  4.732051f,  4.414214f,  3.828427f,  4.146264f, 
+     5.414214f,  5.000000f,  6.146265f,  5.732051f,  5.414214f,  5.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  5.828427f,  6.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     6.414214f,  6.000000f,  6.414214f,  7.414214f,  6.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  4.146264f,  4.464102f,  4.878315f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     3.000000f,  5.732051f,  5.414214f,  5.878315f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     7.414214f,  7.000000f,  7.414214f,  6.414214f,  6.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  6.974691f,  5.974691f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  3.414214f,  3.000000f,  3.414214f,  4.414214f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     8.414213f,  8.000000f,  8.414213f,  5.414214f,  5.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.828427f,  3.828427f,  2.828427f,  7.560478f,  6.560478f,  5.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.414214f,  3.732051f,  4.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     9.414213f,  9.000000f,  9.414213f,  4.414214f,  4.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.242640f,  4.242640f,  3.828427f,  7.146264f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.560478f,  4.242640f,  4.560478f, 
+    10.414213f, 10.000000f, 10.414213f,  3.414214f,  3.732051f,  4.464102f,  4.878315f,  4.560478f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.196153f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.732051f,  4.732051f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.560478f,  5.242640f,  5.560478f, 
+    11.414213f, 11.000000f, 11.414213f,  2.414214f,  2.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.242640f,  6.560478f, 
+    12.414213f, 12.000000f, 12.414213f,  1.414214f,  1.732051f,  5.878315f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  7.242640f,  7.560478f, 
+    13.414213f, 13.000000f, 13.414213f,  1.000000f,  1.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  8.560477f, 
+    14.414213f, 14.000000f, 14.414213f,  1.414214f,  1.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.878315f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  9.560477f, 
+    10.120955f,  9.803118f,  9.485281f,  2.414214f,  2.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.414214f,  6.146264f,  5.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  3.414214f, 
+     9.120955f,  8.803119f,  8.485281f,  8.803119f,  3.732051f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     5.464102f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  5.146264f,  4.732051f,  4.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.464102f,  2.414214f, 
+     8.706742f,  8.388905f,  8.071068f,  8.388905f,  5.146264f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.828427f,  4.146264f, 
+     4.464102f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.146264f,  3.732051f,  3.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  4.464102f,  1.414214f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f,  4.732051f,  9.388905f,  8.974691f,  8.560477f,  8.146264f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  5.878315f,  5.464102f,  5.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  4.414214f,  8.388905f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.732051f,  4.414214f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  4.732051f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  4.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.414214f,  5.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  5.146264f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  3.732051f,  3.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     8.878315f,  7.878315f,  6.878315f,  5.878315f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.146264f,  2.732051f,  2.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     4.560478f,  4.146264f,  3.732051f,  6.292529f,  5.974691f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.732051f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.146264f,  3.732051f,  3.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.414214f,  5.196152f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.146264f,  4.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  2.414214f,  2.732051f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     4.464102f,  4.878315f,  5.878315f,  6.414214f,  6.000000f,  6.414214f,  6.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  5.560478f,  3.732051f,  3.414214f,  3.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     3.828427f,  4.242640f,  5.242640f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  1.414214f,  4.146264f,  3.828427f,  4.146264f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  1.000000f,  1.414214f,  2.414214f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.828427f,  4.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.146264f,  5.464102f,  5.878315f,  1.414214f,  1.000000f,  1.414214f,  4.828427f,  5.146264f, 
+    10.732051f, 10.414213f, 10.732051f, 11.146264f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f, 
+     5.878315f,  5.560478f,  5.242640f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  9.292528f,  9.706741f, 10.120955f, 10.535169f, 11.535169f, 12.535168f, 13.535168f, 
+     9.732051f,  9.414213f,  9.732051f, 10.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.196152f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.560478f,  5.878315f,  8.974691f,  9.388905f,  9.803118f, 10.217332f, 11.217331f, 12.217331f, 13.217331f, 
+     8.732051f,  8.414213f,  8.732051f,  9.146264f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.732051f,  5.414214f,  4.878315f,  5.196152f,  6.196152f,  9.485281f,  9.899494f, 10.899494f,  7.242640f,  7.560478f, 
+     7.732051f,  7.414214f,  7.732051f,  8.146264f,  8.560478f,  5.560478f,  5.146264f,  4.732051f,  6.610366f,  6.196152f,  5.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.414214f,  7.196153f,  6.878315f,  6.560478f,  4.732051f,  4.414214f,  4.732051f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  6.560478f,  6.242640f,  6.560478f, 
+     6.732051f,  6.414214f,  6.732051f,  7.146265f,  7.560478f,  7.974692f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  4.242640f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.732051f,  6.878315f,  6.464102f,  6.146264f,  3.732051f,  3.414214f,  3.732051f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  5.560478f,  5.242640f,  5.560478f, 
+     5.732051f,  5.414214f,  5.732051f,  6.146265f,  6.560478f,  7.560478f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.828427f,  6.146264f,  5.732051f,  2.732051f,  2.414214f,  2.732051f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  4.560478f,  4.242640f,  4.560478f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146265f,  6.146265f,  7.146265f,  6.196153f,  5.878315f,  5.560478f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.732051f,  4.732051f,  5.828427f,  5.414214f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.560478f,  6.560478f,  7.560478f,  4.146264f,  3.828427f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  7.878315f,  8.196152f,  8.610366f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.414214f,  3.414214f,  4.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.878315f,  7.878315f,  3.732051f,  3.414214f,  3.732051f, 
+     2.732051f,  2.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.828427f,  5.146264f,  8.146264f,  7.828427f,  8.146264f,  8.464102f,  4.828427f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.828427f,  5.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  6.146264f,  6.464102f,  7.196153f,  3.146264f,  3.414214f,  3.000000f,  3.414214f, 
+     1.732051f,  1.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.974691f,  4.828427f,  4.414214f,  4.000000f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.146264f,  5.464102f,  3.146264f,  2.732051f,  2.414214f,  3.414214f,  3.732051f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.000000f,  7.414214f,  7.828427f,  5.464102f,  4.464102f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  5.242640f,  5.560478f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  7.610366f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.146264f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  5.146264f,  4.828427f,  5.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.146264f,  2.828427f,  3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.828427f, 
+     5.464102f,  5.146264f,  5.146264f,  4.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     4.732051f,  4.414214f,  4.828427f,  4.414214f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.828427f,  5.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     5.146264f,  4.828427f,  5.146264f,  4.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.828427f,  4.828427f,  5.146264f, 
+     5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.974691f,  6.292529f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     3.732051f,  5.242640f,  5.560478f,  5.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  2.828427f,  6.242640f,  6.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     6.732051f,  6.414214f,  6.732051f,  7.828427f,  5.560478f,  4.878315f,  4.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  7.071068f,  6.656854f,  6.242640f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     7.732051f,  7.414214f,  7.732051f,  6.828427f,  5.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.732051f,  5.146264f,  5.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  6.656854f,  5.656854f,  5.242640f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     8.732051f,  8.414213f,  8.732051f,  5.828427f,  4.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  6.146264f,  6.560478f,  5.146264f,  4.146264f,  3.146264f,  7.242640f,  6.242640f,  5.242640f,  4.242640f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.414214f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.146264f,  4.828427f,  5.146264f, 
+     9.732051f,  9.414213f,  9.732051f,  4.828427f,  5.146264f,  5.878315f,  5.464102f,  5.146264f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.292529f,  5.560478f,  4.560478f,  4.146264f,  6.828427f,  5.828427f,  4.828427f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.242640f,  5.560478f, 
+    10.732051f, 10.414213f, 10.732051f,  3.828427f,  4.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.414214f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.656854f,  5.974691f, 
+    11.732051f, 11.414213f, 11.732051f,  2.828427f,  3.146264f,  5.878315f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  5.000000f,  4.000000f,  3.000000f, 
+     2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.656854f,  6.974691f, 
+    12.732051f, 12.414213f, 12.732051f,  2.414214f,  2.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.974691f, 
+    13.732051f, 13.414213f, 13.732051f,  2.000000f,  2.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  8.196152f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  7.878315f, 
+    14.732051f, 14.414213f, 14.732051f,  2.414214f,  2.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f, 
+    15.732051f, 15.414213f, 15.732051f,  2.828427f,  3.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     5.560478f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.732051f,  6.464102f,  6.146264f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  6.560478f, 
+    16.732052f, 16.414213f, 16.732052f,  3.828427f,  4.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     5.878315f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.464102f,  5.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.146264f,  5.560478f, 
+     9.706741f,  9.388905f,  9.071068f,  4.828427f,  5.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.242640f,  4.560478f, 
+     4.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.464102f,  4.146264f,  3.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     8.242641f,  7.242641f,  6.242641f,  5.828427f,  5.732051f,  6.878315f,  6.464102f,  6.146264f,  7.828427f,  7.414214f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  3.828427f,  4.146264f, 
+     4.464102f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.828427f,  3.414214f,  3.000000f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     8.656855f,  7.656855f,  7.242641f,  6.828427f,  5.414214f,  8.071068f,  7.656854f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  5.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.414214f,  4.000000f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     9.071068f,  8.656855f,  8.242640f,  7.828427f,  5.732051f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  4.414214f,  4.000000f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     3.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.414214f,  5.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.878315f,  4.464102f,  4.146264f,  7.732051f,  6.146264f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  3.414214f,  3.000000f,  3.414214f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.000000f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.146264f, 
+     4.464102f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.464102f,  3.146264f,  2.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.414214f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.464102f,  4.146264f,  3.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f, 
+     5.000000f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  5.464102f,  5.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  3.732051f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.464102f,  5.878315f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.414214f,  3.000000f,  3.414214f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.732051f, 
+     5.146264f,  5.560478f,  5.974691f,  7.732051f,  7.414214f,  7.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  3.732051f,  3.414214f,  3.732051f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.414214f,  4.000000f,  4.414214f, 
+     4.828427f,  5.242640f,  5.656854f,  6.656854f,  4.000000f,  8.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.146264f,  3.828427f,  4.146264f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  3.146264f,  3.000000f,  3.414214f,  3.828427f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.732051f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.560478f,  4.242640f,  4.560478f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  2.414214f,  2.828427f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  6.242640f,  7.242640f,  4.000000f,  3.000000f,  2.000000f,  1.000000f, 
+     0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.146264f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.146264f,  5.560478f,  2.414214f,  2.000000f,  2.414214f,  4.414214f,  4.000000f, 
+    11.146264f, 10.828426f, 11.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f, 
+     6.292529f,  5.974691f,  5.656854f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.610366f,  8.928203f, 11.120955f, 11.535169f, 11.949382f, 12.949382f, 13.949381f, 
+    10.146264f,  9.828426f, 10.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  6.196152f, 
+     5.878315f,  5.560478f,  5.242640f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  6.610366f,  6.928203f, 10.803118f, 11.217331f, 11.631545f, 12.631544f, 13.631544f, 
+     9.146264f,  8.828427f,  9.146264f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.878315f, 
+     5.464102f,  5.146264f,  4.828427f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.292529f,  6.196152f,  6.610366f,  7.610366f,  7.464102f,  7.146264f,  6.828427f,  7.146264f, 
+     8.146264f,  7.828427f,  8.146264f,  8.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.242640f,  3.828427f,  3.414214f,  6.196153f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.878315f,  6.292529f,  7.292529f,  6.464102f,  6.146264f,  5.828427f,  6.146264f, 
+     7.146264f,  6.828427f,  7.146265f,  7.464102f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  5.242640f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.146264f,  3.732051f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.560478f,  5.974691f,  6.974691f,  5.464102f,  5.146264f,  4.828427f,  5.146264f, 
+     6.146264f,  5.828427f,  6.146265f,  6.464102f,  6.878315f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.464102f,  4.146264f,  3.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.242640f,  5.656854f,  6.656854f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     5.146264f,  4.828427f,  5.146265f,  5.464102f,  6.464102f,  6.196152f,  5.878315f,  5.560478f,  5.974691f,  5.656854f,  5.828427f,  6.196152f,  5.000000f,  8.292528f,  7.974691f,  7.656854f,  7.610366f,  7.928203f,  8.342417f,  5.878315f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.414214f,  4.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     4.146264f,  3.828427f,  4.146265f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.878315f,  5.560478f,  5.242640f,  6.414214f,  6.828427f,  8.196152f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  2.828427f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.464102f,  5.146264f,  4.828427f,  5.414214f,  5.828427f,  6.242640f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  4.242640f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  6.560478f,  6.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.732051f,  6.146265f,  6.560478f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.732051f,  2.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.242640f,  5.560478f,  5.878315f,  4.732051f,  3.828427f,  2.828427f,  2.414214f,  4.732051f,  4.414214f,  4.732051f,  5.146265f,  5.560478f,  3.732051f,  2.732051f,  2.414214f,  2.732051f, 
+     2.414214f,  2.000000f,  2.414214f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.560478f,  4.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  5.146265f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146265f,  4.560478f,  3.414214f,  3.146264f,  2.828427f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  5.196152f, 
+     4.878315f,  4.560478f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.828427f,  4.146264f, 
+     3.146264f,  2.828427f,  3.146264f,  4.146264f,  3.828427f,  4.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f, 
+     5.878315f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.828427f,  4.146264f,  5.146264f, 
+     4.146264f,  3.828427f,  4.146264f,  4.560478f,  4.242640f,  7.878315f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.560478f,  4.242640f,  4.560478f,  4.878315f, 
+     5.146264f,  4.828427f,  5.146264f,  5.560478f,  6.560478f,  6.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     4.464102f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.560478f,  5.242640f,  5.828427f,  6.146264f, 
+     6.146264f,  5.828427f,  6.146264f,  6.560478f,  5.560478f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146264f,  6.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  6.146264f,  5.732051f,  5.414214f,  5.732051f, 
+     7.146264f,  6.828427f,  7.146264f,  7.560478f,  4.560478f,  5.878315f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  3.828427f,  2.828427f,  2.414214f,  7.388905f,  6.974691f,  6.560478f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  5.828427f,  5.414214f,  5.000000f,  5.414214f, 
+     8.146264f,  7.828427f,  8.146264f,  7.242640f,  4.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  4.146264f,  3.146264f,  2.732051f,  6.974691f,  5.974691f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196153f,  5.732051f,  5.414214f,  5.732051f, 
+     9.146264f,  8.828427f,  9.146264f,  6.242640f,  3.732051f,  6.560478f,  6.146264f,  4.414214f,  4.000000f,  4.414214f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  4.464102f,  3.464102f,  7.560478f,  6.560478f,  5.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.732051f,  6.464102f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.146264f,  5.828427f,  6.146264f, 
+    10.146264f,  9.828426f, 10.146264f,  5.242640f,  3.414214f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.878315f,  4.464102f,  7.146264f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.146264f,  5.732051f,  5.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.242640f,  6.560478f, 
+    11.146264f, 10.828426f, 11.146264f,  4.242640f,  3.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.292529f,  5.974691f,  6.732051f,  5.732051f,  4.732051f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.828427f,  5.414214f,  5.000000f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  5.414214f,  5.828427f, 
+    12.146264f, 11.828426f, 12.146264f,  3.828427f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.878315f,  5.560478f,  5.242640f,  5.414214f,  4.414214f,  3.414214f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.146264f,  5.732051f,  5.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.732051f,  6.146264f, 
+    13.146264f, 12.828426f, 13.146264f,  3.414214f,  4.560478f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  4.732051f,  3.732051f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.464102f,  4.560478f,  4.146264f,  3.732051f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.560478f,  5.828427f,  6.146264f,  6.464102f, 
+    14.146264f, 13.828426f, 14.146264f,  3.000000f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.560478f,  6.878315f, 
+    15.146264f, 14.828426f, 15.146264f,  3.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.292529f, 
+    16.146263f, 15.828426f, 16.146263f,  3.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     5.974691f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.146264f,  5.464102f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.828427f,  6.242640f, 
+    17.146263f, 16.828426f, 17.146263f,  4.242640f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.414214f,  4.828427f,  5.242640f, 
+     7.560478f,  6.560478f,  5.560478f,  5.242640f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.242640f,  6.464102f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.560478f,  4.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     7.974691f,  6.974691f,  6.560478f,  6.242640f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  6.292529f,  5.974691f,  5.464102f,  5.146265f,  4.828427f,  4.146264f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  4.146264f,  4.146264f,  3.732051f,  3.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     6.560478f,  7.974691f,  7.560478f,  7.242640f,  7.974691f,  8.388905f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  5.732051f,  5.414214f,  5.146264f,  4.732051f,  4.414214f,  3.146264f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.732051f,  3.414214f,  3.732051f,  5.146264f,  4.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  4.732051f,  4.414214f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.732051f,  5.414214f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.414214f,  2.414214f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.000000f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.732051f, 
+     2.414214f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146265f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     2.828427f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     3.828427f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  4.732051f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  6.414214f,  6.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.732051f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  4.414214f,  4.000000f,  4.414214f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  1.732051f,  1.414214f,  1.732051f,  6.828427f,  7.146264f,  7.464102f,  2.414214f,  2.732051f,  3.146264f,  6.464102f,  5.732051f, 
+     6.146264f,  6.560478f,  8.464102f,  8.146264f,  7.828427f,  8.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.732051f,  4.414214f,  4.732051f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.732051f,  2.414214f,  2.732051f,  7.242640f,  7.560478f,  7.878315f,  3.414214f,  3.732051f,  4.146264f,  5.000000f,  5.414214f, 
+     5.828427f,  6.242640f,  6.656854f,  5.828427f,  5.414214f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.146264f,  4.828427f,  5.146264f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  1.732051f,  2.732051f,  8.292528f,  7.974691f,  7.656854f,  7.974691f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.732051f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.146264f,  3.732051f,  3.414214f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  8.388905f,  8.071068f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.828427f,  5.242640f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  3.000000f,  3.828427f,  3.414214f,  3.000000f, 
+    11.560477f,  8.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f, 
+     7.292529f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  8.196152f,  8.610366f,  9.024579f,  5.974691f,  5.656854f,  5.974691f, 14.363595f, 
+    10.560477f,  8.974691f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  7.196152f, 
+     6.878315f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  5.560478f,  5.242640f,  7.414214f,  7.732051f, 
+     9.560477f,  9.242640f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  6.878315f, 
+     6.464102f,  6.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  5.146264f,  6.732051f,  6.414214f,  6.732051f, 
+     8.560477f,  8.242640f,  7.828427f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  6.560478f, 
+     6.146264f,  6.414214f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  5.878315f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  6.146264f,  5.732051f,  5.414214f,  5.732051f, 
+     7.560478f,  7.242640f,  7.560478f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  6.242640f, 
+     5.828427f,  5.414214f,  5.000000f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     6.560478f,  6.242640f,  6.560478f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.388905f,  7.071068f,  7.610366f,  7.928203f,  8.342417f,  6.560478f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     5.560478f,  5.242640f,  6.292529f,  5.974691f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  6.292529f,  5.878315f, 
+     5.464102f,  5.146265f,  4.828427f,  5.146265f,  5.464102f,  4.464102f,  4.146264f,  3.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     4.560478f,  4.242640f,  5.878315f,  5.560478f,  9.706741f,  9.388905f,  9.071068f,  9.388905f,  9.706741f,  6.414214f,  6.732051f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  6.828427f,  7.146264f,  7.464102f,  4.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     4.146264f,  3.828427f,  5.464102f,  5.146264f,  8.706742f,  8.388905f,  8.071068f,  8.388905f,  8.706742f,  5.414214f,  5.732051f,  6.146264f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f, 
+     4.828427f,  4.414214f,  4.000000f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     3.732051f,  3.414214f,  5.146264f,  4.732051f,  7.706742f,  7.388905f,  7.071068f,  7.388905f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f, 
+     5.146264f,  4.732051f,  4.414214f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.146264f,  4.146264f,  3.146264f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     3.414214f,  3.000000f,  3.414214f,  4.414214f,  4.000000f,  6.974691f,  6.656854f,  6.974691f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f, 
+     5.464102f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.732051f,  3.414214f,  3.732051f,  4.732051f,  4.414214f,  6.560478f,  6.242640f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.732051f,  4.414214f,  3.414214f,  3.732051f, 
+     4.146264f,  3.828427f,  4.146264f,  5.146264f,  8.146264f,  8.464102f,  5.828427f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.828427f,  4.414214f,  4.732051f, 
+     4.560478f,  4.242640f,  4.560478f,  5.560478f,  7.146264f,  7.464102f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.242640f,  5.414214f,  5.732051f, 
+     5.560478f,  5.242640f,  5.560478f,  5.974691f,  6.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.656854f,  6.828427f,  7.146264f, 
+     6.560478f,  6.242640f,  6.560478f,  6.974691f,  5.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     4.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.974691f,  7.292529f,  7.610366f,  7.388905f,  7.706742f,  7.146264f,  6.732051f,  6.414214f,  6.732051f, 
+     7.560478f,  7.242640f,  7.560478f,  7.974691f,  4.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.242640f,  3.828427f,  3.414214f,  7.706742f,  7.292529f,  6.878315f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  3.828427f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.292529f,  6.828427f,  6.414214f,  6.000000f,  6.414214f, 
+     8.560477f,  8.242640f,  8.560477f,  2.828427f,  3.146264f,  5.974691f,  6.146264f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.560478f,  4.146264f,  3.732051f,  7.292529f,  6.292529f,  5.878315f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.464102f,  5.146264f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  6.878315f,  7.196153f,  5.242640f,  5.560478f,  5.878315f, 
+     9.560477f,  9.242640f,  9.560477f,  2.414214f,  2.732051f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  4.878315f,  4.464102f,  4.146265f,  6.878315f,  5.878315f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  6.464102f,  6.878315f,  4.828427f,  5.146264f,  5.464102f, 
+    10.560477f, 10.242640f, 10.560477f,  2.000000f,  2.414214f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  5.196152f,  4.878315f,  5.146265f,  6.464102f,  5.464102f,  4.464102f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+    11.560477f, 11.242640f, 11.560477f,  2.414214f,  2.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  6.974691f,  7.146264f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f, 
+    12.560477f, 12.242640f, 12.560477f,  2.828427f,  3.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  6.560478f,  6.242640f,  5.828427f,  4.828427f,  3.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+    13.560477f, 13.242640f, 13.560477f,  3.828427f,  4.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  6.146264f,  5.828427f,  6.146264f,  5.146264f,  4.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.146264f,  4.464102f,  4.878315f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+    14.560477f, 14.242640f, 14.560477f,  4.828427f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  4.464102f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  3.146264f,  3.464102f,  4.464102f,  5.560478f,  5.242640f,  5.560478f,  5.878315f, 
+    15.560477f, 15.242640f, 15.560477f,  5.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.146265f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.974691f,  6.292529f, 
+    16.560476f, 16.242640f, 16.560476f,  4.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f, 
+     6.974691f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.560478f,  5.878315f,  5.828427f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.146264f,  7.292529f, 
+    17.560476f, 17.242640f, 17.560476f,  5.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  5.732051f, 
+     6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.974691f,  5.146265f,  7.974691f,  7.656854f,  7.974691f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     7.974691f,  6.974691f,  5.974691f,  5.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  5.878315f,  6.196152f,  6.242640f,  6.560478f,  5.146264f,  4.732051f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.560478f,  5.242640f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     7.242640f,  6.828427f,  6.974691f,  6.656854f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  5.974691f,  6.292529f,  6.610366f,  6.464102f,  4.560478f,  4.146264f,  3.732051f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.146264f,  4.828427f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     6.242640f,  5.828427f,  5.414214f,  5.000000f,  7.656854f,  8.706742f,  8.292528f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  6.974691f,  7.292529f,  5.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.732051f,  4.414214f,  4.732051f,  5.464102f,  5.146264f,  4.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  5.146264f,  4.828427f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  6.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.146264f,  3.828427f,  4.146264f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.732051f,  4.414214f,  4.732051f,  4.732051f,  4.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.146264f,  3.146264f,  2.828427f,  3.146264f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.146264f,  4.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  5.414214f,  5.732051f,  2.732051f,  2.414214f,  2.732051f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  3.146264f,  2.732051f,  2.414214f,  5.414214f,  5.000000f,  5.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  2.828427f,  2.414214f,  2.000000f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  2.414214f,  2.732051f,  5.560478f,  5.878315f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146265f,  7.560478f,  7.242640f,  7.560478f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.732051f,  6.146264f,  5.414214f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  2.828427f,  3.146264f,  5.146264f,  5.464102f,  5.732051f, 
+     5.414214f,  5.732051f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.464102f,  4.146264f,  3.828427f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.196153f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     6.414214f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.464102f,  3.146264f,  2.828427f, 
+     5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  1.414214f,  2.414214f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  5.146264f,  4.732051f,  4.414214f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  7.388905f,  7.071068f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.146264f,  4.828427f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     8.706742f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f,  7.196152f,  6.878315f,  6.560478f, 
+     6.242640f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  5.560478f,  5.242640f,  5.560478f,  5.878315f, 
+     8.292528f,  7.974691f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  6.878315f,  6.464102f,  6.146264f, 
+     5.828427f,  6.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  4.560478f,  4.242640f,  4.560478f,  7.414214f, 
+     7.878315f,  7.560478f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f,  6.560478f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  4.146264f,  3.828427f,  6.000000f,  6.414214f, 
+     7.464102f,  7.146264f,  6.828427f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  6.242640f,  5.828427f,  5.414214f, 
+     5.000000f,  5.414214f,  5.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.828427f,  5.414214f,  5.000000f,  5.414214f, 
+     7.146264f,  6.732051f,  6.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  7.656854f,  6.974691f,  6.560478f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  6.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     6.974691f,  6.656854f,  6.000000f,  6.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.974691f,  6.656854f,  6.974691f,  6.878315f,  9.342417f,  7.560478f, 
+     7.146264f,  6.146264f,  6.464102f,  6.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     5.974691f,  5.656854f,  7.292529f,  6.732051f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f, 
+     6.464102f,  6.146265f,  6.878315f,  7.196152f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     5.560478f,  5.242640f,  6.878315f,  9.610365f,  9.292528f,  8.974691f,  8.656854f,  8.974691f,  9.292528f,  9.610365f,  9.928203f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f, 
+     6.146264f,  5.732051f,  5.414214f,  6.732051f,  6.414214f,  6.732051f,  4.732051f,  4.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     5.146264f,  4.828427f,  6.464102f,  8.610366f,  8.292528f,  7.974691f,  7.656854f,  7.974691f,  8.292528f,  8.610366f,  8.928203f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f, 
+     5.828427f,  5.414214f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.146265f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     4.732051f,  4.414214f,  6.146264f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     6.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.242640f,  5.560478f,  5.146265f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  6.560478f,  1.414214f,  1.000000f,  1.414214f, 
+     4.414214f,  4.000000f,  5.828427f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f, 
+     6.656854f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.242640f,  5.146265f,  4.146265f,  3.732051f,  3.414214f,  5.878315f,  6.878315f,  6.464102f,  6.146264f,  2.414214f,  2.000000f,  2.414214f, 
+     4.732051f,  4.414214f,  4.732051f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  2.828427f,  6.610366f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     6.974691f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     5.146264f,  4.828427f,  5.146264f,  7.414214f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f, 
+     7.292529f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.414214f,  4.000000f,  4.414214f, 
+     5.560478f,  5.242640f,  5.560478f,  6.414214f,  6.732051f,  4.732051f,  4.414214f,  4.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f, 
+     7.610366f,  8.610366f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.000000f,  5.414214f, 
+     5.974691f,  5.656854f,  5.974691f,  5.414214f,  5.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  7.560478f,  7.878315f, 
+     6.974691f,  6.656854f,  6.974691f,  4.414214f,  4.732051f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+     5.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  6.560478f,  6.242640f,  6.560478f,  6.878315f, 
+     7.974691f,  7.656854f,  7.974691f,  3.414214f,  3.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.242640f,  4.828427f,  4.414214f,  8.024579f,  7.610366f,  7.196152f, 
+     6.878315f,  6.560478f,  6.242640f,  3.732051f,  3.414214f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  5.560478f,  5.242640f,  5.560478f,  5.878315f, 
+     8.974691f,  8.656854f,  8.974691f,  2.414214f,  2.732051f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.560478f,  5.146264f,  4.732051f,  7.610366f,  6.610366f,  6.196152f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  5.878315f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  4.560478f,  4.242640f,  4.560478f,  4.878315f, 
+     9.974690f,  9.656854f,  9.974690f,  1.414214f,  1.732051f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  5.878315f,  5.464102f,  5.146265f,  7.196152f,  6.196152f,  5.196152f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+    10.974690f, 10.656854f, 10.974690f,  1.000000f,  1.414214f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  6.196152f,  5.878315f,  5.560478f,  6.878315f,  5.878315f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+    11.974690f, 11.656854f, 11.974690f,  1.414214f,  1.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  7.974691f,  7.560478f,  6.560478f,  5.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+    12.974690f, 12.656853f, 12.974690f,  2.414214f,  2.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  7.560478f,  7.242640f,  6.242640f,  5.242640f,  4.242640f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+    13.974690f, 13.656853f, 13.974690f,  3.414214f,  3.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.146264f,  6.828427f,  6.560478f,  5.560478f,  4.560478f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+    14.974690f, 14.656853f, 14.974690f,  4.414214f,  4.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.146264f,  4.560478f,  6.414214f,  6.732051f,  5.878315f,  4.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  4.146264f,  4.464102f,  7.196153f,  4.560478f,  4.242640f,  4.560478f,  4.878315f, 
+    15.974690f, 15.656853f, 15.974690f,  5.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.414214f,  6.828427f,  5.196152f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.242640f,  5.560478f,  5.878315f, 
+    16.974689f, 16.656853f, 16.974689f,  6.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.146264f,  7.560478f, 
+     6.000000f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.974691f,  6.292529f,  6.828427f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  6.560478f,  6.878315f, 
+     8.560478f,  8.146264f,  7.732051f,  7.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.828427f,  5.414214f, 
+     5.000000f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196153f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.828427f,  5.146264f,  5.464102f,  5.878315f, 
+     8.388905f,  7.388905f,  6.974691f,  6.656854f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  5.242640f,  4.828427f,  4.414214f, 
+     4.000000f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  8.878315f,  8.560477f,  8.242640f,  8.560477f,  3.828427f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.828427f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.414214f,  5.732051f,  5.878315f,  5.560478f,  5.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  5.656854f,  5.974691f,  7.878315f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.000000f,  5.414214f,  5.828427f,  6.560478f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f, 
+     0.000000f,  1.000000f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.414214f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.196152f,  4.878315f,  4.560478f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196153f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  6.656854f,  5.656854f,  4.560478f,  4.878315f,  4.414214f, 
+     4.000000f,  4.414214f,  4.828427f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.146264f,  6.464102f,  4.414214f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.414214f, 
+     5.000000f,  6.878315f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.146264f,  3.732051f,  3.414214f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.732051f,  6.196153f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     6.000000f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  3.146264f,  2.732051f,  2.414214f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.000000f,  5.414214f,  2.732051f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     5.242640f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.974691f,  6.656854f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     3.000000f,  3.414214f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  2.414214f,  2.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     7.706742f,  7.388905f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  6.610366f,  6.196152f,  5.878315f,  5.560478f, 
+     5.242640f,  5.560478f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  9.146264f,  9.464102f,  9.878315f, 10.292528f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+     7.292529f,  6.974691f,  6.656854f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  6.292529f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     6.878315f,  6.560478f,  6.242640f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  7.000000f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  5.656854f,  5.242640f,  4.828427f,  4.414214f, 
+     4.000000f,  4.414214f,  4.828427f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.732051f,  5.732051f,  2.732051f,  5.732051f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.242640f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  5.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.414214f,  2.000000f,  4.414214f,  4.732051f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  6.560478f,  6.242640f,  6.560478f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.878315f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  2.732051f,  3.732051f,  3.414214f,  3.732051f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f, 
+     5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  3.828427f,  3.414214f,  3.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.464102f,  6.146264f,  5.828427f,  9.196152f,  8.878315f,  8.560477f,  8.242640f,  8.560477f,  8.878315f,  9.196152f,  9.610365f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f, 
+     7.196152f,  7.242640f,  6.292529f,  6.610366f,  6.000000f,  6.414214f,  4.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.146264f,  1.732051f,  1.414214f,  1.732051f, 
+     9.438792f,  9.024579f,  8.610366f,  8.196152f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  8.610366f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     6.878315f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.974691f,  1.414214f,  1.000000f,  1.414214f, 
+     9.024579f,  8.024579f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.560478f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.196152f,  5.878315f,  5.560478f,  1.732051f,  1.414214f,  1.732051f, 
+     8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     6.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.560478f,  5.242640f,  4.878315f,  4.464102f,  4.146264f,  5.146264f,  5.560478f,  5.878315f,  5.464102f,  5.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     8.196152f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.560478f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.146264f,  4.828427f,  5.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.146264f,  4.732051f,  3.732051f,  3.414214f,  3.732051f, 
+     7.878315f,  6.878315f,  7.414214f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     6.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.732051f,  4.414214f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.828427f,  4.414214f,  4.732051f,  4.414214f,  4.732051f, 
+     8.146264f,  7.196153f,  6.414214f,  6.000000f,  6.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.414214f,  3.828427f,  4.242640f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f, 
+     7.196152f,  8.196152f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.146264f,  4.732051f,  4.414214f,  5.414214f,  5.732051f, 
+     6.974691f,  6.656854f,  5.414214f,  5.000000f,  5.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f, 
+     5.560478f,  5.974691f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  7.146264f,  7.464102f,  7.878315f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  7.464102f, 
+     7.388905f,  7.071068f,  4.414214f,  4.000000f,  4.414214f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.560478f,  6.242640f,  6.560478f,  5.196152f,  4.878315f,  4.560478f, 
+     4.242640f,  4.560478f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  5.464102f,  5.146264f,  4.828427f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  6.146264f,  5.828427f,  6.146264f,  6.464102f, 
+     8.388905f,  8.071068f,  3.414214f,  3.000000f,  3.414214f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  6.242640f,  5.828427f,  5.414214f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  3.414214f,  3.000000f,  6.196152f,  5.878315f,  5.560478f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+     9.388905f,  9.071068f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  6.560478f,  6.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  5.974691f,  6.292529f,  6.610366f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+    10.388905f, 10.071067f,  1.414214f,  1.000000f,  1.414214f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  6.878315f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+    11.388904f, 11.071067f,  1.000000f,  0.000000f,  1.000000f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  7.196152f,  6.878315f,  6.560478f,  7.292529f,  6.292529f,  5.878315f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+    12.388904f, 12.071067f,  1.414214f,  1.000000f,  1.414214f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.146264f,  5.464102f,  5.878315f,  7.974691f,  6.974691f,  5.974691f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+    13.388904f, 13.071067f,  2.414214f,  2.000000f,  2.414214f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.656854f,  5.656854f,  5.242640f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+    14.388904f, 14.071066f,  3.414214f,  3.000000f,  3.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.974691f,  5.974691f,  5.560478f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+    15.388904f, 15.071066f,  4.414214f,  4.000000f,  4.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.292529f,  5.878315f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     6.828427f,  5.828427f,  5.414214f,  5.000000f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.560478f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  7.560478f,  4.828427f,  5.146264f,  5.464102f, 
+     7.242641f,  6.828427f,  6.414214f,  6.000000f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.242640f,  3.828427f, 
+     3.414214f,  3.000000f,  7.292529f,  6.974691f,  6.292529f,  6.974691f,  6.464102f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  6.828427f,  7.146264f,  7.464102f,  6.146264f,  6.464102f, 
+     8.242640f,  7.828427f,  7.414214f,  7.000000f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.560478f,  5.732051f, 
+     5.414214f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  5.464102f,  6.146264f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  5.146264f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.464102f, 
+     7.610366f,  7.196152f,  8.146264f,  6.560478f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  4.464102f,  4.146264f,  8.464102f,  8.146264f,  7.828427f,  8.146264f,  8.464102f,  5.146264f,  5.464102f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  7.656854f, 
+     7.292529f,  6.878315f,  7.146264f,  6.828427f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  6.560478f,  4.146264f,  5.732051f,  5.414214f,  5.732051f,  3.464102f,  3.146264f,  2.828427f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     6.974691f,  6.560478f,  6.146264f,  5.828427f,  6.146264f,  7.878315f,  7.464102f,  7.146264f,  8.292528f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  5.414214f,  5.000000f,  5.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  6.292529f,  5.974691f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     6.656854f,  6.242640f,  5.146264f,  4.828427f,  5.146264f,  5.414214f,  5.828427f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  5.242640f,  7.146264f,  7.464102f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  5.732051f,  5.414214f,  5.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.146264f,  6.610366f,  6.292529f,  5.974691f,  6.242640f,  6.560478f,  4.242640f,  4.560478f,  4.878315f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  2.732051f,  2.414214f,  2.732051f,  5.560478f,  5.242640f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  7.464102f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196153f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  6.464102f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.656854f,  4.828427f,  5.146264f,  5.464102f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.656854f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  5.464102f,  5.146264f,  4.828427f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.242640f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.732051f, 
+     5.146264f,  5.560478f,  5.974691f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  6.560478f,  4.414214f,  4.000000f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.828427f,  5.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.732051f, 
+     5.464102f,  5.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.828427f,  3.414214f,  3.000000f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.414214f,  4.732051f,  5.146264f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.878315f,  6.196152f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     4.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  4.732051f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.560478f,  6.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  6.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.000000f,  2.000000f,  1.000000f,  0.000000f, 
+     7.292529f,  6.974691f,  6.656854f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  6.196152f,  5.196152f,  4.878315f,  4.560478f, 
+     4.242640f,  4.560478f,  4.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  8.146264f,  7.828427f,  8.146264f,  8.464102f,  8.878315f,  9.292528f,  5.146265f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+     6.292529f,  5.974691f,  5.656854f,  5.974691f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  8.560477f,  8.974691f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.146264f,  6.828427f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.000000f,  5.414214f,  6.146264f,  5.828427f,  6.146264f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.146264f,  2.732051f,  2.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  1.732051f,  1.414214f,  1.732051f,  4.146264f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  6.146264f,  5.732051f,  5.414214f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.878315f,  4.560478f, 
+     4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  4.146264f,  3.732051f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  8.464102f,  8.146264f,  7.828427f,  8.146264f,  8.464102f,  8.878315f,  9.292528f,  6.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  5.146264f,  4.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.560478f,  3.414214f,  2.414214f,  2.732051f, 
+     9.120955f,  5.560478f,  8.292528f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     6.464102f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.878315f,  5.560478f,  2.414214f,  2.000000f,  2.414214f, 
+     8.706742f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  2.414214f,  2.732051f, 
+     8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.242640f,  5.196152f,  4.878315f,  4.414214f,  4.828427f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  2.828427f,  3.146264f, 
+     7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.146264f,  5.828427f,  6.146264f,  4.464102f,  4.146264f,  3.828427f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.828427f,  4.146264f, 
+     7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     6.464102f,  6.146265f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.732051f,  5.414214f,  5.732051f,  4.146264f,  3.732051f,  3.414214f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  4.828427f,  5.146264f, 
+     7.146265f,  6.732051f,  6.732051f,  6.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     6.878315f,  5.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.414214f,  5.000000f,  5.414214f,  3.828427f,  3.414214f,  3.000000f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  6.146264f, 
+     6.828427f,  6.414214f,  5.732051f,  5.414214f,  5.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.414214f,  3.732051f,  4.146264f, 
+     4.560478f,  5.560478f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  4.146264f,  4.560478f,  5.560478f,  6.414214f,  6.732051f,  7.146264f, 
+     8.388905f,  8.071068f,  4.732051f,  4.414214f,  4.732051f,  6.292529f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  5.878315f,  6.464102f,  6.146264f,  4.464102f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  2.732051f,  2.414214f,  2.732051f,  6.464102f,  6.146264f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  5.732051f,  5.414214f,  5.732051f,  6.146264f, 
+     8.803119f,  8.485281f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.464102f,  4.464102f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.146264f,  4.878315f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.414214f,  3.732051f,  6.878315f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+     9.803118f,  9.485281f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  6.292529f,  8.146264f,  8.464102f,  8.878315f,  5.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+    10.803118f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  8.560477f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  7.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+    11.803118f, 11.485280f,  3.414214f,  3.000000f,  3.414214f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  8.878315f,  7.000000f,  6.610366f,  5.732051f,  8.242640f,  8.656854f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.464102f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+    12.803117f, 12.485280f,  3.732051f,  3.414214f,  3.732051f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  4.732051f,  5.146264f,  5.560478f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  5.414214f,  5.732051f,  6.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+    13.803117f, 13.485280f,  4.146264f,  3.828427f,  4.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+    14.803117f, 14.485280f,  4.560478f,  4.242640f,  4.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.878315f,  5.464102f,  6.560478f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  4.878315f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+    15.803117f, 15.485279f,  5.560478f,  5.242640f,  5.560478f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.464102f,  4.464102f,  3.464102f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  4.464102f,  5.656854f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.974691f,  6.656854f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     7.196153f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.242640f,  5.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.242640f,  6.560478f,  4.414214f,  4.732051f,  5.146264f, 
+     8.196153f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.146264f,  4.828427f,  5.146264f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  5.828427f,  6.146264f,  6.464102f,  5.732051f,  6.146264f, 
+     6.928203f,  6.610366f,  6.292529f,  7.414214f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.146265f,  6.146264f, 
+     5.828427f,  6.146264f,  2.732051f,  3.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f, 
+     6.610366f,  6.196152f,  5.878315f,  5.560478f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  3.146264f,  4.828427f,  4.414214f,  4.000000f,  4.146264f,  3.732051f,  8.146264f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  8.974691f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f, 
+     6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  7.196152f,  6.878315f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  5.146264f,  4.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  8.732051f,  8.414213f,  8.732051f,  9.146264f,  9.560477f,  5.732051f,  5.414214f,  4.828427f,  6.146264f,  6.560478f,  6.974691f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  8.388905f,  7.974691f,  7.388905f,  5.464102f,  5.146264f,  6.414214f,  6.732051f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.656854f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  5.146264f,  5.464102f,  5.878315f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.878315f,  6.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  5.560478f,  6.560478f,  4.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.560478f,  5.242640f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.242640f,  5.242640f,  6.242640f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  1.414214f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.242640f,  4.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  5.560478f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  5.146264f,  4.732051f,  4.414214f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  2.732051f,  2.414214f,  2.732051f,  3.828427f,  4.146264f, 
+     4.464102f,  4.878315f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.560478f, 
+     4.878315f,  5.196152f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.146264f,  4.828427f,  5.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.146264f,  5.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.292529f,  5.974691f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.464102f,  5.878315f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.146264f,  2.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.146264f,  3.828427f,  4.146264f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.732051f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.464102f,  3.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.732051f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.464102f,  4.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.464102f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.146264f,  3.000000f,  3.414214f,  3.732051f, 
+     8.803119f,  4.560478f,  4.242640f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  5.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  6.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  5.146264f,  4.828427f,  4.414214f,  3.414214f, 
+     8.388905f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.732051f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.732051f, 
+     7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.414214f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  4.146264f, 
+     7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.828427f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.560478f, 
+     7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  5.146265f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.732051f,  6.414214f,  6.732051f,  5.146264f,  4.732051f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  5.560478f, 
+     6.732051f,  5.732051f,  7.146265f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.000000f,  2.414214f,  5.560478f, 
+     6.560478f,  4.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.414214f,  6.000000f,  6.414214f,  4.828427f,  4.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     6.414214f,  5.414214f,  6.146265f,  5.828427f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  5.146264f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146264f,  5.146264f,  6.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.732051f,  6.414214f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  8.071068f,  8.485281f,  2.828427f,  3.146264f,  3.464102f, 
+     6.732051f,  5.464102f,  5.146265f,  4.828427f,  5.146265f,  5.464102f,  5.878315f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  7.974691f,  6.146264f,  5.732051f,  3.464102f,  3.146264f,  2.828427f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  2.828427f,  3.146264f,  7.464102f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  5.414214f,  5.000000f,  5.414214f,  5.828427f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  5.146265f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  4.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  4.414214f,  4.000000f,  4.414214f,  4.828427f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  5.464102f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  6.464102f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+    12.217331f, 12.485280f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.292529f,  5.974691f,  5.656854f,  7.464102f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+    13.217331f, 12.899493f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.388905f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+    14.217330f, 13.899493f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  6.974691f,  7.292529f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  5.146264f,  5.560478f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+    15.217330f, 14.899493f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.878315f,  5.560478f,  4.560478f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  4.146264f,  4.560478f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.828427f,  4.414214f,  4.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.464102f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.974691f,  5.656854f,  5.974691f,  3.000000f,  3.414214f,  3.828427f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  5.146264f,  4.732051f,  4.414214f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  6.560478f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.242640f,  4.560478f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  4.414214f,  4.828427f, 
+     7.610366f,  7.196152f,  6.878315f,  6.828427f,  7.146264f,  7.464102f,  5.464102f,  5.146264f,  4.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.146264f,  3.828427f,  4.146264f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.828427f, 
+     6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  6.196152f,  5.878315f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  6.610366f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  5.560478f, 
+     2.732051f,  2.414214f,  2.732051f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  7.828427f,  7.414214f,  7.000000f,  7.414214f,  7.828427f,  8.242640f,  8.656854f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  7.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  5.196152f,  4.878315f,  4.560478f, 
+     4.242640f,  4.560478f,  4.878315f,  4.146264f,  3.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  8.414213f,  8.000000f,  8.414213f,  8.828427f,  9.242640f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  7.656854f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  6.610366f,  6.196152f,  5.878315f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.610366f, 
+     6.196152f,  5.878315f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  6.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f, 
+     5.878315f,  5.464102f,  5.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  4.464102f,  5.464102f,  6.464102f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.560478f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.878315f,  4.878315f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  0.000000f, 
+     5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  4.828427f,  5.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.000000f,  4.414214f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.656854f,  6.974691f,  5.414214f,  1.000000f, 
+     5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.414214f,  3.000000f,  3.414214f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  5.464102f,  5.146264f,  2.000000f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.146264f, 
+     3.464102f,  4.464102f,  5.464102f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.414214f,  5.732051f,  6.146264f,  8.656854f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.146264f, 
+     4.464102f,  4.878315f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  5.828427f,  6.146264f,  2.414214f,  2.732051f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f, 
+     6.610366f,  6.292529f,  5.974691f,  5.656854f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.732051f,  4.414214f,  4.732051f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 
+     5.464102f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     7.610366f,  7.292529f,  6.974691f,  6.656854f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  8.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  6.196152f,  5.196152f,  4.878315f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  6.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.878315f,  4.464102f,  4.146264f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.732051f,  3.414214f,  3.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  3.828427f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146264f,  3.732051f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.464102f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.414214f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  7.414214f,  7.000000f,  7.414214f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     4.464102f,  4.146264f,  3.828427f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.828427f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+     5.464102f,  5.146264f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  5.560478f,  5.242640f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.414214f,  6.414214f,  7.146264f,  7.560478f,  7.974691f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  6.146264f, 
+     7.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f, 
+     4.560478f,  5.560478f,  4.878315f,  4.560478f,  4.242640f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146264f,  5.146264f,  6.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.464102f,  6.146264f,  5.828427f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.242640f,  6.242640f,  2.828427f,  2.414214f,  2.000000f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     3.732051f,  4.732051f,  5.732051f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  7.414214f,  7.146264f,  6.828427f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.560478f,  6.560478f,  3.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.878315f, 
+     3.414214f,  4.414214f,  5.414214f,  6.414214f,  3.000000f,  3.414214f,  3.828427f,  7.414214f,  7.000000f,  7.414214f,  7.414214f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.878315f,  6.878315f,  4.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     3.732051f,  4.732051f,  4.828427f,  5.242640f,  3.414214f,  3.732051f,  4.146264f,  7.732051f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     6.878315f,  6.464102f,  4.414214f,  3.414214f,  2.414214f,  6.464102f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.464102f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  5.414214f,  5.732051f,  6.146264f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.828427f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  4.000000f,  3.000000f,  2.000000f,  1.000000f, 
+     0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+    13.217331f, 13.485280f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  7.292529f,  6.974691f,  6.656854f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+    13.631544f, 13.899493f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.878315f,  6.560478f,  6.242640f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.292529f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+    14.631544f, 14.313706f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.464102f,  6.146264f,  5.828427f,  4.560478f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  5.242640f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.828427f,  5.242640f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     4.560478f,  4.146265f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.146264f,  5.732051f,  5.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  4.242640f,  3.828427f, 
+     3.414214f,  4.414214f,  4.828427f,  3.828427f,  4.242640f,  5.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.560478f,  6.242640f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     5.560478f,  5.146265f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.828427f,  5.414214f,  5.000000f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.146264f,  5.464102f,  5.878315f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  3.414214f,  3.732051f,  4.146264f, 
+     8.292528f,  7.878315f,  7.464102f,  7.146264f,  5.732051f,  6.146264f,  6.146264f,  5.732051f,  5.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.732051f,  5.146264f,  5.560478f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.146264f,  3.828427f,  4.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  5.146264f, 
+     7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  7.146264f,  6.464102f,  6.146264f,  5.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.828427f,  4.000000f,  3.000000f,  2.000000f, 
+     1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.146264f,  2.828427f,  3.146264f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.146264f, 
+     6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  8.146264f,  7.732051f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.878315f,  5.560478f, 
+     3.414214f,  3.000000f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  3.146264f,  2.732051f,  2.414214f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  5.878315f,  5.464102f,  5.146264f, 
+     4.828427f,  5.146264f,  4.464102f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  5.974691f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.974691f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f, 
+     4.146264f,  4.560478f,  5.560478f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f, 
+     6.878315f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.974691f,  5.560478f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  1.414214f, 
+     6.560478f,  6.146264f,  5.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  7.464102f,  7.878315f,  7.560478f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     6.242640f,  5.828427f,  5.414214f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.732051f,  3.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     6.560478f,  6.146264f,  5.732051f,  6.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f, 
+     6.878315f,  6.464102f,  6.146264f,  5.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  8.071068f,  5.878315f,  5.560478f,  5.242640f,  4.242640f, 
+     7.196152f,  6.878315f,  6.560478f,  6.242640f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  1.732051f,  1.414214f,  1.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  4.732051f,  4.414214f,  4.146264f,  3.828427f, 
+     7.610366f,  7.292529f,  6.974691f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.000000f,  4.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     5.146264f,  5.560478f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f, 
+     8.024579f,  7.706742f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.000000f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  8.196152f,  5.414214f,  5.146265f,  4.732051f,  3.828427f,  3.414214f,  3.000000f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  6.610366f,  6.196152f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.878315f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.414214f,  4.000000f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.560478f,  5.146264f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.000000f,  3.000000f,  2.000000f,  1.000000f, 
+     0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  4.828427f,  4.414214f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  5.974691f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.146264f,  4.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.560478f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.414214f,  7.732051f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.732051f,  4.146264f,  4.560478f,  4.414214f, 
+     4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.828427f,  5.414214f,  3.828427f,  4.146264f,  4.464102f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.146264f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  5.146264f,  5.464102f, 
+     5.146264f,  4.732051f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  4.878315f,  5.146264f,  4.828427f,  5.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.242640f,  5.656854f,  6.828427f,  7.242640f,  7.656854f,  6.242640f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  6.464102f, 
+     6.146264f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.464102f,  5.464102f,  5.828427f,  6.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.828427f, 
+     4.242640f,  5.242640f,  6.242640f,  7.242640f,  6.974691f,  6.560478f,  6.146264f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.732051f,  1.732051f,  1.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  6.878315f,  6.560478f,  6.242640f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  3.146264f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     3.414214f,  4.414214f,  5.414214f,  6.414214f,  4.414214f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  7.560478f,  7.242640f,  6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     7.242640f,  6.828427f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     3.000000f,  4.000000f,  5.000000f,  6.000000f,  5.242640f,  4.414214f,  4.828427f,  6.974691f,  6.656854f,  8.146264f,  7.828427f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     6.242640f,  5.828427f,  5.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.292529f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     3.414214f,  4.414214f,  5.414214f,  5.560478f,  5.974691f,  6.974691f,  5.146264f,  7.388905f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     5.242640f,  4.828427f,  4.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.464102f,  4.878315f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  5.828427f,  6.146264f,  6.464102f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  3.414214f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  7.878315f,  7.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.878315f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.878315f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  7.464102f,  7.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  5.560478f,  5.146264f, 
+     4.732051f,  3.732051f,  4.146264f,  5.146265f,  4.878315f,  5.196152f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  7.146264f,  6.732051f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146265f,  4.464102f,  4.878315f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.146264f,  5.828427f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     8.974691f,  8.560477f,  8.146264f,  7.732051f,  4.414214f,  4.828427f,  6.828427f,  6.414214f,  6.000000f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.732051f,  4.146264f,  4.560478f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.146264f,  4.464102f, 
+     7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  5.828427f,  7.146264f,  6.732051f,  6.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  3.414214f,  3.828427f,  3.414214f,  3.732051f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.464102f, 
+     6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  6.828427f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  3.828427f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.146264f,  4.560478f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.878315f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  8.146264f,  7.828427f,  8.146264f,  8.464102f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  5.196152f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.828427f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  6.878315f,  6.464102f,  6.146264f, 
+     5.828427f,  6.242640f,  4.146264f,  3.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.878315f,  7.464102f,  7.146264f,  3.828427f,  4.242640f,  5.242640f,  7.878315f,  6.974691f,  6.560478f,  6.146264f,  4.414214f, 
+     4.828427f,  5.242640f,  5.656854f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.560478f,  4.146264f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  7.071068f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     3.828427f,  4.242640f,  5.242640f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  4.828427f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  6.146264f,  5.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.878315f,  7.196152f,  7.610366f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     7.560478f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     7.878315f,  7.464102f,  7.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  4.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  4.146264f,  3.828427f,  4.242640f,  4.560478f, 
+     8.196152f,  7.878315f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.732051f,  2.414214f,  2.732051f,  3.000000f,  3.414214f, 
+     3.828427f,  4.242640f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  3.732051f,  3.414214f,  5.242640f,  5.560478f, 
+     8.610366f,  6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  4.414214f,  4.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.414214f, 
+     4.828427f,  5.242640f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  3.414214f,  3.000000f,  4.732051f,  4.414214f, 
+     9.024579f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  4.414214f,  4.000000f,  3.732051f,  3.414214f,  4.414214f,  4.000000f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  5.828427f,  6.146264f,  6.146264f,  5.732051f,  5.414214f,  7.706742f,  8.706742f,  6.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  7.610366f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  5.242640f,  5.560478f,  5.878315f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.560478f,  4.242640f,  4.560478f,  4.878315f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.560478f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.878315f,  4.560478f,  4.242640f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+     2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.146264f,  3.828427f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.242640f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  3.732051f,  3.414214f,  3.732051f,  3.828427f,  4.146264f,  4.464102f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.146264f,  4.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  4.464102f,  4.878315f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  5.878315f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.560478f,  3.000000f,  3.414214f,  4.242640f,  4.560478f,  4.878315f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  7.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.146264f,  3.464102f,  7.196153f,  6.878315f, 
+     6.560478f,  5.732051f,  6.146264f,  6.560478f,  5.974691f,  5.560478f,  5.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.560478f,  5.878315f, 
+     4.828427f,  4.414214f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.242640f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  2.414214f,  2.732051f,  4.414214f,  6.196153f,  5.878315f, 
+     5.560478f,  5.974691f,  7.146264f,  7.560478f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  6.878315f, 
+     5.828427f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.414214f,  5.732051f,  2.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     4.560478f,  5.560478f,  6.560478f,  4.878315f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.974691f,  5.656854f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  3.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146264f,  5.146264f,  4.146264f,  4.464102f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  6.656854f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     3.732051f,  4.732051f,  5.732051f,  4.146264f,  4.560478f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     7.560478f,  7.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     3.414214f,  4.414214f,  5.414214f,  3.828427f,  4.242640f,  5.242640f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  8.242640f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     6.560478f,  6.146264f,  5.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.878315f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     3.732051f,  4.732051f,  5.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  6.974691f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     5.560478f,  5.146264f,  4.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146264f,  4.146264f,  4.464102f,  4.878315f,  4.878315f,  5.878315f,  6.878315f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f,  6.242640f,  6.560478f,  4.146264f, 
+     4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.414214f,  4.732051f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  3.732051f,  3.414214f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.196153f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  5.242640f,  5.560478f,  5.878315f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  4.560478f,  4.242640f,  4.560478f,  4.878315f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  8.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.464102f,  6.878315f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  5.146264f,  5.464102f,  5.878315f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  3.414214f,  3.000000f,  3.414214f,  3.828427f, 
+    10.656854f, 10.242640f,  9.828426f,  2.414214f,  2.732051f,  3.146264f,  8.464102f,  8.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  5.464102f,  5.878315f,  5.878315f,  5.464102f, 
+     5.146264f,  4.828427f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f, 
+     9.656854f,  9.242640f,  8.828427f,  8.414213f,  3.732051f,  4.146264f,  8.146264f,  7.732051f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.878315f,  4.464102f, 
+     4.146264f,  3.828427f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.732051f,  5.414214f,  5.732051f,  3.828427f,  4.146264f,  4.464102f, 
+     8.656854f,  8.242640f,  7.828427f,  7.414214f,  7.610366f,  5.146264f,  7.828427f,  7.414214f,  7.000000f,  5.878315f,  5.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.464102f,  3.464102f, 
+     3.146264f,  2.828427f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.878315f, 
+     7.656854f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.146264f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.000000f,  3.414214f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.732051f,  6.146264f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.732051f,  2.414214f,  2.000000f,  2.414214f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  2.414214f,  2.732051f,  3.146264f,  6.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.878315f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  3.146264f,  3.464102f,  4.464102f,  4.464102f,  3.464102f, 
+     3.146264f,  2.828427f,  3.146264f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  3.464102f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  4.146264f,  4.464102f,  4.878315f,  4.878315f,  4.464102f, 
+     4.146264f,  3.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.464102f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.146264f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196153f,  5.464102f,  5.878315f,  5.878315f,  5.464102f, 
+     5.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  3.732051f,  3.414214f,  3.732051f,  3.732051f,  4.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  8.196152f,  7.878315f,  7.560478f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.000000f,  4.732051f,  4.414214f,  4.732051f, 
+     5.146264f,  5.560478f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.464102f,  4.146264f,  3.146264f,  4.146264f,  5.146264f,  5.732051f,  5.414214f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  2.828427f,  3.146264f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  6.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.292529f,  6.610366f,  5.732051f,  5.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  8.071068f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     7.656854f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  7.656854f,  8.071068f,  8.485281f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  3.146264f,  2.828427f,  3.828427f,  4.146264f, 
+     6.560478f,  6.242640f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  5.560478f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  2.732051f,  2.414214f,  2.732051f,  5.146264f, 
+     3.414214f,  3.732051f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.828427f,  5.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  3.414214f, 
+     5.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.828427f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  2.414214f,  2.000000f,  2.414214f,  3.000000f, 
+     3.000000f,  3.414214f,  3.828427f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.732051f, 
+     4.146264f,  4.560478f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.146264f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  3.000000f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  9.120955f,  8.706742f,  6.292529f,  5.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  8.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  5.656854f,  5.974691f,  6.292529f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.560478f,  5.464102f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.242640f,  5.560478f,  5.878315f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  5.242640f,  5.146264f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  4.828427f,  5.146264f,  5.464102f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.414214f,  4.732051f,  5.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.146264f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  7.196152f,  7.464102f,  7.146265f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  3.464102f,  4.464102f,  5.464102f,  3.828427f,  4.146264f,  4.000000f,  4.414214f,  4.828427f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.242640f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  4.464102f,  3.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.196152f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  4.414214f,  4.732051f,  5.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.560478f,  4.242640f,  4.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.146264f,  5.196152f,  4.878315f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.828427f,  5.146264f,  5.464102f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.878315f,  5.196152f,  5.146264f, 
+     4.828427f,  5.146264f,  5.464102f,  5.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  7.292529f,  6.878315f,  2.000000f,  2.414214f,  5.242640f,  5.560478f,  4.146264f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.828427f,  6.878315f,  6.464102f, 
+     6.146264f,  5.828427f,  6.464102f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.974691f,  3.732051f, 
+     5.146264f,  4.732051f,  4.414214f,  7.196152f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.146264f,  4.828427f,  5.878315f,  5.464102f, 
+     5.146264f,  4.828427f,  5.146264f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  6.974691f,  3.414214f, 
+     6.146264f,  5.732051f,  6.610366f,  6.196152f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.414214f,  5.000000f,  6.828427f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.878315f,  4.464102f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  6.656854f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.732051f, 
+     8.196152f,  7.196152f,  6.196152f,  5.196152f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  4.464102f,  3.464102f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  7.071068f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  4.146264f, 
+     7.878315f,  6.878315f,  5.878315f,  4.878315f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  1.414214f, 
+     7.878315f,  6.560478f,  5.560478f,  4.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     3.828427f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  1.000000f, 
+     6.878315f,  6.464102f,  6.146264f,  4.242640f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.464102f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.146264f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.878315f,  6.560478f,  6.242640f,  7.974691f,  7.656854f,  7.974691f,  8.292528f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  1.414214f, 
+     5.878315f,  5.464102f,  5.146264f,  4.828427f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f, 
+     4.464102f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  9.342417f,  6.656854f,  4.146264f,  2.414214f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.414214f,  4.000000f,  4.414214f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  4.146264f,  3.828427f,  4.146264f,  4.146264f, 
+     3.828427f,  4.146264f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  8.928203f,  5.656854f,  5.974691f,  6.292529f, 
+     4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.414214f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.878315f,  6.292529f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  5.560478f,  5.242640f,  5.560478f,  5.878315f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.146264f,  4.828427f,  5.146264f,  5.464102f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.146264f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  4.732051f,  4.414214f,  4.732051f,  5.146264f, 
+    11.974690f, 11.560477f,  4.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  4.414214f,  4.000000f,  4.414214f,  4.828427f, 
+    10.974690f, 10.560477f, 10.146264f,  5.464102f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  5.974691f,  5.878315f, 
+     5.560478f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.000000f,  6.414214f,  4.414214f,  4.732051f,  5.146264f, 
+     9.974690f,  9.560477f,  9.146264f,  8.732051f,  6.196152f,  4.464102f,  4.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.878315f, 
+     4.560478f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  5.146264f,  5.464102f, 
+     8.974691f,  8.560477f,  8.146264f,  7.732051f,  6.610366f,  5.464102f,  5.878315f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.464102f, 
+     4.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f, 
+     7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  7.928203f,  6.878315f,  7.292529f,  6.878315f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146264f, 
+     3.732051f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.732051f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.974691f,  5.974691f,  5.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.732051f,  5.146264f,  3.828427f, 
+     3.414214f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.146264f,  5.464102f,  5.878315f, 
+     3.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.146264f,  6.196152f,  5.878315f,  5.560478f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.560478f,  5.878315f,  4.464102f, 
+     4.146264f,  3.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.974691f,  6.292529f,  4.878315f, 
+     4.560478f,  4.242640f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.146264f,  3.464102f,  4.464102f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  2.732051f,  1.732051f,  7.292529f,  6.974691f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.146264f,  4.732051f,  7.292529f,  7.610366f, 
+     5.560478f,  5.242640f,  4.146264f,  3.146264f,  2.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f, 
+     5.464102f,  5.878315f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.732051f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.146264f, 
+     4.464102f,  4.878315f,  5.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  2.732051f,  2.414214f,  2.732051f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.414214f,  2.732051f,  3.828427f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  3.146264f, 
+     3.464102f,  4.464102f,  5.464102f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  3.732051f,  3.414214f,  3.732051f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  4.732051f,  3.000000f,  3.414214f,  6.292529f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.928203f,  6.610366f,  6.292529f,  5.974691f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.388905f,  9.388905f,  3.414214f,  3.732051f,  7.292529f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.146264f,  3.828427f,  4.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  8.803119f,  9.803118f,  3.828427f,  4.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  4.464102f,  5.464102f,  5.146264f,  3.146264f,  2.828427f,  3.146264f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  2.732051f,  2.414214f,  3.414214f,  3.732051f, 
+     5.560478f,  5.242640f,  5.560478f,  5.878315f,  7.414214f,  7.732051f,  8.146264f,  8.560477f,  8.974691f,  9.388905f,  9.803118f, 10.217332f,  4.242640f,  4.560478f,  5.146265f,  4.732051f,  4.414214f,  4.732051f,  3.828427f,  4.146264f, 
+     3.146264f,  4.878315f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  1.732051f,  1.414214f,  1.732051f,  2.414214f, 
+     2.414214f,  2.732051f,  3.146264f,  4.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.242640f,  5.560478f,  4.828427f,  4.414214f,  4.000000f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  1.414214f,  1.000000f,  1.414214f,  2.000000f, 
+     2.000000f,  2.414214f,  2.828427f,  5.146264f,  4.414214f,  3.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  2.000000f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  6.974691f,  6.560478f,  4.146264f,  4.560478f,  5.560478f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.560478f, 
+     4.242640f,  4.560478f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  6.974691f,  7.292529f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  4.146264f, 
+     3.828427f,  4.146264f,  8.732051f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  6.560478f,  6.878315f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.242640f,  5.560478f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  6.146264f,  6.464102f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.242640f,  4.242640f,  3.828427f,  3.414214f, 
+     3.000000f,  3.414214f,  3.828427f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  5.414214f,  5.732051f,  6.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.560478f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  5.560478f,  7.928203f,  7.464102f,  6.464102f,  6.146265f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.000000f,  5.414214f,  5.828427f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  4.878315f,  4.464102f,  4.146264f, 
+     3.828427f,  4.146264f,  4.464102f,  5.242640f,  4.828427f,  4.414214f,  4.828427f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  3.732051f,  4.146264f,  4.560478f,  2.732051f,  2.414214f,  2.732051f,  5.414214f,  5.732051f,  6.146264f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  4.146264f,  3.828427f,  4.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.196152f,  4.878315f,  4.560478f, 
+     4.242640f,  4.560478f,  4.878315f,  5.560478f,  5.146264f,  4.732051f,  4.464102f,  4.146264f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.146264f,  6.464102f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.292529f,  5.878315f,  7.560478f,  5.560478f, 
+     5.242640f,  5.560478f,  5.878315f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  6.732051f,  6.414214f,  6.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.560478f,  3.146264f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.974691f,  6.560478f,  6.146264f, 
+     5.732051f,  5.414214f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  6.828427f,  7.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  2.732051f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.732051f,  5.146264f,  5.560478f,  5.560478f,  5.974691f,  5.560478f,  5.146264f, 
+     4.732051f,  4.414214f,  4.732051f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  7.242640f,  8.196152f,  7.196152f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  2.000000f,  2.414214f, 
+     6.464102f,  6.146264f,  5.828427f,  6.610366f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.196152f,  4.878315f,  4.560478f,  5.560478f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  2.414214f,  2.732051f, 
+     7.464102f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  3.146264f,  2.828427f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  4.878315f,  4.464102f,  4.146264f,  5.146264f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.828427f,  3.146264f, 
+     7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  4.146264f,  3.828427f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.828427f,  4.146264f, 
+     8.196152f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  5.146264f,  4.828427f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  4.828427f,  0.000000f, 
+     7.196152f,  6.878315f,  6.560478f,  5.146264f,  4.146264f,  3.146264f,  6.146264f,  5.828427f,  2.732051f,  3.146264f,  4.146264f,  5.414214f,  5.732051f,  6.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  1.414214f,  1.000000f, 
+     6.196152f,  5.878315f,  5.560478f,  5.242640f,  4.560478f,  4.146264f,  6.974691f,  5.974691f,  3.732051f,  4.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  6.828427f,  7.388905f,  7.071068f,  7.388905f,  7.706742f,  8.024579f,  8.342417f,  8.660254f,  9.660254f,  4.242640f,  4.560478f,  2.000000f, 
+     5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.560478f,  4.242640f,  4.560478f,  4.878315f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  9.342417f,  6.656854f,  5.560478f,  1.414214f, 
+     4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.560478f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f,  6.242640f,  6.560478f,  6.878315f, 
+     3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.242640f,  4.828427f,  4.414214f, 
+     4.000000f,  4.414214f,  4.828427f,  6.146264f,  6.560478f,  6.974691f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  6.146264f,  5.828427f,  6.146264f,  6.464102f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  3.414214f,  3.828427f,  4.242640f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  5.146264f,  4.732051f, 
+     4.414214f,  4.732051f,  5.146264f,  5.414214f,  5.828427f,  6.242640f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  5.732051f,  5.414214f,  5.732051f,  6.146264f, 
+    12.292528f, 11.878315f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  5.464102f,  5.146264f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  7.071068f,  5.414214f,  5.000000f,  5.414214f,  5.828427f, 
+    11.292528f, 10.878315f, 10.464102f,  4.464102f,  4.878315f,  5.878315f,  4.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.878315f,  6.292529f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  6.414214f,  6.732051f,  7.146264f,  5.732051f,  6.146264f, 
+    10.292528f,  9.878315f,  9.464102f,  9.146264f,  5.196152f,  6.196152f,  7.196152f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.828427f,  4.242640f,  4.464102f,  5.878315f, 
+     2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.464102f, 
+     9.292528f,  8.878315f,  8.464102f,  8.146264f,  6.196152f,  6.610366f,  7.610366f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.146264f,  5.464102f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f, 
+     8.292528f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.610366f,  8.024579f,  6.974691f,  6.560478f,  6.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.828427f,  5.146264f, 
+     2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.146264f,  4.464102f,  7.292529f,  6.974691f,  6.656854f,  6.974691f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  4.560478f,  4.146264f,  7.974691f,  6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.732051f,  4.146264f,  4.560478f, 
+     4.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.828427f,  3.146264f,  3.464102f,  7.706742f,  7.388905f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  7.706742f,  7.292529f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  4.146264f,  4.464102f,  4.878315f, 
+     4.732051f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.464102f,  7.196152f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  4.560478f,  4.878315f,  5.196152f, 
+     6.196152f,  3.414214f,  3.000000f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  7.610366f,  7.292529f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  5.242640f,  5.560478f,  5.878315f,  6.196152f, 
+     6.610366f,  4.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.414214f,  3.732051f,  4.146264f,  7.196152f, 
+     7.610366f,  5.414214f,  4.464102f,  3.464102f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     5.242640f,  6.242640f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.000000f,  3.414214f, 
+     5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     5.560478f,  5.196152f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.878315f,  4.732051f,  4.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  2.000000f,  2.414214f,  2.828427f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     5.878315f,  4.878315f,  5.878315f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  3.414214f,  3.828427f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f, 
+     6.196152f,  4.560478f,  5.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  9.292528f,  4.828427f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  3.414214f, 
+     3.828427f,  4.242640f,  5.242640f,  5.146264f,  4.732051f,  5.146264f,  4.732051f,  4.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  8.706742f,  9.706741f,  5.828427f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  3.732051f, 
+     4.146264f,  4.560478f,  5.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  9.120955f, 10.120955f,  4.828427f,  5.146264f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     4.464102f,  4.878315f,  5.878315f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.414214f,  2.000000f,  3.000000f,  3.414214f, 
+     4.560478f,  4.242640f,  4.560478f,  4.878315f,  7.828427f,  8.146264f,  8.464102f,  8.878315f,  9.292528f,  9.706741f, 10.120955f, 10.535169f, 11.535169f,  5.560478f,  6.146265f,  5.732051f,  5.414214f,  5.732051f,  4.242640f,  1.732051f, 
+     2.732051f,  3.732051f,  4.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  1.414214f,  1.000000f,  1.414214f,  1.414214f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  1.000000f,  0.000000f,  1.000000f,  1.000000f, 
+     1.000000f,  1.414214f,  2.414214f,  4.146264f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  1.000000f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f,  6.878315f,  3.146264f,  4.146264f,  5.146264f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  4.464102f,  8.828427f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f,  8.292528f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  6.292529f,  5.878315f,  5.464102f,  3.828427f,  4.828427f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  8.414213f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f,  7.878315f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  4.732051f,  8.000000f,  7.000000f,  6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  7.000000f,  7.146264f,  7.464102f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  3.732051f,  4.146264f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  6.732051f,  7.146264f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  5.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     3.464102f,  2.732051f,  3.146264f,  8.560478f,  7.560478f,  6.560478f,  6.146265f,  5.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  6.414214f,  6.828427f, 
+     3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.732051f,  4.414214f,  4.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.464102f,  4.146264f,  3.828427f,  5.146264f, 
+     4.464102f,  1.732051f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.828427f,  4.732051f,  4.414214f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  2.000000f,  2.414214f,  2.828427f,  6.732051f,  7.146264f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.464102f,  5.146264f,  4.828427f,  5.560478f, 
+     5.242640f,  1.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  3.414214f,  3.732051f,  7.000000f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  7.146264f,  3.732051f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  7.292529f,  6.610366f,  6.292529f,  5.974691f, 
+     5.656854f,  1.732051f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  2.414214f,  2.732051f, 
+     4.878315f,  4.560478f,  4.242640f,  4.560478f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  7.071068f,  6.656854f,  6.242640f,  5.828427f, 
+     5.414214f,  5.000000f,  6.196153f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  1.414214f,  1.732051f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.146264f,  5.464102f,  5.878315f,  5.974691f,  5.656854f,  5.242640f,  4.828427f, 
+     4.414214f,  4.000000f,  4.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  8.610366f,  7.610366f,  6.610366f,  6.196152f,  5.878315f,  5.560478f,  2.828427f,  1.000000f,  1.414214f, 
+     6.878315f,  6.560478f,  6.242640f,  5.464102f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  5.878315f,  5.560478f,  5.242640f,  4.242640f,  3.828427f, 
+     3.414214f,  3.000000f,  3.414214f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  8.292528f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  1.414214f,  1.732051f, 
+     7.878315f,  7.146265f,  6.146265f,  5.146265f,  4.146265f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  3.828427f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  2.414214f,  2.732051f, 
+     8.878315f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  4.146264f,  3.732051f,  3.414214f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  3.414214f,  3.732051f, 
+     8.610366f,  7.146265f,  6.146265f,  5.146265f,  4.146265f,  5.146264f,  4.732051f,  4.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  3.000000f,  2.000000f, 
+     1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.414214f,  4.732051f, 
+     7.610366f,  7.292529f,  6.464102f,  5.464102f,  4.464102f,  4.146264f,  5.732051f,  5.414214f,  3.146264f,  3.464102f,  4.464102f,  5.000000f,  5.414214f,  5.828427f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  7.292529f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.414214f,  5.732051f, 
+     5.146264f,  4.828427f,  5.146264f,  5.464102f,  4.878315f,  4.560478f,  6.732051f,  5.656854f,  4.146264f,  4.464102f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  2.828427f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.732051f,  6.414214f,  6.732051f,  8.071068f,  8.388905f,  8.706742f,  9.024579f,  9.342417f,  9.660254f,  5.560478f,  5.242640f,  6.414214f,  0.000000f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.560478f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  5.560478f,  5.242640f,  5.560478f,  3.828427f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.732051f,  8.292528f,  7.974691f,  7.656854f,  7.974691f,  8.292528f,  8.610366f,  8.928203f,  9.342417f,  6.146264f,  6.464102f,  6.878315f,  1.000000f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.656854f,  6.146264f,  4.828427f, 
+     4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  8.196152f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  8.610366f,  9.024579f,  5.146264f,  5.464102f,  5.878315f,  6.292529f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.242640f,  5.828427f,  5.414214f, 
+     5.000000f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  8.292528f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  8.292528f,  8.706742f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  6.146264f,  5.732051f, 
+     5.414214f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  7.974691f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.974691f,  8.388905f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+    12.610365f, 12.196152f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  5.464102f,  6.146264f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  6.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+    11.610365f, 11.196152f, 10.878315f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  7.560478f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+    10.610365f, 10.196152f,  9.878315f,  9.560477f,  4.878315f,  5.878315f,  6.878315f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  4.146264f,  3.146264f,  3.464102f,  4.464102f, 
+     3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  7.878315f,  7.464102f,  7.146264f,  6.828427f,  7.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     9.610365f,  9.196152f,  8.878315f,  8.560477f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  2.414214f,  2.732051f,  3.146264f,  2.732051f,  3.146264f,  4.146264f, 
+     2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.878315f,  7.878315f,  7.560478f,  7.242640f,  7.560478f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.878315f,  6.292529f, 
+     8.610366f,  8.196152f,  7.878315f,  7.560478f,  7.242640f,  7.292529f,  7.706742f,  8.706742f,  6.242640f,  5.828427f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  2.828427f,  3.828427f, 
+     2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.560478f,  4.878315f,  8.292528f,  7.974691f,  7.656854f,  7.974691f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     7.610366f,  7.196152f,  6.878315f,  6.560478f,  6.242640f,  4.146264f,  3.146264f,  2.732051f,  7.242640f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.146264f,  4.464102f,  4.878315f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f, 
+     6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  2.828427f,  2.414214f,  2.000000f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     5.464102f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     5.878315f,  3.732051f,  3.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.828427f,  4.242640f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f, 
+     5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  2.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  5.146265f,  4.828427f,  5.146264f,  5.464102f,  5.878315f, 
+     6.292529f,  4.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  2.414214f,  2.732051f,  3.146264f,  6.878315f, 
+     7.292529f,  7.706742f,  4.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.732051f, 
+     5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     4.828427f,  5.828427f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  4.146264f,  3.828427f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  6.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.732051f,  3.146264f,  4.146264f,  6.146264f,  6.560478f,  6.974691f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  2.828427f,  3.146264f,  4.146264f,  4.464102f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f, 
+     5.464102f,  6.464102f,  7.464102f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.000000f,  2.414214f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  2.414214f,  2.732051f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  3.732051f,  4.146264f,  4.560478f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f, 
+     5.878315f,  6.878315f,  4.464102f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  2.000000f,  2.414214f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  4.732051f,  5.146264f,  5.560478f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.828427f,  4.414214f,  4.828427f,  4.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  2.414214f,  2.732051f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f, 10.024579f,  6.146264f,  6.560478f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  3.828427f,  3.414214f,  3.000000f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  7.242640f,  7.560478f,  7.878315f,  8.196152f,  8.610366f,  9.024579f,  9.438792f, 10.438792f, 11.438792f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  2.828427f,  2.414214f,  2.000000f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  8.560477f,  8.878315f,  9.196152f,  9.610365f, 10.024579f, 10.438792f, 10.853005f, 11.853005f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  5.414214f,  1.414214f,  1.000000f,  1.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  1.732051f,  1.414214f,  1.732051f,  1.000000f, 
+     1.000000f,  4.828427f,  3.146264f,  2.732051f,  3.146264f,  4.146264f,  9.878315f,  1.732051f,  1.414214f,  1.732051f,  3.414214f,  3.732051f,  4.732051f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     2.000000f,  3.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  1.414214f,  1.000000f,  1.414214f,  0.000000f, 
+     0.000000f,  1.000000f,  3.464102f,  3.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  3.000000f,  3.414214f,  4.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  0.000000f,  1.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  7.610366f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  9.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f,  1.414214f, 
+     6.292529f,  5.974691f,  5.656854f,  5.974691f,  6.292529f,  6.610366f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  8.732051f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  1.000000f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  8.414213f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  8.414213f,  8.464102f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.414214f,  6.000000f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.414214f,  3.828427f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  6.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  8.732051f,  8.146264f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.414214f,  5.000000f,  5.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  2.414214f,  2.828427f,  8.146265f,  7.146265f,  6.146265f,  5.146265f,  5.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  7.414214f,  7.828427f, 
+     4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  1.414214f,  2.414214f,  3.828427f,  2.828427f,  2.414214f,  4.828427f,  4.414214f,  4.000000f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  2.732051f,  3.146264f,  4.146264f,  4.414214f, 
+     5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  1.000000f, 
+     0.000000f,  1.000000f,  2.000000f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  3.414214f,  3.000000f,  3.414214f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.000000f,  3.414214f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.000000f,  2.414214f, 
+     5.878315f,  5.560478f,  5.242640f,  5.560478f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.560478f,  4.878315f,  6.732051f,  6.414214f,  6.732051f,  6.560478f,  6.146264f, 
+     5.732051f,  2.414214f,  2.828427f,  4.878315f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  1.000000f,  1.414214f, 
+     6.292529f,  5.974691f,  5.656854f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  6.000000f,  5.878315f,  6.196153f,  5.414214f,  5.732051f,  5.560478f,  5.146264f, 
+     4.732051f,  4.414214f,  3.828427f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  1.000000f,  0.000000f,  1.000000f, 
+     7.292529f,  6.974691f,  6.656854f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.414214f,  4.732051f,  4.414214f,  4.732051f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  1.414214f,  1.000000f,  1.414214f, 
+     8.292528f,  7.560478f,  6.560478f,  5.560478f,  5.146265f,  2.828427f,  2.414214f,  2.000000f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  6.878315f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  2.000000f,  2.414214f, 
+     9.292528f,  7.242641f,  6.242641f,  5.242641f,  4.828427f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  6.560478f,  2.732051f,  2.414214f,  2.732051f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  3.000000f,  3.414214f, 
+     9.024579f,  7.560478f,  6.560478f,  5.560478f,  5.146265f,  4.828427f,  4.414214f,  4.000000f,  3.732051f,  4.146264f,  4.560478f,  6.414214f,  6.560478f,  7.560478f,  6.242640f,  1.732051f,  1.414214f,  1.732051f,  3.414214f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  4.000000f,  4.414214f, 
+     5.732051f,  5.414214f,  5.732051f,  5.878315f,  5.464102f,  5.146264f,  5.414214f,  5.000000f,  4.146264f,  4.464102f,  4.878315f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  1.414214f,  1.000000f,  1.414214f,  3.732051f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  7.706742f,  7.292529f,  6.878315f,  6.464102f,  6.146264f,  5.828427f,  5.000000f,  5.414214f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.560478f,  6.414214f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  1.732051f,  1.414214f,  1.732051f,  4.146264f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.974691f,  9.706741f, 10.024579f,  6.732051f,  6.414214f,  6.732051f,  6.242640f,  1.414214f,  1.732051f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.974691f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  2.414214f,  2.732051f,  4.560478f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.414214f,  7.000000f,  8.974691f,  7.388905f,  6.974691f,  9.292528f,  9.610365f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  1.000000f,  1.414214f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.732051f,  5.560478f,  5.146264f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  8.878315f,  8.560477f,  6.974691f,  5.974691f,  8.878315f,  9.196152f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  1.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  6.560478f,  6.146264f, 
+     5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.388905f,  8.878315f,  8.464102f,  7.560478f,  6.560478f,  5.560478f,  8.464102f,  8.878315f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  7.146264f,  6.732051f, 
+     6.414214f,  6.414214f,  6.732051f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  8.560477f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.732051f,  5.146264f,  5.560478f, 
+     5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  8.242640f,  7.828427f,  7.414214f,  7.000000f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+    11.928203f, 11.610365f, 11.292528f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  3.732051f,  4.146264f,  4.560478f, 
+     4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  8.560477f,  8.146264f,  7.732051f,  7.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f, 
+    10.928203f, 10.610365f, 10.292528f,  9.974690f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  8.878315f,  8.464102f,  8.146264f,  7.828427f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f, 
+     9.928203f,  9.610365f,  9.292528f,  8.974691f,  5.560478f,  5.974691f,  6.974691f,  7.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  2.828427f,  3.146264f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.292529f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f, 
+     8.928203f,  8.610366f,  8.292528f,  7.974691f,  7.656854f,  6.974691f,  7.388905f,  2.732051f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.560478f,  5.878315f,  6.196153f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  5.196152f,  6.196152f, 
+     7.928203f,  7.610366f,  7.292529f,  6.974691f,  6.656854f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.732051f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f, 
+     6.928203f,  6.610366f,  6.292529f,  5.974691f,  5.656854f,  5.974691f,  2.414214f,  1.414214f,  1.000000f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  6.974691f,  6.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     6.610366f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     5.560478f,  6.560478f,  3.828427f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f, 
+     6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  5.146265f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     5.974691f,  6.974691f,  5.560478f,  5.146264f,  4.732051f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f, 
+     5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  2.414214f,  2.732051f,  5.464102f,  5.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.560478f, 
+     6.974691f,  7.388905f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.560478f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.146264f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  2.000000f,  2.414214f,  2.828427f,  6.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  5.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.560478f,  4.242640f,  4.560478f,  4.146264f,  3.828427f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  6.974691f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.732051f,  5.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.656854f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  3.146264f,  3.464102f,  4.464102f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  6.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.242640f,  5.656854f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  8.610366f,  4.146264f,  4.464102f,  4.878315f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     5.560478f,  3.732051f,  4.146264f,  5.560478f,  4.560478f,  4.146264f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.292529f,  6.610366f,  6.928203f,  7.928203f,  8.928203f,  5.146264f,  5.464102f,  5.878315f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  5.146264f,  4.732051f,  5.146264f,  3.146264f,  2.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  9.342417f, 10.342416f,  6.464102f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  4.146264f,  3.732051f,  3.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.464102f,  3.146264f,  2.828427f,  3.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  8.292528f,  8.610366f,  8.928203f,  9.342417f,  9.756630f, 10.756630f, 11.756629f,  7.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.146264f,  2.732051f,  2.414214f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  9.292528f,  9.610365f,  2.828427f,  3.146264f,  2.828427f,  3.146264f, 12.170843f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  1.732051f,  1.414214f,  1.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f, 
+     4.732051f,  3.732051f,  2.732051f,  1.732051f,  5.560478f,  5.974691f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  5.414214f,  1.414214f,  1.000000f,  1.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  1.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f, 
+     1.000000f,  1.414214f,  6.560478f,  2.732051f,  2.414214f,  6.974691f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  1.414214f,  1.000000f,  2.732051f,  2.414214f,  2.732051f,  1.414214f, 
+     7.706742f,  7.388905f,  7.071068f,  7.388905f,  7.706742f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  3.828427f,  4.828427f,  8.464102f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  9.464102f,  1.000000f, 
+     7.292529f,  6.974691f,  6.656854f,  6.974691f,  7.292529f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f,  0.000000f, 
+     6.878315f,  6.560478f,  6.242640f,  6.560478f,  6.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f, 
+     2.000000f,  3.000000f,  4.000000f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  7.828427f,  8.828427f,  1.000000f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.732051f,  4.146264f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  8.146264f,  9.146264f,  2.000000f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.828427f,  2.732051f,  3.146264f,  7.146265f,  7.464102f,  6.464102f,  5.560478f,  5.732051f,  5.414214f,  5.732051f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  7.464102f,  8.464102f,  9.464102f,  5.732051f, 
+     5.828427f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  4.828427f,  4.414214f,  4.000000f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     3.828427f,  1.732051f,  2.732051f,  3.414214f,  2.414214f,  1.414214f,  6.560478f,  4.732051f,  4.414214f,  4.732051f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  3.464102f,  4.464102f,  4.732051f, 
+     6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.732051f,  4.414214f,  4.732051f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  3.732051f,  3.414214f,  3.732051f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  3.732051f, 
+     6.464102f,  6.146264f,  5.828427f,  6.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.828427f,  5.146264f,  6.656854f,  6.242640f,  1.414214f,  1.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.146264f,  6.464102f,  6.878315f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.414214f,  2.732051f, 
+     6.878315f,  6.560478f,  6.242640f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.560478f,  5.878315f,  6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f, 
+     2.414214f,  2.732051f,  3.146264f,  4.560478f,  4.146264f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     7.292529f,  6.974691f,  6.656854f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  6.414214f,  1.732051f,  5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f, 
+     5.146264f,  4.828427f,  4.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  3.464102f,  3.146264f,  2.828427f,  2.414214f,  2.732051f,  1.000000f,  1.414214f, 
+     7.706742f,  7.388905f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  7.732051f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f, 
+     4.146264f,  3.828427f,  4.146264f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  8.292528f,  7.878315f,  1.732051f,  1.414214f,  1.732051f,  1.414214f,  1.732051f, 
+     8.706742f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  7.974691f,  7.560478f,  7.146264f,  1.000000f,  1.414214f,  2.414214f,  2.732051f, 
+     7.414214f,  7.656855f,  6.656855f,  6.242641f,  5.828427f,  4.146264f,  3.732051f,  3.414214f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  7.656854f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  7.656854f,  7.242640f,  6.828427f,  1.414214f,  1.732051f,  3.414214f,  3.732051f, 
+     6.414214f,  6.000000f,  6.414214f,  6.560478f,  6.146265f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  6.828427f,  7.146264f,  7.974691f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  7.974691f,  7.560478f,  7.146264f,  2.414214f,  2.732051f,  3.000000f,  3.414214f, 
+     5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.464102f,  6.146264f,  5.732051f,  5.414214f,  5.146264f,  5.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  8.292528f,  7.878315f,  7.464102f,  3.414214f,  3.732051f,  2.000000f,  2.414214f, 
+     4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  6.560478f,  6.732051f,  6.292529f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.560478f,  7.242640f,  6.828427f,  6.414214f,  6.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.732051f,  7.414214f,  7.732051f,  7.071068f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  5.414214f,  1.000000f,  0.000000f,  1.000000f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  7.292529f,  8.292528f,  8.414213f,  7.656854f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  1.000000f,  1.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.414214f,  4.828427f,  5.242640f, 
+     6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  7.706742f,  5.560478f,  8.242640f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  2.414214f, 
+     1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  1.000000f,  1.414214f,  5.146264f, 
+     4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.146264f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.414214f,  1.732051f,  4.732051f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  3.146264f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  6.828427f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.000000f,  6.000000f,  5.000000f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  2.732051f, 
+    11.342416f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  7.242640f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.242640f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.414214f, 
+    10.342416f,  4.000000f,  4.414214f,  4.828427f,  5.242640f,  5.656854f,  6.656854f,  3.414214f,  3.000000f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  3.828427f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.828427f,  6.828427f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  2.732051f, 
+     5.414214f,  5.000000f,  5.414214f,  5.828427f,  6.242640f,  6.656854f,  2.828427f,  2.414214f,  2.000000f,  6.464102f,  6.146264f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 
+     4.000000f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.878315f,  7.196153f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  3.146264f, 
+     6.414214f,  6.000000f,  6.414214f,  6.828427f,  7.242640f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.464102f,  6.878315f,  7.292529f,  6.656854f,  5.656854f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.732051f,  4.146264f, 
+     7.414214f,  7.000000f,  7.414214f,  7.828427f,  4.000000f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     4.828427f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  5.878315f,  6.656854f,  6.242640f,  5.828427f,  5.414214f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  2.732051f, 
+     8.414213f,  8.000000f,  6.878315f,  6.560478f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     5.242640f,  6.242640f,  4.242640f,  4.560478f,  5.414214f,  5.000000f,  5.414214f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.242640f,  7.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  1.414214f,  2.414214f, 
+     6.414214f,  6.000000f,  6.414214f,  6.828427f,  5.828427f,  3.828427f,  6.464102f,  5.146264f,  4.732051f,  7.706742f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.242640f, 
+     5.656854f,  6.656854f,  5.242640f,  6.146264f,  5.732051f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.828427f,  5.242640f,  5.656854f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  1.414214f,  1.732051f,  2.732051f, 
+     5.414214f,  5.000000f,  5.414214f,  5.828427f,  5.414214f,  5.732051f,  6.146264f,  4.146264f,  3.732051f,  7.388905f,  3.414214f,  3.732051f,  5.878315f,  5.560478f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.242640f, 
+     6.656854f,  7.071068f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  6.242640f,  5.146264f,  4.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f, 
+     4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.000000f,  5.414214f,  5.828427f,  3.146264f,  2.732051f,  7.071068f,  3.000000f,  3.414214f,  3.828427f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 
+     4.000000f,  5.000000f,  0.000000f,  4.828427f,  3.828427f,  2.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  2.732051f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.732051f,  6.146264f,  2.732051f,  1.732051f,  7.388905f,  8.388905f,  3.732051f,  4.146264f,  4.560478f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  5.414214f,  1.000000f,  5.146265f,  4.146265f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  1.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  6.146264f,  6.464102f,  6.878315f,  1.414214f,  7.706742f,  8.706742f,  4.146264f,  4.464102f,  4.878315f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f, 
+     4.828427f,  5.828427f,  2.000000f,  5.464102f,  4.464102f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  5.000000f,  1.414214f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  8.024579f,  9.024579f,  4.560478f,  4.878315f,  5.196152f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f, 
+     3.000000f,  3.414214f,  3.828427f,  4.242640f,  4.878315f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.146264f,  4.560478f,  5.560478f,  1.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  7.292529f,  7.610366f,  7.928203f,  8.342417f,  9.342417f, 10.342416f,  5.878315f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  5.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.706742f,  8.024579f,  8.342417f,  8.660254f,  9.660254f, 10.660254f,  6.878315f,  6.242640f,  5.828427f,  5.414214f,  5.000000f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  4.464102f,  4.146264f,  3.828427f,  3.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.464102f,  4.146264f,  3.828427f,  4.146264f, 
+     2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  8.706742f,  9.024579f,  9.342417f,  9.660254f, 10.074467f, 11.074467f, 12.074467f,  7.242640f,  6.828427f,  4.464102f,  3.464102f,  3.000000f,  2.000000f,  1.000000f, 
+     0.000000f,  1.000000f,  2.000000f,  3.464102f,  3.146264f,  2.828427f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  4.878315f,  4.560478f,  4.242640f,  4.560478f, 
+     4.828427f,  3.828427f,  2.828427f,  3.828427f,  0.000000f,  1.000000f,  2.000000f,  4.146265f,  3.828427f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.732051f,  2.414214f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  4.146264f,  3.146264f,  2.732051f,  2.414214f, 
+     2.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  4.146264f,  3.732051f,  3.414214f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  2.000000f,  2.414214f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  2.732051f,  2.414214f,  4.146265f,  2.828427f,  2.414214f,  2.000000f, 
+     2.000000f,  2.414214f,  7.560478f,  2.414214f,  2.000000f,  2.414214f,  3.828427f,  3.414214f,  3.000000f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  4.242640f,  5.242640f,  1.414214f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  2.414214f,  2.000000f,  3.732051f,  3.414214f,  3.732051f,  2.414214f, 
+     8.706742f,  8.388905f,  8.071068f,  8.388905f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.878315f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  1.414214f, 
+     8.292528f,  7.974691f,  7.656854f,  7.974691f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  3.732051f,  4.732051f,  5.732051f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  5.828427f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  1.000000f, 
+     7.878315f,  7.560478f,  7.242640f,  7.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.414214f,  3.414214f,  4.414214f,  5.414214f,  7.242640f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  4.828427f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     2.732051f,  4.146264f,  4.464102f,  5.732051f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.828427f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  7.560478f,  1.414214f,  2.414214f,  3.414214f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  7.146264f,  6.464102f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f, 
+     3.146264f,  3.146264f,  3.464102f,  6.732051f,  7.878315f,  6.878315f,  5.878315f,  1.414214f,  2.414214f,  3.414214f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.878315f,  2.414214f,  2.828427f,  3.828427f, 
+     6.828427f,  6.414214f,  6.000000f,  6.414214f,  5.878315f,  5.464102f,  5.146264f,  4.732051f,  5.146264f,  4.732051f,  5.146264f,  0.000000f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  2.732051f,  3.146264f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.196152f,  3.414214f,  3.828427f,  5.146264f, 
+     7.146264f,  6.732051f,  6.414214f,  6.732051f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  2.414214f, 
+     2.000000f,  2.414214f,  2.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  0.000000f,  5.878315f,  6.196152f,  6.610366f,  7.610366f,  5.000000f,  5.414214f,  5.828427f,  4.146264f, 
+     7.464102f,  7.146264f,  6.828427f,  7.146264f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.414214f,  7.388905f,  6.974691f,  6.560478f,  1.000000f,  1.414214f,  2.414214f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.146264f,  3.464102f,  6.560478f,  6.878315f,  7.196152f,  7.610366f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  3.146264f, 
+     7.878315f,  7.560478f,  7.242640f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.000000f,  2.414214f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.146264f, 
+     2.828427f,  3.146264f,  3.464102f,  4.242640f,  3.828427f,  3.414214f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  7.560478f,  7.878315f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  2.732051f, 
+     8.292528f,  7.974691f,  5.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  1.000000f,  1.414214f,  1.414214f,  5.414214f,  5.732051f,  6.146264f,  6.560478f, 
+     6.974691f,  4.146264f,  4.464102f,  5.242640f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  2.414214f, 
+     8.706742f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  0.000000f,  1.000000f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     5.974691f,  4.242640f,  5.464102f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  0.000000f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  2.732051f, 
+     9.120955f,  7.464102f,  6.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  6.464102f,  1.000000f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     5.560478f,  3.828427f,  4.146264f,  4.464102f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  5.464102f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.146264f, 
+     7.732051f,  7.414214f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  6.656854f,  7.071068f,  2.000000f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  3.414214f,  3.732051f,  4.146264f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  2.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     6.732051f,  6.414214f,  6.732051f,  7.146264f,  7.146265f,  7.560478f,  7.146265f,  6.146265f,  5.732051f,  6.146264f,  6.560478f,  7.242640f,  7.560478f,  3.000000f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.878315f,  5.464102f,  5.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.292529f,  1.000000f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  3.414214f,  3.732051f, 
+     5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  7.146264f,  7.464102f,  6.464102f,  6.146264f,  6.464102f,  6.878315f,  6.242640f,  6.560478f,  6.878315f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.464102f,  6.146264f,  5.828427f,  6.146264f,  6.464102f,  6.878315f,  7.292529f,  0.000000f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  2.414214f,  2.732051f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  7.878315f,  6.878315f,  6.196152f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  6.878315f,  7.146264f,  6.828427f,  7.146264f,  7.464102f,  7.878315f,  7.560478f,  7.146264f,  1.414214f,  4.414214f,  2.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  8.292528f,  6.196152f,  5.196152f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     4.560478f,  4.242640f,  4.560478f,  4.878315f,  5.196152f,  6.196152f,  7.196152f,  8.146264f,  7.828427f,  8.146264f,  7.388905f,  6.974691f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.878315f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  4.878315f,  5.878315f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     5.560478f,  5.242640f,  5.560478f,  5.878315f,  6.196152f,  6.610366f,  1.000000f,  1.414214f,  2.414214f,  7.974691f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  1.732051f,  1.414214f,  1.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  1.414214f,  1.000000f,  5.146264f,  5.560478f, 
+     5.974691f,  6.242640f,  6.560478f,  6.878315f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  8.560477f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  2.414214f,  2.732051f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  1.414214f,  1.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  8.146264f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  3.414214f,  3.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  6.732051f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  1.000000f,  0.000000f,  1.414214f,  1.000000f,  1.414214f,  4.414214f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  2.414214f,  2.828427f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  1.414214f,  1.000000f,  1.414214f,  2.000000f,  2.414214f,  4.000000f, 
+     3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  4.000000f,  7.414214f,  6.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  1.414214f,  2.414214f, 
+     1.000000f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  4.732051f,  4.414214f,  4.878315f,  4.560478f,  4.242640f,  4.560478f,  4.878315f,  2.414214f,  2.000000f,  2.414214f,  2.732051f,  3.146264f,  4.414214f, 
+     3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  7.732051f,  6.732051f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  0.000000f,  1.000000f,  2.000000f, 
+     0.000000f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  4.146264f,  3.732051f,  3.414214f,  5.878315f,  5.560478f,  5.242640f,  5.560478f,  5.878315f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  7.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  1.000000f,  1.414214f,  2.414214f, 
+     5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  6.560478f,  5.560478f,  5.146264f,  4.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  4.242640f,  5.242640f,  8.196153f,  7.560478f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.000000f,  2.414214f,  0.000000f, 
+     6.732051f,  6.414214f,  6.732051f,  7.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  5.656854f,  5.242640f,  4.828427f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.732051f,  5.732051f,  4.414214f,  4.000000f,  4.414214f,  4.828427f,  5.974691f,  6.974691f,  7.878315f,  8.292528f,  6.974691f,  5.974691f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.000000f,  3.414214f,  2.828427f, 
+     8.732051f,  8.414213f,  8.732051f,  8.146264f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  5.974691f,  5.560478f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  6.146264f,  4.828427f,  5.146264f,  5.464102f,  5.878315f,  6.732051f,  7.146264f,  7.560478f,  6.732051f,  7.146264f,  7.560478f,  6.560478f,  6.146264f,  5.732051f,  5.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     7.732051f,  7.414214f,  7.732051f,  8.146264f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  5.878315f,  5.464102f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f, 
+     5.560478f,  6.560478f,  5.242640f,  5.560478f,  6.414214f,  6.000000f,  4.560478f,  4.242640f,  5.414214f,  5.732051f,  6.146264f,  6.560478f,  6.974691f,  7.146264f,  6.732051f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f, 
+     6.732051f,  6.414214f,  6.732051f,  7.146264f,  6.828427f,  4.146265f,  5.242640f,  4.828427f,  4.414214f,  4.000000f,  3.146264f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f, 
+     5.974691f,  6.974691f,  5.656854f,  7.146264f,  6.732051f,  4.464102f,  4.146264f,  4.732051f,  4.414214f,  4.732051f,  5.146264f,  5.560478f,  5.974691f,  1.000000f,  0.000000f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f, 
+     5.732051f,  5.414214f,  5.732051f,  6.146264f,  6.414214f,  6.732051f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f,  4.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  6.560478f, 
+     6.974691f,  1.732051f,  7.878315f,  7.464102f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  5.560478f,  6.560478f,  3.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f, 
+     4.732051f,  4.414214f,  4.732051f,  5.146264f,  6.000000f,  6.414214f,  3.828427f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  4.414214f,  4.828427f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f, 
+     4.414214f,  1.414214f,  1.000000f,  6.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  2.414214f,  2.000000f,  2.414214f,  5.560478f,  3.414214f,  3.828427f, 
+     3.732051f,  3.414214f,  3.732051f,  4.146264f,  4.560478f,  6.732051f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  4.732051f,  5.146264f,  5.560478f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f, 
+     4.732051f,  1.732051f,  1.414214f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  1.414214f,  1.000000f,  1.414214f,  5.146264f,  4.828427f,  5.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  7.146264f,  3.000000f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  5.146264f,  5.464102f,  5.878315f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f, 
+     5.146264f,  4.732051f,  2.414214f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  5.414214f,  1.000000f,  0.000000f,  5.146264f,  4.732051f,  4.414214f,  4.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  7.560478f,  7.878315f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  5.878315f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  4.146264f,  3.732051f, 
+     3.414214f,  3.732051f,  4.146264f,  4.560478f,  4.732051f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  5.732051f,  1.414214f,  1.000000f,  4.828427f,  4.414214f,  4.000000f,  4.414214f, 
+     1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.414214f,  8.292528f,  8.610366f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.292529f,  5.560478f,  5.146264f,  4.732051f,  4.414214f,  4.732051f,  3.146264f,  2.732051f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  3.464102f,  4.464102f,  5.464102f,  2.000000f,  2.414214f,  4.732051f,  4.414214f,  4.732051f, 
+     1.732051f,  1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.732051f,  8.706742f,  9.024579f,  3.414214f,  3.000000f,  3.414214f,  3.828427f,  7.292529f,  6.560478f,  6.146264f,  5.732051f,  4.732051f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  4.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  6.146264f,  7.146264f,  5.146264f,  4.828427f,  5.146264f, 
+     2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  9.120955f,  3.732051f,  4.414214f,  4.000000f,  4.414214f,  3.414214f,  3.828427f,  7.560478f,  7.146264f,  5.414214f,  4.414214f,  3.414214f,  2.414214f,  1.414214f, 
+     1.000000f,  1.414214f,  2.414214f,  3.414214f,  4.146264f,  3.828427f,  5.146264f,  4.732051f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  3.828427f,  4.828427f,  5.828427f,  5.146265f,  5.560478f,  5.242640f,  5.560478f, 
+     4.414214f,  3.414214f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  3.414214f,  2.828427f,  2.414214f,  2.000000f,  2.414214f,  2.828427f,  6.560478f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  2.732051f,  1.732051f, 
+     1.414214f,  1.732051f,  2.732051f,  3.732051f,  3.732051f,  3.414214f,  5.146264f,  4.146264f,  3.146264f,  2.732051f,  2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  3.828427f,  4.146265f,  4.146264f,  3.732051f,  3.414214f, 
+     3.414214f,  3.732051f,  2.732051f,  1.732051f,  1.414214f,  1.732051f,  2.732051f,  4.732051f,  2.414214f,  1.414214f,  1.000000f,  1.414214f,  2.414214f,  6.242640f,  5.242640f,  4.242640f,  3.828427f,  3.414214f,  3.000000f,  3.414214f, 
+     2.414214f,  2.732051f,  3.146264f,  4.146264f,  5.146264f,  0.000000f,  5.464102f,  4.464102f,  3.464102f,  3.146264f,  2.828427f,  3.146264f,  3.464102f,  4.464102f,  3.732051f,  3.414214f,  5.146265f,  4.828427f,  3.414214f,  3.000000f, 
+     3.000000f,  3.414214f,  8.560478f,  2.732051f,  2.414214f,  2.732051f,  4.828427f,  4.414214f,  2.000000f,  1.000000f,  0.000000f,  1.000000f,  2.000000f,  3.000000f,  5.560478f,  4.560478f,  4.146264f,  3.732051f,  3.414214f,  3.732051f, 
+     4.146264f,  4.560478f,  4.146264f,  4.560478f,  5.560478f,  1.000000f,  5.878315f,  4.878315f,  4.464102f,  4.146264f,  3.828427f,  4.146264f,  4.464102f,  3.828427f,  3.414214f,  3.000000f,  4.732051f,  4.414214f,  4.732051f,  3.414214f
+};
+
+static unsigned int eccTrafo_volume_centers[663] = {
+    0, 0, 0, 10, 2, 5, 20, 2, 5, 27, 7, 5, 31, 3, 9, 38, 4, 7, 19, 10, 3, 3, 9, 7, 24, 14, 2, 12, 10, 5, 
+    32, 17, 3, 16, 15, 4, 2, 16, 6, 15, 25, 1, 38, 16, 3, 14, 21, 4, 33, 24, 3, 24, 25, 7, 2, 31, 6, 8, 27, 4, 
+    31, 28, 3, 34, 35, 5, 7, 38, 1, 19, 34, 4, 37, 38, 3, 24, 34, 4, 28, 34, 4, 39, 36, 1, 14, 37, 5, 25, 38, 1, 
+    36, 8, 6, 20, 22, 8, 35, 15, 6, 16, 28, 5, 27, 36, 6, 24, 38, 9, 29, 2, 17, 39, 13, 9, 31, 13, 12, 35, 23, 9, 
+    30, 21, 12, 27, 28, 13, 12, 31, 12, 30, 39, 12, 9, 8, 12, 4, 17, 10, 26, 14, 13, 6, 19, 12, 11, 27, 11, 15, 37, 11, 
+    38, 37, 10, 19, 7, 13, 35, 17, 12, 3, 25, 14, 35, 29, 12, 22, 27, 13, 6, 2, 14, 11, 13, 12, 38, 9, 13, 19, 11, 15, 
+    21, 38, 14, 1, 13, 15, 12, 25, 13, 2, 32, 17, 39, 32, 10, 34, 33, 14, 31, 34, 16, 36, 38, 10, 1, 10, 23, 29, 13, 16, 
+    21, 22, 15, 8, 25, 15, 5, 29, 19, 11, 34, 15, 5, 38, 17, 12, 17, 15, 37, 22, 15, 38, 27, 17, 14, 39, 15, 13, 1, 21, 
+    12, 6, 20, 37, 18, 16, 26, 17, 20, 6, 22, 18, 39, 6, 18, 17, 15, 19, 29, 21, 19, 3, 23, 22, 16, 24, 21, 18, 30, 21, 
+    24, 37, 20, 22, 4, 21, 30, 5, 21, 4, 10, 22, 21, 12, 20, 9, 10, 21, 37, 10, 22, 8, 18, 21, 38, 16, 20, 33, 20, 21, 
+    18, 37, 20, 22, 8, 22, 32, 25, 24, 28, 30, 22, 36, 39, 18, 39, 39, 18, 22, 21, 24, 10, 35, 24, 24, 29, 23, 38, 35, 21, 
+    15, 34, 24, 29, 39, 21, 34, 39, 18, 28, 13, 24, 36, 30, 25, 31, 35, 25, 36, 39, 22, 17, 16, 23, 8, 23, 26, 39, 28, 22, 
+    9, 13, 25, 32, 13, 26, 3, 34, 26, 7, 39, 22, 20, 39, 24, 27, 3, 28, 38, 8, 27, 31, 7, 25, 30, 6, 29, 15, 10, 31, 
+    24, 13, 28, 3, 19, 28, 8, 2, 28, 37, 20, 30, 7, 39, 26, 39, 39, 28, 30, 20, 30, 20, 31, 27, 12, 34, 31, 16, 38, 30, 
+    25, 37, 30, 37, 4, 30, 2, 5, 33, 20, 3, 32, 6, 14, 31, 12, 24, 30, 37, 12, 32, 20, 18, 31, 7, 38, 32, 18, 34, 32, 
+    33, 39, 29, 30, 2, 36, 17, 13, 32, 21, 25, 31, 25, 27, 33, 35, 27, 34, 28, 30, 30, 4, 30, 33, 12, 5, 34, 11, 19, 36, 
+    3, 19, 32, 39, 33, 30, 14, 25, 35, 38, 33, 35, 30, 36, 37, 7, 12, 34, 22, 24, 35, 37, 38, 35, 35, 39, 36, 35, 7, 36, 
+    28, 9, 37, 21, 13, 36, 10, 30, 35, 18, 2, 38, 7, 9, 37, 1, 19, 38, 16, 24, 38, 27, 30, 36, 16, 30, 38, 1, 34, 38, 
+    0, 39, 36, 18, 38, 36, 25, 38, 36, 39, 38, 36, 26, 5, 39, 38, 9, 37, 39, 13, 35, 4, 37, 38, 8, 39, 35, 8, 1, 38, 
+    39, 15, 36, 8, 26, 38, 20, 6, 37, 35, 21, 38, 28, 32, 38, 20, 36, 38, 10, 39, 39, 39, 1, 38, 16, 14, 38, 38, 16, 38, 
+    23, 21, 39, 16, 8, 39, 13, 10, 39, 36, 11, 39, 17, 19, 39, 37, 22, 39, 37, 27, 39, 9, 32, 39, 22, 30, 38, 35, 32, 39, 
+    25, 38, 39, 36, 2, 39, 11, 5, 39, 31, 6, 39, 32, 10, 39, 33, 14, 39, 26, 18, 39, 15, 20, 39, 0, 23, 39, 39, 24, 39, 
+    34, 28, 39
+};
+
+#endif // VIGRA_MULTIDISTANCE_TEST_DATA_HXX
diff --git a/test/multimorphology/test.cxx b/test/multimorphology/test.cxx
index 54152e3..e3f43b0 100644
--- a/test/multimorphology/test.cxx
+++ b/test/multimorphology/test.cxx
@@ -177,40 +177,75 @@ struct MultiMorphologyTest
         IntVolume res(vol.shape()), res2(vol.shape());
         int f = NumericTraits<int>::one();
         
-        static const int desired[] = {  0, 0, 0, 0, 0, 
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,
-
-                                        0, 0, 0, 0, 0, 
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,
-
-                                        0, 0, 0, 0, 0, 
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, f, 0, 0,  
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,
-
-                                        0, 0, 0, 0, 0, 
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,
-
-                                        0, 0, 0, 0, 0, 
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0,  
-                                        0, 0, 0, 0, 0};
+        static const int desiredErosion[] = {  0, 0, 0, 0, 0, 
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,
+                                               
+                                               0, 0, 0, 0, 0, 
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,
+                                               
+                                               0, 0, 0, 0, 0, 
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, f, 0, 0,  
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,
+                                               
+                                               0, 0, 0, 0, 0, 
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,
+                                               
+                                               0, 0, 0, 0, 0, 
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0,  
+                                               0, 0, 0, 0, 0};
 
         multiBinaryErosion(vol, res, 1);
-        shouldEqualSequence(res.begin(), res.end(), desired);
+        shouldEqualSequence(res.begin(), res.end(), desiredErosion);
+
+        static const int desiredDilation[] = {  0, 0, 0, 0, 0, 
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, 0, 0, 0,
+                                                
+                                                0, 0, 0, 0, 0, 
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, f, 0, 0,  
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, 0, 0, 0,
+                                                
+                                                0, 0, 0, 0, 0, 
+                                                0, 0, f, 0, 0,  
+                                                0, f, f, f, 0,  
+                                                0, 0, f, 0, 0,  
+                                                0, 0, 0, 0, 0,
+                                                
+                                                0, 0, 0, 0, 0, 
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, f, 0, 0,  
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, 0, 0, 0,
+                                                
+                                                0, 0, 0, 0, 0, 
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, 0, 0, 0,  
+                                                0, 0, 0, 0, 0};
+
+        IntVolume v2(res);
+        
+        multiBinaryDilation(v2, res, 1);
+        shouldEqualSequence(res.begin(), res.end(), desiredDilation);
 
-        multiBinaryDilation(res, res2, 1.8);
+        multiBinaryDilation(v2, res2, 1.8);
         shouldEqualSequence(res2.begin(), res2.end(), vol.begin());
     }
     
diff --git a/test/objectfeatures/CMakeLists.txt b/test/objectfeatures/CMakeLists.txt
index 2052e49..90c0e31 100644
--- a/test/objectfeatures/CMakeLists.txt
+++ b/test/objectfeatures/CMakeLists.txt
@@ -1,4 +1,4 @@
 VIGRA_ADD_TEST(test_objectfeatures test.cxx LIBRARIES vigraimpex)
-
+VIGRA_ADD_TEST(test_stand_alone_acc_chain stand_alone_acc_chain.cxx)
 VIGRA_COPY_TEST_DATA(of.gif)
 
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/test/objectfeatures/stand_alone_acc_chain.cxx
similarity index 57%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to test/objectfeatures/stand_alone_acc_chain.cxx
index 37a8c81..e9b86db 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/test/objectfeatures/stand_alone_acc_chain.cxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*             Copyright 2011-2012 by Ullrich Koethe                    */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,86 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
-
-#include <Python.h>
-#include <vigra/config.hxx>
 #include <iostream>
-#include <boost/python.hpp>
-#include <vigra/numpy_array.hxx>
-#include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
+#include <sstream>
+#include <map>
+#include <set>
+
+#include <vigra/unittest.hxx>
+#include <vigra/multi_array.hxx>
+#include <vigra/accumulator.hxx>
 
-namespace python = boost::python;
 
-namespace vigra {
+using namespace vigra;
 
-UInt32 pychecksum(python::str const & s)
+// mask cl.exe shortcomings
+#if defined(_MSC_VER)
+#pragma warning( disable : 4503 )
+#endif
+
+struct StandAloneAccChainTest
 {
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
+    StandAloneAccChainTest()
+    {}
+    
+    void testStandardizeTag()
+    {
+        using namespace vigra::acc;
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+        typedef double DataType;
+        typedef MultiArrayShape<3>::type CoordType;
+        typedef MultiArrayShape<3>::type   Point;
 
-} // namespace vigra
+        typedef Select< 
+            DataArg<1>,
+            Variance, 
+            Mean, 
+            StdDev, 
+            Minimum, 
+            Maximum, 
+            RootMeanSquares, 
+            Skewness,
+            Covariance,
+            RegionCenter
+        >  SelectType;
+
+        typedef StandAloneAccumulatorChain<3, DataType, SelectType> FreeChain;
+        FreeChain a;
+
+        a.updatePassN(1.0, Point(3,0,0), 1);
+        a.updatePassN(2.0, Point(0,3,0), 1);
+        a.updatePassN(3.0, Point(0,0,3), 1);
+        
 
-using namespace boost::python;
-using namespace vigra;
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
+        a.updatePassN(1.0, Point(3,0,0), 2);
+        a.updatePassN(2.0, Point(0,3,0), 2);
+        a.updatePassN(3.0, Point(0,0,3), 2);
+
+        shouldEqualTolerance( get<Mean>(a), 2.0, 0.000001);
+
+        CoordType rCenter = get<RegionCenter>(a);
+        CoordType trueCenter(1,1,1);
+        shouldEqualSequence(rCenter.begin(),rCenter.end(), trueCenter.begin());
+    }
+};
+
+
+
+struct StandAloneAccChainTestSuite : public vigra::test_suite
 {
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
+    StandAloneAccChainTestSuite()
+        : vigra::test_suite("StandAloneAccChainTestSuite")
+    {
+        add(testCase(&StandAloneAccChainTest::testStandardizeTag));
+    }
+};
+
+int main(int argc, char** argv)
+{
+    StandAloneAccChainTestSuite test;
+    const int failed = test.run(vigra::testsToBeExecuted(argc, argv));
+    std::cout << test.report() << std::endl;
+
+    return failed != 0;
 }
diff --git a/test/objectfeatures/test.cxx b/test/objectfeatures/test.cxx
index dad316b..051c8ee 100644
--- a/test/objectfeatures/test.cxx
+++ b/test/objectfeatures/test.cxx
@@ -244,6 +244,16 @@ struct AccumulatorTest
             // nested Select
         should((IsSameType<Select<Count, Mean, Select<Sum, Minimum>, Variance>::type,
                            Select<Count, Mean, Sum, Minimum, Variance>::type>::value));
+
+            // RegionContour
+        should((IsSameType<StandardizeTag<RegionContour>::type,
+                           RegionContour >::value));
+        should((IsSameType<StandardizeTag<DataFromHandle<RegionContour> >::type,
+                           RegionContour >::value));
+        should((IsSameType<StandardizeTag<Coord<RegionContour> >::type,
+                           RegionContour >::value));
+        should((IsSameType<StandardizeTag<Weighted<Coord<RegionContour> > >::type,
+                           RegionContour >::value));
     }
 
     template <class SOURCE, class REFERENCE>
@@ -534,6 +544,8 @@ struct AccumulatorTest
             typedef AccumulatorChain<V::view_type, Select<Covariance, Mean, StdDev, Minimum, Maximum, CentralMoment<2> > > A;
             typedef LookupTag<Mean, A>::value_type W;
             typedef LookupTag<Covariance, A>::value_type Var;
+            
+            should((IsSameType<W, MultiArray<1, double> >::value));
 
             A a;
 
@@ -564,7 +576,7 @@ struct AccumulatorTest
             shouldEqual(get<Variance>(a), variance);
 
             W stddev = sqrt(variance);
-            shouldEqualTolerance(stddev, get<StdDev>(a), W(1e-15));
+            shouldEqualTolerance(stddev, get<StdDev>(a), W(s, 1e-15));
 
             a.reset(1);
 
@@ -732,7 +744,7 @@ struct AccumulatorTest
             typedef Iterator::value_type Handle;
             typedef Shape3 V;
 
-            typedef AccumulatorChain<Handle, Select<Coord<Maximum>, Coord<Minimum>, Coord<Mean>, Coord<StdDev>, Coord<Covariance>,
+            typedef AccumulatorChain<Handle, Select<Coord<Maximum>, Coord<Minimum>, BoundingBox, Coord<Mean>, Coord<StdDev>, Coord<Covariance>,
                                                Coord<Principal<Variance> >, Coord<Principal<CoordinateSystem> >,
                                                Coord<AbsSum>, Coord<MeanAbsoluteDeviation>, Coord<CovarianceEigensystem>
                                           > > A;
@@ -755,6 +767,8 @@ struct AccumulatorTest
             shouldEqual(get<Count>(a), 3.0);
             shouldEqual(get<Coord<Minimum> >(a), V(1));
             shouldEqual(get<Coord<Maximum> >(a), V(3));
+            shouldEqual(get<BoundingBox>(a).first, V(1));
+            shouldEqual(get<BoundingBox>(a).second, V(3));
             shouldEqual(get<Coord<Sum> >(a), W(6.0));
             shouldEqual(get<Coord<AbsSum> >(a), W(6.0));
             shouldEqual(get<Coord<Mean> >(a), W(2.0));
@@ -1116,7 +1130,7 @@ struct AccumulatorTest
         return acc::acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference>::exec(a);
     }
 
-    void testLabelDispatch()
+    void testRegionAccumulators()
     {
         using namespace vigra::acc;
         {
@@ -1124,13 +1138,13 @@ struct AccumulatorTest
             typedef Iterator::value_type Handle;
             typedef Shape2 V;
 
-            typedef Select<Count, Coord<Sum>, Global<Count>, Global<Coord<Minimum> >, LabelArg<1>, DataArg<1> > Selected;
+            typedef Select<Count, RegionAnchor, Coord<Sum>, Global<Count>, Global<Coord<Minimum> >, LabelArg<1>, DataArg<1> > Selected;
             typedef AccumulatorChainArray<Handle, Selected> A;
 
             should((IsSameType<acc::acc_detail::ConfigureAccumulatorChainArray<Handle, Selected>::GlobalTags, 
                                TypeList<Count,TypeList<Coord<Minimum>,TypeList<DataArg<1>, TypeList<LabelArg<1>, void> > > > >::value));
             should((IsSameType<acc::acc_detail::ConfigureAccumulatorChainArray<Handle, Selected>::RegionTags, 
-                               TypeList<Count,TypeList<Coord<Sum>,TypeList<DataArg<1>, void> > > >::value));
+                               TypeList<RegionAnchor,TypeList<Count,TypeList<Coord<Sum>,TypeList<DataArg<1>, TypeList<LabelArg<1>, void> > > > > >::value));
 
             typedef LookupTag<Count, A>::type RegionCount;
             typedef LookupDependency<Global<Count>, RegionCount>::type GlobalCountViaRegionCount;
@@ -1166,10 +1180,19 @@ struct AccumulatorTest
             shouldEqual(2, get<Count>(a, 1));
             shouldEqual(6, get<Global<Count> >(a));
 
+            shouldEqual(Shape2(0,0), get<RegionAnchor>(a, 0));
+            shouldEqual(Shape2(2,0), get<RegionAnchor>(a, 1));
+
             shouldEqual(V(2,2), get<Coord<Sum> >(a, 0));
             shouldEqual(V(4,1), get<Coord<Sum> >(a, 1));
             shouldEqual(V(0,0), get<Global<Coord<Minimum> > >(a));
 
+            a.merge(1, 0);
+
+            shouldEqual(6, get<Count>(a, 1));
+            shouldEqual(Shape2(0,0), get<RegionAnchor>(a, 1));
+            shouldEqual(V(6,3), get<Coord<Sum> >(a, 1));
+
             A aa;
             aa.setMaxRegionLabel(1);
             aa.setCoordinateOffset(V(2, -1));
@@ -1185,6 +1208,23 @@ struct AccumulatorTest
             shouldEqual(V(8,-1), get<Coord<Sum> >(aa, 1));
             shouldEqual(V(2,-1), get<Global<Coord<Minimum> > >(aa));
 
+            A ab;
+            ab.setMaxRegionLabel(1);
+            ab.setCoordinateOffset(V(2, -1));
+            ab.setCoordinateOffset(0, V(-1,1));
+            ab.setCoordinateOffset(1, V(1,-2));
+
+            for(i = start; i < end; ++i)
+                ab(*i);
+            
+            shouldEqual(4, get<Count>(ab, 0));
+            shouldEqual(2, get<Count>(ab, 1));
+            shouldEqual(6, get<Global<Count> >(ab));
+
+            shouldEqual(V(-2,6), get<Coord<Sum> >(ab, 0));
+            shouldEqual(V(6,-3), get<Coord<Sum> >(ab, 1));
+            shouldEqual(V(2,-1), get<Global<Coord<Minimum> > >(ab));
+
             A b;
             b.ignoreLabel(0);
 
@@ -1206,7 +1246,8 @@ struct AccumulatorTest
             typedef CoupledIteratorType<2, double, int>::type Iterator;
             typedef Iterator::value_type Handle;
 
-            typedef AccumulatorChainArray<Handle, Select<Count, AutoRangeHistogram<3>, GlobalRangeHistogram<3>,
+            typedef AccumulatorChainArray<Handle, Select<Count, RegionPerimeter, RegionCircularity, RegionEccentricity, 
+                                                         AutoRangeHistogram<3>, GlobalRangeHistogram<3>,
                                                          Global<Count>, Global<AutoRangeHistogram<3> >, DataArg<1>, LabelArg<2>
                                           > > A;
 
@@ -1256,6 +1297,24 @@ struct AccumulatorTest
             shouldEqual(V(3,1,0), get<GlobalRangeHistogram<3> >(a, 0));
             shouldEqual(V(0,1,1), get<GlobalRangeHistogram<3> >(a, 1));
             shouldEqual(V(3,2,1), get<Global<AutoRangeHistogram<3> > >(a));
+
+            typedef LookupTag<RegionContour, A>::value_type::value_type Point;
+
+            Point ref0[] = { Point(0, -0.5), Point(-0.5, 0), Point(-0.5, 1), Point(0, 1.5), Point(1, 1.5), 
+                             Point(1.5, 1), Point(1.5, 0), Point(1, -0.5), Point(0.0, -0.5) };
+            shouldEqual(get<RegionContour>(a, 0).size(), 9);
+            shouldEqualSequence(get<RegionContour>(a, 0).cbegin(), get<RegionContour>(a, 0).cend(), ref0);
+            shouldEqualTolerance(get<RegionPerimeter>(a, 0), 4.0 + 2.0*M_SQRT2, 1e-15);
+            shouldEqualTolerance(get<RegionCircularity>(a, 0), 0.9712214720608953, 1e-15);
+            shouldEqualTolerance(get<RegionEccentricity>(a, 0), 0.0, 1e-15);
+ 
+            Point ref1[] = { Point(2, -0.5), Point(1.5, 0), Point(1.5, 1), Point(2, 1.5), 
+                             Point(2.5, 1), Point(2.5, 0), Point(2, -0.5) };
+            shouldEqual(get<RegionContour>(a, 1).size(), 7);
+            shouldEqualSequence(get<RegionContour>(a, 1).cbegin(), get<RegionContour>(a, 1).cend(), ref1);
+            shouldEqualTolerance(get<RegionPerimeter>(a, 1), 2.0 + 2.0*M_SQRT2, 1e-15);
+            shouldEqualTolerance(get<RegionCircularity>(a, 1), 0.8991763601646624, 1e-15);
+            shouldEqualTolerance(get<RegionEccentricity>(a, 1), 1.0, 1e-15);
         }
 
         {
@@ -1431,6 +1490,65 @@ struct AccumulatorTest
             shouldEqual(W(3, 0, 1), get<AutoRangeHistogram<3> >(c,3));
         }
     }
+
+    void testConvexHullFeatures()
+    {
+        using namespace vigra::acc;
+
+        int size = 6;
+        MultiArray<2, int> mask(vigra::Shape2(size, size));
+
+        mask(1, 1) = 1;
+        mask(2, 1) = 1;
+        mask(2, 2) = 1;
+        mask(2, 3) = 1;
+        mask(1, 3) = 1;
+        mask(3, 1) = 1;
+        mask(3, 3) = 1;
+        mask(4, 1) = 1;
+        mask(4, 3) = 1;
+
+        //for(auto i = mask.begin(); i != mask.end(); ++i)
+        //{
+        //    std::cerr << (*i ? "*" : " ");
+        //    if(i.point()[0] == mask.shape(0)-1)
+        //        std::cerr << "\n";
+        //}
+
+        AccumulatorChainArray<CoupledArrays<2, int>, 
+                              Select<LabelArg<1>, ConvexHull> > chf;
+        chf.ignoreLabel(0);
+        extractFeatures(mask, chf);
+
+        shouldEqual(getAccumulator<ConvexHull>(chf, 1).inputArea(), 8.5);
+        shouldEqualTolerance(getAccumulator<ConvexHull>(chf, 1).inputPerimeter(), 8.0 + 6.0*M_SQRT2, 1e-15);
+
+        typedef TinyVector<double, 2> P;
+        P ref[] = { P(1.0, 0.5), P(0.5, 1.0), P(0.5, 3.0), P(1.0, 3.5), P(4.0, 3.5), 
+                    P(4.5, 3.0), P(4.5, 1.0), P(4.0, 0.5),  P(1.0, 0.5) };
+        shouldEqual(get<ConvexHull>(chf, 1).hull().size(), 9);
+        shouldEqualSequence(ref, ref+9, get<ConvexHull>(chf, 1).hull().begin());
+        shouldEqual(get<ConvexHull>(chf, 1).hullArea(), 11.5);
+        shouldEqualTolerance(get<ConvexHull>(chf, 1).hullPerimeter(), 10.0 + 2.0*M_SQRT2, 1e-15);
+
+        shouldEqualTolerance(get<ConvexHull>(chf, 1).convexity(), 8.5 / 11.5, 1e-15);
+        shouldEqualTolerance(get<ConvexHull>(chf, 1).rugosity(),  1.2850586602653933, 1e-15);
+
+        shouldEqual(get<ConvexHull>(chf, 1).convexityDefectCount(), 2);
+        shouldEqual(get<ConvexHull>(chf, 1).defectAreaList().size(), 2);
+        shouldEqual(get<ConvexHull>(chf, 1).defectAreaList()[0], 2);
+        shouldEqual(get<ConvexHull>(chf, 1).defectAreaList()[1], 1);
+
+        shouldEqualTolerance(get<ConvexHull>(chf, 1).convexityDefectAreaMean(), 1.5, 1e-15);
+        shouldEqualTolerance(get<ConvexHull>(chf, 1).convexityDefectAreaVariance(), 0.5, 1e-15);
+        shouldEqualTolerance(get<ConvexHull>(chf, 1).convexityDefectAreaSkewness(), 0.0, 1e-15);
+        shouldEqualTolerance(get<ConvexHull>(chf, 1).convexityDefectAreaKurtosis(), 0.0, 1e-15);
+        shouldEqualTolerance(get<ConvexHull>(chf, 1).meanDefectDisplacement(), 1.185185185185185, 1e-15);
+
+        shouldEqualTolerance(P(2.4444444444444444, 2.0), get<ConvexHull>(chf, 1).inputCenter(), P(1e-15));
+        shouldEqualTolerance(P(2.5, 2.0), get<ConvexHull>(chf, 1).hullCenter(), P(1e-15));
+        shouldEqualTolerance(P(2.6666666666666667, 2.0), get<ConvexHull>(chf, 1).convexityDefectCenter(), P(1e-15));
+    }
 };
 
 struct FeaturesTestSuite : public vigra::test_suite
@@ -1445,8 +1563,9 @@ struct FeaturesTestSuite : public vigra::test_suite
         add(testCase(&AccumulatorTest::testMerge));
         add(testCase(&AccumulatorTest::testCoordAccess));
         add(testCase(&AccumulatorTest::testHistogram));
-        add(testCase(&AccumulatorTest::testLabelDispatch));
+        add(testCase(&AccumulatorTest::testRegionAccumulators));
         add(testCase(&AccumulatorTest::testIndexSpecifiers));
+        add(testCase(&AccumulatorTest::testConvexHullFeatures));
     }
 };
 
diff --git a/test/pixeltypes/test.cxx b/test/pixeltypes/test.cxx
index b7cfce4..4d3057b 100755
--- a/test/pixeltypes/test.cxx
+++ b/test/pixeltypes/test.cxx
@@ -43,6 +43,7 @@
 #include "vigra/rgbvalue.hxx"
 #include "vigra/diff2d.hxx"
 #include "vigra/box.hxx"
+#include "vigra/algorithm.hxx"
 
 using namespace vigra;
 
@@ -137,7 +138,7 @@ struct TinyVectorTest
         should(equalIter(bv3.begin(), bv3.end(), bv4.begin()));
         should(equalVector(bv3, bv4));
 
-        BV bv5(bv3.begin(), BV::ReverseCopy);
+        BV bv5(bv3.begin(), ReverseCopy);
         should(equalIter(bv3.begin(), bv3.end(),
                          std::reverse_iterator<typename BV::iterator>(bv5.end())));
 
@@ -179,9 +180,29 @@ struct TinyVectorTest
             should(!iv.any());
         }
 
+        IV seq = IV::linearSequence(), seq_ref;
+        linearSequence(seq_ref.begin(), seq_ref.end());
+        shouldEqual(seq, seq_ref);
+
+        seq = IV::linearSequence(2);
+        linearSequence(seq_ref.begin(), seq_ref.end(), 2);
+        shouldEqual(seq, seq_ref);
+
+        seq = IV::linearSequence(20, -1);
+        linearSequence(seq_ref.begin(), seq_ref.end(), 20, -1);
+        shouldEqual(seq, seq_ref);
+
         IV r = reverse(iv3);
         for(int k=0; k<SIZE; ++k)
             shouldEqual(iv3[k], r[SIZE-1-k]);
+
+        shouldEqual(transpose(r, IV::linearSequence(SIZE-1, -1)), iv3);
+
+        typedef TinyVector<typename FV::value_type, SIZE-1> FV1;
+        FV1 fv10(fv3.begin());
+        shouldEqual(fv10, fv3.dropIndex(SIZE-1));
+        FV1 fv11(fv3.begin()+1);
+        shouldEqual(fv11, fv3.dropIndex(0));
     }
 
     void testComparison()
@@ -200,6 +221,19 @@ struct TinyVectorTest
         should(iv3 != fv3);
         should(fv3 != bv3);
 
+        should(bv0 < bv1);
+
+        should(allLess(bv0, bv1));
+        should(!allLess(bv1, bv3));
+        should(allGreater(bv1, bv0));
+        should(!allGreater(bv3, bv1));
+        should(allLessEqual(bv0, bv1));
+        should(allLessEqual(bv1, bv3));
+        should(!allLessEqual(bv3, bv1));
+        should(allGreaterEqual(bv1, bv0));
+        should(allGreaterEqual(bv3, bv1));
+        should(!allGreaterEqual(bv1, bv3));
+
         should(closeAtTolerance(fv3, fv3));
         
         should(!bv0.any() && !bv0.all() && bv1.any() && bv1.all());
@@ -252,6 +286,17 @@ struct TinyVectorTest
         ivi3 = -round(fvm3);
         should(equalIter(ivi3.begin(), ivi3.end(), ri));
 
+        shouldEqual(clipLower(iv3), iv3);
+        shouldEqual(clipLower(iv3, 11), IV(11));
+        shouldEqual(clipUpper(iv3, 0), IV(0));
+        shouldEqual(clipUpper(iv3, 11), iv3);
+        shouldEqual(clip(iv3, 0, 11), iv3);
+        shouldEqual(clip(iv3, 11, 12), IV(11));
+        shouldEqual(clip(iv3, -1, 0), IV(0));
+        shouldEqual(clip(iv3, IV(0), IV(11)), iv3);
+        shouldEqual(clip(iv3, IV(11), IV(12)), IV(11));
+        shouldEqual(clip(iv3, IV(-1), IV(0)), IV(0));
+
         should(bv1.squaredMagnitude() == SIZE);
         should(iv1.squaredMagnitude() == SIZE);
         should(fv1.squaredMagnitude() == (float)SIZE);
@@ -295,6 +340,10 @@ struct TinyVectorTest
         should(dot(bv, bv) == expectedSM2);
         should(bv.squaredMagnitude() == expectedSM2);
 
+        should(equalVector(bv0 + 1.0, fv1));
+        should(equalVector(1.0 + bv0, fv1));
+        should(equalVector(bv1 - 1.0, fv0));
+        should(equalVector(1.0 - bv1, fv0));
         should(equalVector(bv3 - iv3, bv0));
         should(equalVector(fv3 - fv3, fv0));
         BV bvp = (bv3 + bv3)*0.5;
@@ -319,7 +368,11 @@ struct TinyVectorTest
         should(equalIter(fvp.begin(), fvp.end(), fp));
         fvp = fv3 / 2.0;
         float fp1[] = {0.6f, 1.2f, 1.8f, 2.4f, 4.05f, 4.85f};
-        
+        should(equalIter(fvp.begin(), fvp.end(), fp1));
+        shouldEqual(2.0 / fv1, 2.0 * fv1);        
+        float fp2[] = {1.0f, 0.5f, 0.25f, 0.2f, 0.125f, 0.1f};
+        fvp = 1.0 / bv3;
+        should(equalIter(fvp.begin(), fvp.end(), fp2));
 
         int ivsq[] = { 1, 4, 16, 25, 64, 100 };
         ivp = iv3*iv3;
diff --git a/test/polygon/CMakeLists.txt b/test/polygon/CMakeLists.txt
new file mode 100644
index 0000000..b24ff35
--- /dev/null
+++ b/test/polygon/CMakeLists.txt
@@ -0,0 +1,2 @@
+VIGRA_ADD_TEST(test_polygon test.cxx LIBRARIES vigraimpex)
+
diff --git a/test/math/convex_hull_test.hxx b/test/polygon/convex_hull_test.hxx
similarity index 99%
rename from test/math/convex_hull_test.hxx
rename to test/polygon/convex_hull_test.hxx
index 3c6a869..a2cd5bf 100644
--- a/test/math/convex_hull_test.hxx
+++ b/test/polygon/convex_hull_test.hxx
@@ -41,23 +41,23 @@
 typedef vigra::TinyVector<double, 2> P;
 
 P convexHullReference[] = {
-    P(124.0,  23.0),
-    P(125.0,  20.0),
-    P(127.0,  17.0),
+    P(141.0,   5.0),
     P(128.0,  16.0),
-    P(141.0,   5.0), 
-    P(159.0,   5.0),
-    P(176.0,  11.0),
-    P(186.0,  15.0),
-    P(251.0,  47.0),
-    P(254.0,  49.0),
-    P(293.0,  84.0),
-    P(297.0,  88.0),
-    P(455.0, 510.0),
-    P(455.0, 511.0),
-    P(188.0, 511.0),
+    P(127.0,  17.0),
+    P(125.0,  20.0),
+    P(124.0,  23.0),
     P(178.0, 476.0),
-    P(124.0,  23.0)
+    P(188.0, 511.0),
+    P(455.0, 511.0),
+    P(455.0, 510.0),
+    P(297.0,  88.0),
+    P(293.0,  84.0),
+    P(254.0,  49.0),
+    P(251.0,  47.0),
+    P(186.0,  15.0),
+    P(176.0,  11.0),
+    P(159.0,   5.0),
+    P(141.0,   5.0)
 };
 
 P convexHullInputs[] = {
diff --git a/test/polygon/test.cxx b/test/polygon/test.cxx
new file mode 100644
index 0000000..442fd0b
--- /dev/null
+++ b/test/polygon/test.cxx
@@ -0,0 +1,902 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 1998-2014 by                                 */
+/*               Ullrich Koethe,                                        */
+/*               Esteban Pardo                                          */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#include <vigra/unittest.hxx>
+#include <vigra/multi_array.hxx>
+#include <vigra/polygon.hxx>
+#include "convex_hull_test.hxx"
+
+
+using namespace vigra;
+
+struct PolygonTest
+{
+
+    MultiArray<2, int> mask;
+    
+    PolygonTest()
+    : mask(Shape2(6, 6))
+    {
+        mask(1, 1) = 1;
+        mask(2, 1) = 1;
+        mask(2, 2) = 1;
+        mask(2, 3) = 1;
+        mask(1, 3) = 1;
+        mask(3, 1) = 1;
+        mask(3, 3) = 1;
+        mask(4, 1) = 1;
+        mask(4, 3) = 1;
+    }
+
+    void print(MultiArray<2, int> const & a)
+    {
+        for(MultiArray<2, int>::const_iterator i = a.begin(); i != a.end(); ++i)
+        {
+            std::cerr << (char)*i;
+            if(i.point()[0] == a.shape(0)-1)
+                std::cerr << "\n";
+        }
+    }
+
+    void testBasics()
+    {
+        typedef TinyVector<double, 2> P;
+        typedef vigra::Polygon<P> Poly;
+
+        P points[] = { P(1.0,1.0), P(4.0, 1.0), P(4.0, 5.0) };
+        Poly p(points, points+3);
+
+        shouldEqual(p.size(), 3);
+        shouldEqualSequence(p.begin(), p.end(), points);
+        shouldEqual(p.length(), 7.0);
+        shouldEqual(p.partialArea(), -6.5);
+        should(!p.closed());
+        shouldEqual(p.interpolate(0, 0.0), P(1.0, 1.0));
+        shouldEqual(p.interpolate(1, 0.25), P(4.0, 2.0));
+        shouldEqual(p.interpolate(1, 0.5), P(4.0, 3.0));
+        shouldEqual(p.interpolate(1, 0.75), P(4.0, 4.0));
+        shouldEqual(p.interpolate(1, 1.0), P(4.0, 5.0));
+        shouldEqual(p.nearestPoint(P(0.0, 0.0)), P(1.0, 1.0));
+        shouldEqualTolerance(p.nearestPoint(P(2.0, 0.0)), P(2.0, 1.0), P(1e-15));
+        shouldEqualTolerance(p.nearestPoint(P(3.5, 2.0)), P(4.0, 2.0), P(1e-15));
+        shouldEqual(p.arcLengthQuantile(0.0), 0.0);
+        shouldEqual(p.arcLengthQuantile(1.0), 2.0);
+        shouldEqual(p.arcLengthQuantile(0.5), 1.125);
+
+        Poly p2(2);
+        p2.setPoint(0, P(4.0, 5.0));
+        p2.setPoint(1, P(1.0, 1.0));
+        shouldEqual(p2.size(), 2);
+        shouldEqual(p2.length(), 5.0);
+        shouldEqual(p2.partialArea(), 0.5);
+        should(!p2.closed());
+
+        p.extend(p2);
+        shouldEqual(p.size(), 4);
+        should(p.closed());
+        shouldEqual(p.length(), 12.0);
+        shouldEqual(p.partialArea(), -6.0);
+        shouldEqual(p.area(), 6.0);
+        ArrayVector<double> arcLengthList;
+        p.arcLengthList(arcLengthList);
+        shouldEqual(arcLengthList.size(), 4);
+        double arcLengthRef[] = { 0.0, 3.0, 7.0, 12.0 };
+        shouldEqualSequence(arcLengthList.begin(), arcLengthList.end(), arcLengthRef);
+
+        p.reverse();
+        shouldEqual(p.size(), 4);
+        P ref[] = { P(1.0,1.0), P(4.0, 5.0), P(4.0, 1.0), P(1.0, 1.0) };
+        shouldEqualSequence(p.cbegin(), p.cend(), ref);
+        should(p.closed());
+        shouldEqual(p.length(), 12.0);
+        shouldEqual(p.partialArea(), 6.0);
+        shouldEqual(p.area(), 6.0);
+
+        p2.push_back(P(4.0, 5.0));
+        p2.insert(p2.begin()+2, p.cbegin()+2, p.cbegin()+3);
+        shouldEqual(p2.size(), 4);
+        should(p2.closed());
+        shouldEqual(p2.length(), 12.0);
+        shouldEqual(p2.partialArea(), -6.0);
+        shouldEqual(p2.area(), 6.0);
+
+        p.setPoint(1, P(5.0, 4.0));
+        p.setPoint(2, P(1.0, 4.0));
+        shouldEqual(p.size(), 4);
+        P ref1[] = { P(1.0,1.0), P(5.0, 4.0), P(1.0, 4.0), P(1.0, 1.0) };
+        shouldEqualSequence(p.cbegin(), p.cend(), ref1);
+        should(p.closed());
+        shouldEqual(p.length(), 12.0);
+        shouldEqual(p.partialArea(), -6.0);
+        shouldEqual(p.area(), 6.0);
+
+        p.insert(p.begin()+1, P(5.0, 1.0));
+        shouldEqual(p.size(), 5);
+        P ref2[] = { P(1.0,1.0), P(5.0, 1.0), P(5.0, 4.0), P(1.0, 4.0), P(1.0, 1.0) };
+        shouldEqualSequence(p.cbegin(), p.cend(), ref2);
+        should(p.closed());
+        shouldEqual(p.length(), 14.0);
+        shouldEqual(p.partialArea(), -12.0);
+        shouldEqual(p.area(), 12.0);
+        shouldEqual(centroid(p), P(3.0, 2.5));
+
+        p.erase(p.begin()+3);
+        shouldEqual(p.size(), 4);
+        P ref3[] = { P(1.0,1.0), P(5.0, 1.0), P(5.0, 4.0), P(1.0, 1.0) };
+        shouldEqualSequence(p.cbegin(), p.cend(), ref3);
+        should(p.closed());
+        shouldEqual(p.length(), 12.0);
+        shouldEqual(p.partialArea(), -6.0);
+        shouldEqual(p.area(), 6.0);
+
+        p2 = p;
+        should(p2 == p);
+        shouldEqualSequence(p2.cbegin(), p2.cend(), round(p2 + P(0.3, -0.2)).begin());
+        shouldEqualSequence(p2.cbegin(), p2.cend(), roundi(p2 + P(0.3, -0.2)).begin());
+
+        p2 *= 2.0;
+        shouldEqual(p2.size(), 4);
+        P ref4[] = { P(2.0,2.0), P(10.0, 2.0), P(10.0, 8.0), P(2.0, 2.0) };
+        shouldEqualSequence(p2.cbegin(), p2.cend(), ref4);
+        should(p2.closed());
+        shouldEqual(p2.length(), 24.0);
+        shouldEqual(p2.partialArea(), -24.0);
+        shouldEqual(p2.area(), 24.0);
+        should(p2 == p * 2.0);
+        should(p2 == 2.0 * p);
+        should(p2 / 2.0 == p);
+
+        p2 /= 2.0;
+        shouldEqual(p2.size(), 4);
+        shouldEqualSequence(p2.cbegin(), p2.cend(), ref3);
+        should(p2.closed());
+        shouldEqual(p2.length(), 12.0);
+        shouldEqual(p2.partialArea(), -6.0);
+        shouldEqual(p2.area(), 6.0);
+
+        p2 += P(1.0, 2.0);
+        shouldEqual(p2.size(), 4);
+        P ref5[] = { P(2.0, 3.0), P(6.0, 3.0), P(6.0, 6.0), P(2.0, 3.0) };
+        shouldEqualSequence(p2.cbegin(), p2.cend(), ref5);
+        should(p2.closed());
+        shouldEqual(p2.length(), 12.0);
+        shouldEqual(p2.area(), 6.0);
+        should(p2 == p + P(1.0, 2.0));
+        should(p2 == P(1.0, 2.0) + p);
+        should(p2 - P(1.0, 2.0) == p);
+
+        p2 -= P(2.0, 1.0);
+        shouldEqual(p2.size(), 4);
+        P ref6[] = { P(0.0, 2.0), P(4.0, 2.0), P(4.0, 5.0), P(0.0, 2.0) };
+        shouldEqualSequence(p2.cbegin(), p2.cend(), ref6);
+        should(p2.closed());
+        shouldEqual(p2.length(), 12.0);
+        shouldEqual(p2.area(), 6.0);
+
+        p2 = -p2;
+        shouldEqual(p2.size(), 4);
+        P ref7[] = { P(0.0, -2.0), P(-4.0, -2.0), P(-4.0, -5.0), P(0.0, -2.0) };
+        shouldEqualSequence(p2.cbegin(), p2.cend(), ref7);
+
+        p2 = transpose(-p2);
+        shouldEqual(p2.size(), 4);
+        P ref8[] = { P(2.0, 0.0), P(2.0, 4.0), P(5.0, 4.0), P(2.0, 0.0) };
+        shouldEqualSequence(p2.cbegin(), p2.cend(), ref8);
+
+        p2 = p;
+        shouldEqual(p2.size(), 4);
+        shouldEqualSequence(p2.cbegin(), p2.cend(), ref3);
+        p2.erase(p2.begin(), p2.begin()+2);
+        shouldEqual(p2.size(), 2);
+        shouldEqualSequence(p2.cbegin(), p2.cend(), ref3+2);
+        shouldEqual(p2.length(), 5.0);
+        shouldEqual(p2.partialArea(), -0.5);
+
+        p2 = p.split(3);
+        shouldEqual(p.size(), 3);
+        shouldEqualSequence(p.cbegin(), p.cend(), ref3);
+        should(!p.closed());
+        shouldEqual(p.length(), 7.0);
+        shouldEqual(p.partialArea(), -5.5);
+        shouldEqual(p2.size(), 1);
+        shouldEqual(p2[0], ref3[3]);
+        should(p2.closed());
+    }
+
+    #define CHECK_IS_INSIDE(img, poly) \
+            for(MultiArray<2, int>::iterator i=img.begin(); i != img.end(); ++i) \
+                if(*i == ' ') \
+                    shouldMessage(!poly.contains(i.point()), std::string("contains failed at ") << i.point()); \
+                else \
+                    shouldMessage(poly.contains(i.point()), std::string("contains failed at ") << i.point())
+
+    void testFillAndContains()
+    {
+        typedef TinyVector<double, 2> P;
+        typedef vigra::Polygon<P> Poly;
+
+        {
+            // triangle in general position
+            P p[] = { P(0.5, 0.5), P(1.5, 4.1), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+4);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // triangle, lower knot on scanline
+            P p[] = { P(0.5, 0.5), P(1.5, 4.0), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+4);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // triangle, lower knot on pixel
+            P p[] = { P(0.5, 0.5), P(1.0, 4.0), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+4);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " *        "
+                " *        "
+                " *        "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // triangle, all knots on scanlines
+            P p[] = { P(0.5, 1.0), P(1.5, 4.0), P(2.5, 1.0), P(0.5, 1.0) };
+            Poly poly(p, p+4);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // triangle, all knots on scanlines
+            P p[] = { P(0.5, 1.0), P(1.5, 4.0), P(2.5, 1.0), P(2.2, 1.0), P(0.5, 1.0) };
+            Poly poly(p, p+5);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // quadrilateral in general position
+            P p[] = { P(0.5, 0.5), P(0.9, 2.5), P(1.5, 4.1), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+5);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // quadrilateral, one knot on scanline
+            P p[] = { P(0.5, 0.5), P(0.9, 2.0), P(1.5, 4.1), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+5);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // quadrilateral, two knots on scanline
+            P p[] = { P(0.5, 0.5), P(0.9, 2.0), P(1.5, 4.0), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+5);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // quadrilateral, one knot on scanline, one knot on pixel
+            P p[] = { P(0.5, 0.5), P(0.9, 2.0), P(1.0, 4.0), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+5);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " *        "
+                " *        "
+                " *        "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave pentagon in general position
+            P p[] = { P(0.5, 0.5), P(0.9, 2.5), P(1.2, 2.5), P(1.5, 4.1), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+6);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave pentagon, two knots on scanline
+            P p[] = { P(0.5, 0.5), P(0.9, 2.0), P(1.2, 2.0), P(1.5, 4.1), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+6);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave pentagon, three knots on scanline
+            P p[] = { P(0.5, 0.5), P(0.9, 2.0), P(1.2, 2.0), P(1.5, 4.0), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+6);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "          "
+                "          "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave pentagon, two knots on scanline, one knot on pixel
+            P p[] = { P(0.5, 0.5), P(0.9, 2.0), P(1.2, 2.0), P(2.0, 4.0), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+6);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "  *       "
+                "  *       "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave hexagon, three knots on scanline, one knot on pixel
+            P p[] = { P(0.5, 0.5), P(0.9, 2.0), P(1.1, 2.0), P(1.3, 2.0), P(2.0, 4.0), P(2.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+7);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " **       "
+                " **       "
+                "  *       "
+                "  *       "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave pentagon in general position
+            P p[] = { P(0.5, 0.5), P(1.0, 4.1), P(2.0, 2.9), P(3.0, 4.1), P(3.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+6);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ***      "
+                " ***      "
+                " * *      "
+                " * *      "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave pentagon, one knot on scanline
+            P p[] = { P(0.5, 0.5), P(1.0, 4.1), P(1.9, 2.0), P(3.0, 4.1), P(3.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+6);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ***      "
+                " ***      "
+                " * *      "
+                " * *      "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave pentagon, one knot on pixel
+            P p[] = { P(0.5, 0.5), P(1.0, 4.1), P(2.0, 2.0), P(3.0, 4.1), P(3.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+6);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ***      "
+                " ***      "
+                " * *      "
+                " * *      "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave pentagon, three knots on pixel
+            P p[] = { P(0.5, 0.5), P(1.0, 4.0), P(2.0, 2.0), P(3.0, 4.0), P(3.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+6);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ***      "
+                " ***      "
+                " * *      "
+                " * *      "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave pentagon, all knots on pixel
+            P p[] = { P(1.0, 1.0), P(1.0, 4.0), P(2.0, 2.0), P(3.0, 4.0), P(3.0, 1.0), P(1.0, 1.0) };
+            Poly poly(p, p+6);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ***      "
+                " ***      "
+                " * *      "
+                " * *      "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave hexagon in general position
+            P p[] = { P(0.5, 0.5), P(1.0, 4.1), P(1.9, 2.9), P(2.1, 2.9), P(3.0, 4.1), P(3.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+7);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ***      "
+                " ***      "
+                " * *      "
+                " * *      "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave hexagon, two knots on scanline
+            P p[] = { P(0.5, 0.5), P(1.0, 4.1), P(1.9, 2.0), P(2.1, 2.0), P(3.0, 4.1), P(3.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+7);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ***      "
+                " ***      "
+                " * *      "
+                " * *      "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave hexagon, four knots on scanline
+            P p[] = { P(0.5, 0.5), P(1.0, 4.0), P(1.9, 2.0), P(2.1, 2.0), P(3.0, 4.0), P(3.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+7);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ***      "
+                " ***      "
+                " * *      "
+                " * *      "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave hexagon, four knots on scanline
+            P p[] = { P(0.5, 0.5), P(1.0, 4.0), P(1.9, 2.0), P(3.1, 2.0), P(4.0, 4.0), P(4.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+7);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ****     "
+                " ****     "
+                " *  *     "
+                " *  *     "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave hexagon, four knots on scanline
+            P p[] = { P(0.5, 0.5), P(1.0, 4.0), P(1.9, 2.0), P(3.1, 2.0), P(4.0, 2.0), P(4.5, 0.5), P(0.5, 0.5) };
+            Poly poly(p, p+7);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ****     "
+                " ****     "
+                " *        "
+                " *        "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave hexagon, all knots on scanline
+            P p[] = { P(0.5, 1.0), P(1.0, 4.0), P(1.9, 2.0), P(3.1, 2.0), P(4.0, 2.0), P(4.5, 1.0), P(0.5, 1.0) };
+            Poly poly(p, p+7);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ****     "
+                " ****     "
+                " *        "
+                " *        "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+        {
+            // concave heptagon, all knots on scanline
+            P p[] = { P(0.5, 1.0), P(1.0, 4.0), P(1.9, 2.0), P(3.1, 2.0), P(4.0, 2.0), P(4.5, 1.0), P(3.2, 1.0), P(0.5, 1.0) };
+            Poly poly(p, p+8);
+            MultiArray<2, int> mask(Shape2(10,6), ' ');
+            fillPolygon(poly, mask, int('*'));
+
+            std::string ref =
+                "          "
+                " ****     "
+                " ****     "
+                " *        "
+                " *        "
+                "          "
+            ;
+            shouldEqualSequence(mask.begin(), mask.end(), ref.begin());
+            CHECK_IS_INSIDE(mask, poly);
+        }
+    }
+    
+    void testExtractContour()
+    {
+        typedef TinyVector<float, 2> Point;
+
+        mask(3,0) = 1; // have the object touch the image border
+
+        TinyVector<int, 2> anchor_point(1,1);
+        vigra::Polygon<Point> contour_points;
+
+        extractContour(mask, anchor_point, contour_points);
+        
+        Point real_contour_points[] = {
+            Point(1, 0.5),
+            Point(0.5, 1),
+            Point(1, 1.5),
+            Point(1.5, 2),
+            Point(1, 2.5),
+            Point(0.5, 3),
+            Point(1, 3.5),
+            Point(2, 3.5),
+            Point(3, 3.5),
+            Point(4, 3.5),
+            Point(4.5, 3),
+            Point(4, 2.5),
+            Point(3, 2.5),
+            Point(2.5, 2),
+            Point(3, 1.5),
+            Point(4, 1.5),
+            Point(4.5, 1),
+            Point(4, 0.5),
+            Point(3.5, 0),
+            Point(3, -0.5),
+            Point(2.5, 0),
+            Point(2, 0.5),
+            Point(1, 0.5),
+        };
+
+        shouldEqual(23, contour_points.size());
+        shouldEqualSequence(contour_points.begin(), contour_points.end(), real_contour_points);
+
+        MultiArray<2, int> render(mask.shape());
+        fillPolygon(contour_points, render, 1);
+
+        shouldEqualSequence(mask.begin(), mask.end(), render.begin());
+    }
+    
+   void testConvexHull()
+    {
+        typedef TinyVector<double, 2> Point;
+        ArrayVector<Point> points, reference, hull;
+        points.push_back(Point(0.0, 0.0));
+        points.push_back(Point(2.0, 1.0));
+        points.push_back(Point(2.0, -1.0));
+        points.push_back(Point(0.0, 2.0));
+        points.push_back(Point(-2.0, 1.0));
+        points.push_back(Point(-2.0, -1.0));
+        points.push_back(Point(0.0, -2.0));
+
+        reference.push_back(Point(0.0, -2.0));
+        reference.push_back(Point(-2.0, -1.0));
+        reference.push_back(Point(-2.0, 1.0));
+        reference.push_back(Point(0.0, 2.0));
+        reference.push_back(Point(2.0, 1.0));
+        reference.push_back(Point(2.0, -1.0));
+        reference.push_back(Point(0.0, -2.0));
+        
+        vigra::convexHull(points, hull);
+
+        shouldEqual(7u, hull.size());
+        shouldEqualSequence(reference.begin(), reference.end(), hull.begin());
+
+        hull.clear();
+
+        vigra::convexHull(reference, hull);
+        
+        shouldEqual(7u, hull.size());
+        shouldEqualSequence(reference.begin(), reference.end(), hull.begin());
+        
+        typedef Point P;
+        P p[200] = { P(0.0, 0.0), P(42.0, 468.0), P(335.0, 501.0), P(170.0, 725.0), P(479.0, 359.0), 
+                  P(963.0, 465.0), P(706.0, 146.0), P(282.0, 828.0), P(962.0, 492.0), 
+                  P(996.0, 943.0), P(828.0, 437.0), P(392.0, 605.0), P(903.0, 154.0), 
+                  P(293.0, 383.0), P(422.0, 717.0), P(719.0, 896.0), P(448.0, 727.0), 
+                  P(772.0, 539.0), P(870.0, 913.0), P(668.0, 300.0), P(36.0, 895.0), 
+                  P(704.0, 812.0), P(323.0, 334.0), P(674.0, 665.0), P(142.0, 712.0), 
+                  P(254.0, 869.0), P(548.0, 645.0), P(663.0, 758.0), P(38.0, 860.0), 
+                  P(724.0, 742.0), P(530.0, 779.0), P(317.0, 36.0), P(191.0, 843.0), 
+                  P(289.0, 107.0), P(41.0, 943.0), P(265.0, 649.0), P(447.0, 806.0), 
+                  P(891.0, 730.0), P(371.0, 351.0), P(7.0, 102.0), P(394.0, 549.0), 
+                  P(630.0, 624.0), P(85.0, 955.0), P(757.0, 841.0), P(967.0, 377.0), 
+                  P(932.0, 309.0), P(945.0, 440.0), P(627.0, 324.0), P(538.0, 539.0), 
+                  P(119.0, 83.0), P(930.0, 542.0), P(834.0, 116.0), P(640.0, 659.0), 
+                  P(705.0, 931.0), P(978.0, 307.0), P(674.0, 387.0), P(22.0, 746.0), 
+                  P(925.0, 73.0), P(271.0, 830.0), P(778.0, 574.0), P(98.0, 513.0), 
+                  P(987.0, 291.0), P(162.0, 637.0), P(356.0, 768.0), P(656.0, 575.0), 
+                  P(32.0, 53.0), P(351.0, 151.0), P(942.0, 725.0), P(967.0, 431.0), 
+                  P(108.0, 192.0), P(8.0, 338.0), P(458.0, 288.0), P(754.0, 384.0), 
+                  P(946.0, 910.0), P(210.0, 759.0), P(222.0, 589.0), P(423.0, 947.0), 
+                  P(507.0, 31.0), P(414.0, 169.0), P(901.0, 592.0), P(763.0, 656.0), 
+                  P(411.0, 360.0), P(625.0, 538.0), P(549.0, 484.0), P(596.0, 42.0), 
+                  P(603.0, 351.0), P(292.0, 837.0), P(375.0, 21.0), P(597.0, 22.0), 
+                  P(349.0, 200.0), P(669.0, 485.0), P(282.0, 735.0), P(54.0, 1000.0), 
+                  P(419.0, 939.0), P(901.0, 789.0), P(128.0, 468.0), P(729.0, 894.0), 
+                  P(649.0, 484.0), P(808.0, 422.0), P(311.0, 618.0), P(814.0, 515.0), 
+                  P(310.0, 617.0), P(936.0, 452.0), P(601.0, 250.0), P(520.0, 557.0), 
+                  P(799.0, 304.0), P(225.0, 9.0), P(845.0, 610.0), P(990.0, 703.0), 
+                  P(196.0, 486.0), P(94.0, 344.0), P(524.0, 588.0), P(315.0, 504.0), 
+                  P(449.0, 201.0), P(459.0, 619.0), P(581.0, 797.0), P(799.0, 282.0), 
+                  P(590.0, 799.0), P(10.0, 158.0), P(473.0, 623.0), P(539.0, 293.0), 
+                  P(39.0, 180.0), P(191.0, 658.0), P(959.0, 192.0), P(816.0, 889.0), 
+                  P(157.0, 512.0), P(203.0, 635.0), P(273.0, 56.0), P(329.0, 647.0), 
+                  P(363.0, 887.0), P(876.0, 434.0), P(870.0, 143.0), P(845.0, 417.0), 
+                  P(882.0, 999.0), P(323.0, 652.0), P(22.0, 700.0), P(558.0, 477.0), 
+                  P(893.0, 390.0), P(76.0, 713.0), P(601.0, 511.0), P(4.0, 870.0), 
+                  P(862.0, 689.0), P(402.0, 790.0), P(256.0, 424.0), P(3.0, 586.0), 
+                  P(183.0, 286.0), P(89.0, 427.0), P(618.0, 758.0), P(833.0, 933.0), 
+                  P(170.0, 155.0), P(722.0, 190.0), P(977.0, 330.0), P(369.0, 693.0), 
+                  P(426.0, 556.0), P(435.0, 550.0), P(442.0, 513.0), P(146.0, 61.0), 
+                  P(719.0, 754.0), P(140.0, 424.0), P(280.0, 997.0), P(688.0, 530.0), 
+                  P(550.0, 438.0), P(867.0, 950.0), P(194.0, 196.0), P(298.0, 417.0), 
+                  P(287.0, 106.0), P(489.0, 283.0), P(456.0, 735.0), P(115.0, 702.0), 
+                  P(317.0, 672.0), P(787.0, 264.0), P(314.0, 356.0), P(186.0, 54.0), 
+                  P(913.0, 809.0), P(833.0, 946.0), P(314.0, 757.0), P(322.0, 559.0), 
+                  P(647.0, 983.0), P(482.0, 145.0), P(197.0, 223.0), P(130.0, 162.0), 
+                  P(536.0, 451.0), P(174.0, 467.0), P(45.0, 660.0), P(293.0, 440.0), 
+                  P(254.0, 25.0), P(155.0, 511.0), P(746.0, 650.0), P(187.0, 314.0), 
+                  P(475.0, 23.0), P(169.0, 19.0), P(788.0, 906.0), P(959.0, 392.0), 
+                  P(203.0, 626.0), P(478.0, 415.0), P(315.0, 825.0), P(335.0, 875.0), 
+                  P(373.0, 160.0), P(834.0, 71.0), P(488.0, 298.0) };
+                  
+        P ref[10] = { P(0.0, 0.0), 
+                      P(4.0, 870.0),
+                      P(54.0, 1000.0),
+                      P(882.0, 999.0),
+                      P(996.0, 943.0),
+                      P(987.0, 291.0),
+                      P(959.0, 192.0), 
+                      P(925.0, 73.0),
+                      P(597.0, 22.0), 
+                      P(0.0, 0.0) };
+
+        points = vigra::ArrayVector<Point>(p, p+200);
+        hull.clear();
+        
+        vigra::convexHull(points, hull);
+        
+        shouldEqual(10u, hull.size());
+        shouldEqualSequence(ref, ref+10, hull.begin());
+
+        int size = sizeof(convexHullInputs) / sizeof(Point);
+        points = vigra::ArrayVector<Point>(convexHullInputs, convexHullInputs+size);
+        hull.clear();
+        
+        vigra::convexHull(points, hull);
+        
+        shouldEqual(17u, hull.size());
+        shouldEqualSequence(convexHullReference, convexHullReference+17, hull.begin());
+    }
+};
+
+struct PolygonTestSuite : public vigra::test_suite
+{
+    PolygonTestSuite()
+        : vigra::test_suite("PolygonTestSuite")
+    {
+        add(testCase(&PolygonTest::testBasics));
+        add(testCase(&PolygonTest::testFillAndContains));
+        add(testCase(&PolygonTest::testExtractContour));
+        add(testCase(&PolygonTest::testConvexHull));
+    }
+};
+
+int main(int argc, char** argv)
+{
+    PolygonTestSuite test;
+    const int failed = test.run(vigra::testsToBeExecuted(argc, argv));
+    std::cerr << test.report() << std::endl;
+
+    return failed != 0;
+}
+
diff --git a/test/registration/CMakeLists.txt b/test/registration/CMakeLists.txt
new file mode 100644
index 0000000..a89495b
--- /dev/null
+++ b/test/registration/CMakeLists.txt
@@ -0,0 +1,14 @@
+VIGRA_CONFIGURE_THREADING()
+
+if(FFTW3_FOUND)
+    INCLUDE_DIRECTORIES(${FFTW3_INCLUDE_DIR})
+    ADD_DEFINITIONS(-DHasFFTW3)
+
+    VIGRA_ADD_TEST(test_registration test.cxx LIBRARIES ${FFTW3_LIBRARIES} ${FFTW3F_LIBRARIES} ${THREADING_LIBRARIES} vigraimpex)
+else()
+    MESSAGE(STATUS "** WARNING: tests of correlation-based registration will not be executed")
+
+    VIGRA_ADD_TEST(test_registration test.cxx LIBRARIES ${THREADING_LIBRARIES} vigraimpex)
+endif()
+
+VIGRA_COPY_TEST_DATA(nuernberg-1991.png nuernberg-1995.png)
diff --git a/test/registration/nuernberg-1991.png b/test/registration/nuernberg-1991.png
new file mode 100644
index 0000000..a36eec2
Binary files /dev/null and b/test/registration/nuernberg-1991.png differ
diff --git a/test/registration/nuernberg-1995.png b/test/registration/nuernberg-1995.png
new file mode 100644
index 0000000..131e466
Binary files /dev/null and b/test/registration/nuernberg-1995.png differ
diff --git a/test/registration/test.cxx b/test/registration/test.cxx
new file mode 100755
index 0000000..e687f7c
--- /dev/null
+++ b/test/registration/test.cxx
@@ -0,0 +1,839 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2014 by Benjamin Seppke                    */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#include <iostream>
+
+#include <vigra/unittest.hxx>
+#include <vigra/stdimage.hxx>
+#include <vigra/convolution.hxx>
+#include <vigra/impex.hxx>
+
+#ifdef HasFFTW3
+# include <vigra/affine_registration_fft.hxx>
+#endif
+#include <vigra/projective_registration.hxx>
+#include <vigra/polynomial_registration.hxx>
+#include <vigra/rbf_registration.hxx>
+
+using namespace vigra;
+
+static int pointdata[] = {
+/*  x_1     y_1     x_2     y_2 */
+    362  ,  379  ,  783  ,  658,
+    362  ,  250  ,  786  ,  582,
+    378  ,  250  ,  797  ,  581,
+    470  ,  250  ,  859  ,  581,
+    504  ,  251  ,  879  ,  583,
+    674  ,  249  ,  991  ,  582,
+    858  ,  255  , 1121  ,  581,
+    857  ,  284  , 1121  ,  605,
+    913  ,  285  , 1161  ,  606,
+    913  ,  311  , 1161  ,  620,
+    913  ,  376  , 1159  ,  657,
+    824  ,  376  , 1093  ,  657,
+    785  ,  377  , 1067  ,  657,
+    646  ,  377  ,  972  ,  658,
+    535  ,  379  ,  896  ,  659,
+    535  ,  393  ,  896  ,  668,
+    377  ,  392  ,  793  ,  667,
+    377  ,  367  ,  793  ,  655,
+    535  ,  367  ,  896  ,  655,
+    377  ,  334  ,  794  ,  638,
+    377  ,  281  ,  796  ,  607,
+    504  ,  281  ,  878  ,  607,
+    503  ,  334  ,  877  ,  638,
+    674  ,  277  ,  991  ,  602,
+    754  ,  285  , 1049  ,  611,
+    672  ,  365  ,  990  ,  654,
+    659  ,  352  ,  981  ,  648,
+    659  ,  339  ,  981  ,  642,
+    654  ,  339  ,  978  ,  642,
+    654  ,  352  ,  978  ,  648,
+    738  ,  353  , 1036  ,  645,
+    790  ,  363  , 1071  ,  648,
+    774  ,  365  , 1060  ,  651,
+    806  ,  364  , 1081  ,  649,
+    807  ,  316  , 1083  ,  623,
+    790  ,  316  , 1071  ,  623,
+    790  ,  330  , 1071  ,  631,
+    806  ,  331  , 1081  ,  631,
+    822  ,  350  , 1093  ,  644,
+    835  ,  350  , 1102  ,  644,
+    835  ,  364  , 1102  ,  651,
+    902  ,  364  , 1152  ,  651,
+    902  ,  350  , 1152  ,  643,
+    889  ,  350  , 1144  ,  643,
+    618  ,  103  ,  960  ,  448,
+    505  ,  104  ,  883  ,  448,
+    505  ,   53  ,  883  ,  392,
+    452  ,   10  ,  853  ,  339,
+    273  ,   10  ,  732  ,  340,
+    269  ,  212  ,  724  ,  545,
+    503  ,  215  ,  879  ,  545,
+    271  ,   83  ,  728  ,  428,
+    504  ,   84  ,  883  ,  428,
+     17  ,  424  ,  558  ,  681,
+     19  ,  378  ,  559  ,  662,
+    155  ,  381  ,  645  ,  663,
+    174  ,  382  ,  659  ,  663,
+    317  ,  385  ,  750  ,  663,
+    317  ,  430  ,  750  ,  682,
+    174  ,  428  ,  658  ,  682,
+    154  ,  427  ,  644  ,  682,
+    758  ,  255  , 1052  ,  582,
+    461  ,  368  ,  848  ,  656,
+    461  ,  392  ,  848  ,  668,
+    461  ,  487  ,  848  ,  702,
+    540  ,  492  ,  897  ,  704
+};
+
+static int point_count = 66;
+static int pointdata_size = point_count*4;
+static double test_epsilon = 1.0e-5;
+static double rbf_test_epsilon = 1.0e-2;
+
+static std::vector<TinyVector<double,2> > srcPoints()
+{
+    std::vector<TinyVector<double,2> >  result(point_count);
+
+    for (int i=0; i<pointdata_size; i+=4)
+    {
+        result[i/4][0] = pointdata[i  ];
+        result[i/4][1] = pointdata[i+1];
+    }
+
+    return result;
+}
+
+static std::vector<TinyVector<double,2> > destPoints()
+{
+    std::vector<TinyVector<double,2> >  result(point_count);
+
+    for (int i=0; i<pointdata_size; i+=4)
+    {
+        result[i/4][0] = pointdata[i+2];
+        result[i/4][1] = pointdata[i+3];
+    }
+
+    return result;
+}
+
+void printMatrix(const Matrix<double> & m)
+{
+    for (int i=0; i<m.rowCount(); ++i)
+    {
+        for (int j=0; j<m.columnCount(); ++j)
+        {
+            printf("m(%d,%d) = %10.15f;\n", i , j , m(i,j));
+        }
+    }
+}
+
+void shouldEqualToleranceMatrices(const Matrix<double> & m1, const Matrix<double> & m2, double eps=test_epsilon)
+{
+    should(m1.rowCount() == m2.rowCount());
+    should(m1.columnCount() == m2.columnCount());
+
+    for (int i=0; i<m1.rowCount(); ++i)
+    {
+        for (int j=0; j<m1.columnCount(); ++j)
+        {
+            shouldEqualTolerance(m1(i,j), m2(i,j), eps);
+        }
+    }
+}
+
+#ifdef HasFFTW3
+struct EstimateGlobalRotationTranslationTest
+{
+
+    unsigned int size;
+    unsigned int fill_size_h;
+    unsigned int fill_size_v;
+
+    BImage s_img;
+    BImage d_img;
+
+    EstimateGlobalRotationTranslationTest()
+    : size(200),
+      fill_size_h(20),
+      fill_size_v(50)
+    {
+        s_img.resize(size,size);
+        d_img.resize(size,size);
+
+        for(MultiArrayIndex y=(size-fill_size_v)/2; y<(MultiArrayIndex)(size+fill_size_v)/2; ++y)
+            for(MultiArrayIndex x=(size-fill_size_h)/2; x<(MultiArrayIndex)(size+fill_size_h)/2; ++x)
+                s_img(x,y) = 255;
+
+        gaussianSmoothing(srcImageRange(s_img),destImage(s_img), 1.0);
+    }
+    void testInit()
+    {
+        TinyVector<double,2> trans(-25,30);
+        double theta = 24.75;
+
+        Matrix<double> t_m = translationMatrix2D(trans);
+        Matrix<double> r_m = rotationMatrix2DDegrees(theta, TinyVector<double,2>(size,size)/2.0);
+
+        //Normaly, we would write t*r. since the matrix is reversed to transform I2 based on tranformed I1,
+        // we have to change our point of view and reverse the order here to.
+        Matrix<double> known_transformation =  r_m * t_m;
+        std::cerr << "Known transformation: " << known_transformation << "\n";
+
+        Matrix<double> estimated_transformation;
+
+        affineWarpImage(SplineImageView<2,double>(srcImageRange(s_img)), destImageRange(d_img), known_transformation);
+
+        exportImage(srcImageRange(s_img), ImageExportInfo("img_quad_1.png"));
+        exportImage(srcImageRange(d_img), ImageExportInfo("img_quad_2.png"));
+
+        double corr_rot, corr_trans;
+
+        estimateGlobalRotationTranslation(srcImageRange(s_img),
+                                          destImageRange(d_img),
+                                          estimated_transformation,
+                                          corr_rot,
+                                          corr_trans);
+
+        std::cerr << "Estimated transformation: \n" << estimated_transformation << "(rot-certainty: " << corr_rot << ", trans-certainty: " << corr_trans << ")\n\n\n";
+
+        d_img=0;
+        affineWarpImage(SplineImageView<2,double>(srcImageRange(s_img)), destImageRange(d_img), estimated_transformation);
+        exportImage(srcImageRange(d_img), ImageExportInfo("img_quad_corr_1.png"));
+
+        shouldEqualToleranceMatrices(known_transformation, estimated_transformation, 0.1);
+        should(corr_rot   > 0.95);
+        should(corr_trans > 0.99);
+
+    }
+};
+struct EstimateGlobalRotationTranslationRealImageTest
+{
+    BImage s_img;
+    BImage d_img;
+
+    double rotation;
+    TinyVector<double,2> translation;
+
+    Diff2D border;
+
+    EstimateGlobalRotationTranslationRealImageTest()
+    : rotation(24.25),
+      translation(10,-30),
+      border(400,200)
+    {
+        ImageImportInfo info1("nuernberg-1995.png");
+        s_img.resize(info1.width(), info1.height());
+        d_img.resize(info1.width(), info1.height());
+        importImage(info1, destImage(s_img));
+    }
+
+    void testInit()
+    {
+        Matrix<double> r_m = rotationMatrix2DDegrees(rotation, TinyVector<double,2>(s_img.width(), s_img.height())/2.0);
+        Matrix<double> t_m = translationMatrix2D(translation);
+
+        //Normaly, we would write t*r. since the matrix is reversed to transform I2 based on transformed I1,
+        // we have to change our point of view and reverse the order here to.
+        Matrix<double> known_transformation =  r_m * t_m;
+        std::cerr << "Known transformation: \n" << known_transformation << "\n";
+
+        affineWarpImage(SplineImageView<2,double>(srcImageRange(s_img)), destImageRange(d_img), known_transformation);
+
+        exportImage(srcIterRange(s_img.upperLeft()+border, s_img.lowerRight()-border, s_img.accessor()),
+                           ImageExportInfo("img_nb_1.png"));
+        exportImage(srcIterRange(d_img.upperLeft()+border, d_img.lowerRight()-border, d_img.accessor()),
+                           ImageExportInfo("img_nb_2.png"));
+
+        Matrix<double> estimated_transformation;
+
+        double corr_rot, corr_trans;
+
+
+        estimateGlobalRotationTranslation(srcImageRange(s_img),
+                                          srcImageRange(d_img),
+                                          estimated_transformation,
+                                          corr_rot,
+                                          corr_trans,
+                                          border);
+
+        std::cerr << "Estimated transformation: \n" << estimated_transformation << "(rot-certainty: " << corr_rot << ", trans-certainty: " << corr_trans << ")\n\n\n";
+
+        d_img=0;
+        affineWarpImage(SplineImageView<2,double>(srcImageRange(s_img)),
+                        destImageRange(d_img),
+                        estimated_transformation);
+        exportImage(srcIterRange(d_img.upperLeft()+border, d_img.lowerRight()-border, d_img.accessor()),
+                    ImageExportInfo("img_nb_corr_1.png"));
+
+        shouldEqualToleranceMatrices(known_transformation, estimated_transformation, 0.1);
+        should(corr_rot   > 0.85);
+        should(corr_trans > 0.95);
+    }
+};
+
+struct EstimateGlobalRotationTranslationTestSuite
+: public test_suite
+{
+    EstimateGlobalRotationTranslationTestSuite()
+    : test_suite("EstimateGlobalRotationTranslationTestSuite")
+    {
+        add( testCase( &EstimateGlobalRotationTranslationTest::testInit));
+        add( testCase( &EstimateGlobalRotationTranslationRealImageTest::testInit));
+    }
+};
+#endif
+
+struct ProjectiveIdentityTest
+{
+    std::vector<TinyVector<double,2> > s_points;
+
+    ProjectiveIdentityTest()
+    : s_points(srcPoints())
+    {
+    }
+
+    void testInit()
+    {
+        /**
+         * First test: If point sets are equal -> identity matrix should be the result!
+         */
+        Matrix<double> identity = projectiveMatrix2DFromCorrespondingPoints(s_points.begin(), s_points.end(), s_points.begin());
+
+        shouldEqualToleranceMatrices(identity, linalg::identityMatrix<double>(3), test_epsilon);
+    }
+
+};
+
+struct ProjectiveRegistrationTest
+{
+    BImage s_img;
+    BImage d_img;
+
+    std::vector<TinyVector<double,2> > s_points;
+    std::vector<TinyVector<double,2> > d_points;
+
+    ProjectiveRegistrationTest()
+    : s_points(srcPoints()),
+      d_points(destPoints())
+    {
+        ImageImportInfo info1("nuernberg-1991.png");
+        s_img.resize(info1.width(), info1.height());
+        importImage(info1, destImage(s_img));
+
+        ImageImportInfo info2("nuernberg-1995.png");
+        d_img.resize(info2.width(), info2.height());
+        importImage(info2, destImage(d_img));
+    }
+
+    void testInit()
+    {
+        /**
+         * Test with well-known point sets and a known result matrix
+         */
+        Matrix<double> proj = projectiveMatrix2DFromCorrespondingPoints(s_points.begin(), s_points.end(), d_points.begin());
+
+        /**
+         * Estimated result:
+         *
+         *  0.7908564596 -0.2771243619 -246.1575689662
+         * -0.0156283750  0.6189887443 -195.9746959403
+         * -0.0000258457 -0.0006847562    1.0000000000
+         */
+
+        Matrix<double> reference(3,3);
+        reference(0,0) =  0.7908564596; reference(0,1) = -0.2771243619; reference(0,2) = -246.1575689662;
+        reference(1,0) = -0.0156283750; reference(1,1) =  0.6189887443; reference(1,2) = -195.9746959403;
+        reference(2,0) = -0.0000258457; reference(2,1) = -0.0006847562; reference(2,2) =    1.000000;
+
+        shouldEqualToleranceMatrices(proj, reference, test_epsilon);
+
+        /**
+         * visual interpretation by means of the warped image:
+         */
+
+         BImage temp = d_img;
+         projectiveWarpImage(SplineImageView<2,unsigned char>(srcImageRange(s_img)), destImageRange(temp), proj);
+         exportImage(srcImageRange(temp), ImageExportInfo("res-proj.png"));
+
+    }
+
+};
+struct ProjectiveRegistrationTestSuite
+: public test_suite
+{
+    ProjectiveRegistrationTestSuite()
+    : test_suite("ProjectiveRegistrationTestSuite")
+    {
+        add( testCase( &ProjectiveIdentityTest::testInit));
+        add( testCase( &ProjectiveRegistrationTest::testInit));
+   }
+};
+struct PolynomialIdentityTest
+{
+    std::vector<TinyVector<double,2> > s_points;
+
+    PolynomialIdentityTest()
+    : s_points(srcPoints())
+    {
+    }
+
+    void testInit()
+    {
+        /**
+         * First test: If point sets are equal -> identity w.r.t polynom matrix representation should be the result!
+         */
+        Matrix<double> identity = polynomialMatrix2DFromCorrespondingPoints<3>(s_points.begin(), s_points.end(), s_points.begin());
+
+        /**
+         * Estimated result:
+         *
+         * Simple polygon: x -> (0 + 1*x + 0*y + 0*x^2 + 0*x*y + 0*y^2 + 0*x^3 + 0*x^2*y + 0*x*y^2 + 0*y^3)
+         *                 y -> (0 + 0*x + 1*y + 0*x^2 + 0*x*y + 0*y^2 + 0*x^3 + 0*x^2*y + 0*x*y^2 + 0*y^3)
+         *
+         * In matrix notation: [0.00, 0.00]
+         *                     [1.00, 0.00] x^1 , y^0
+         *                     [0.00, 1.00] x^0 , y^1
+         *                     [0.00, 0.00] x^2 , y^0
+         *                     [0.00, 0.00] x^1 , y^1
+         *                     [0.00, 0.00] x^0 , y^2
+         *                     [0.00, 0.00] x^3 , y^0
+         *                     [0.00, 0.00] x^2 , y^1
+         *                     [0.00, 0.00] x^1 , y^2
+         *                     [0.00, 0.00] x^0 , y^3
+         */
+
+        Matrix<double> reference(10,2, 0.0);
+        reference(1,0) = 1.0; reference(2,1) = 1.0;
+        shouldEqualToleranceMatrices(identity, reference, test_epsilon);
+    }
+};
+
+
+struct PolynomialRegistrationTest
+{
+    BImage s_img;
+    BImage d_img;
+
+    std::vector<TinyVector<double,2> > s_points;
+    std::vector<TinyVector<double,2> > d_points;
+
+    PolynomialRegistrationTest()
+    : s_points(srcPoints()),
+      d_points(destPoints())
+    {
+        ImageImportInfo info1("nuernberg-1991.png");
+        s_img.resize(info1.width(), info1.height());
+        importImage(info1, destImage(s_img));
+
+        ImageImportInfo info2("nuernberg-1995.png");
+        d_img.resize(info2.width(), info2.height());
+        importImage(info2, destImage(d_img));
+    }
+
+    void testDegree0()
+    {
+        /**
+         * Test with well-known point sets and a known result matrix
+         */
+        Matrix<double> poly = polynomialMatrix2DFromCorrespondingPoints<0>(s_points.begin(), s_points.end(), d_points.begin());
+
+        /**
+         * Estimated result:
+         */
+        Matrix<double> reference(1,2);
+        reference(0,0) =  571.1969696970; reference(0,1) = 313.2727272727;
+
+        shouldEqualToleranceMatrices(poly, reference, test_epsilon);
+    }
+
+    void testDegree1()
+    {
+        /**
+         * Test with well-known point sets and a known result matrix
+         */
+        Matrix<double> poly = polynomialMatrix2DFromCorrespondingPoints<1>(s_points.begin(), s_points.end(), d_points.begin());
+
+        /**
+         * Estimated result:
+         */
+        Matrix<double> reference(3,2);
+        reference(0,0) =  -824.6829238728; reference(0,1) = -431.5519142745;
+        reference(1,0) =     1.4856474242; reference(1,1) =   -0.0376429179;
+        reference(2,0) =     0.0350960498; reference(2,1) =    1.2727692988;
+
+        shouldEqualToleranceMatrices(poly, reference, test_epsilon);
+
+        /**
+         * visual interpretation by means of the warped image:
+         */
+        BImage temp = d_img;
+        polynomialWarpImage<1>(SplineImageView<2,unsigned char>(srcImageRange(s_img)), destImageRange(temp), poly);
+        exportImage(srcImageRange(temp), ImageExportInfo("res-poly-degree1.png"));
+    }
+
+    void testDegree2()
+    {
+        /**
+         * Test with well-known point sets and a known result matrix
+         */
+        Matrix<double> poly = polynomialMatrix2DFromCorrespondingPoints<2>(s_points.begin(), s_points.end(), d_points.begin());
+
+        /**
+         * Estimated result:
+         */
+        Matrix<double> reference(6,2);
+        reference(0,0) =  -929.9603797537; reference(0,1) = 62.7580017829;
+        reference(1,0) =     1.7368027425; reference(1,1) =  0.1279186082;
+        reference(2,0) =     0.0013088970; reference(2,1) = -1.0443071694;
+        reference(3,0) =    -0.0001356183; reference(3,1) = -0.0000165442;
+        reference(4,0) =    -0.0000115962; reference(4,1) = -0.0001563045;
+        reference(5,0) =     0.0000516651; reference(5,1) =  0.0022927547;
+
+        shouldEqualToleranceMatrices(poly, reference, test_epsilon);
+
+        /**
+         * visual interpretation by means of the warped image:
+         */
+        BImage temp = d_img;
+        polynomialWarpImage<2>(SplineImageView<2,unsigned char>(srcImageRange(s_img)), destImageRange(temp), poly);
+        exportImage(srcImageRange(temp), ImageExportInfo("res-poly-degree2.png"));
+    }
+
+    void testDegree3()
+    {
+        /**
+         * Test with well-known point sets and a known result matrix
+         */
+        Matrix<double> poly = polynomialMatrix2DFromCorrespondingPoints<3>(s_points.begin(), s_points.end(), d_points.begin());
+
+        /**
+         * Estimated result:
+         */
+        Matrix<double> reference(10,2);
+        reference(0,0) =  -694.265682659954450; reference(0,1) = -762.451820047407978;
+        reference(1,0) =     0.931229115560906; reference(1,1) =   -0.268572962775846;
+        reference(2,0) =     0.048740058262766; reference(2,1) =    4.944397113671227;
+        reference(3,0) =     0.000541326855916; reference(3,1) =   -0.000071716238508;
+        reference(4,0) =     0.000742558256144; reference(4,1) =    0.001026085249118;
+        reference(5,0) =    -0.000725321990759; reference(5,1) =   -0.010416513068178;
+        reference(6,0) =    -0.000000240139823; reference(6,1) =    0.000000135932974;
+        reference(7,0) =    -0.000000079399077; reference(7,1) =   -0.000000426260228;
+        reference(8,0) =    -0.000000502113506; reference(8,1) =   -0.000000232882327;
+        reference(9,0) =     0.000000746973881; reference(9,1) =    0.000008095034260;
+
+        shouldEqualToleranceMatrices(poly, reference, test_epsilon);
+
+        /**
+         * visual interpretation by means of the warped image:
+         */
+        BImage temp = d_img;
+        polynomialWarpImage<3>(SplineImageView<2,unsigned char>(srcImageRange(s_img)), destImageRange(temp), poly);
+        exportImage(srcImageRange(temp), ImageExportInfo("res-poly-degree3.png"));
+    }
+};
+
+struct PolynomialRegistrationTestSuite
+: public test_suite
+{
+    PolynomialRegistrationTestSuite()
+    : test_suite("PolynomialRegistrationTestSuite")
+    {
+        add( testCase( &PolynomialIdentityTest::testInit));
+        add( testCase( &PolynomialRegistrationTest::testDegree0));
+        add( testCase( &PolynomialRegistrationTest::testDegree1));
+        add( testCase( &PolynomialRegistrationTest::testDegree2));
+        add( testCase( &PolynomialRegistrationTest::testDegree3));
+    }
+};
+
+
+template<class RBF>
+struct RBFNameTraits
+{
+    static std::string name() { return "unknown"; }
+};
+
+template<>
+struct RBFNameTraits<ThinPlateSplineFunctor>
+{
+    static std::string name() { return "tps"; }
+};
+
+template<int N>
+struct RBFNameTraits<DistancePowerFunctor<N> >
+{
+    static std::string name()
+    {
+        char num_string[16];
+        sprintf ( num_string, "%d", N );
+        return std::string("dist-") + std::string(num_string);
+    }
+};
+
+
+
+template<class RadialBasisFunctor>
+struct RadialBasisRegistrationTest
+{
+    BImage s_img;
+    BImage d_img;
+
+    std::vector<TinyVector<double,2> > s_points;
+    std::vector<TinyVector<double,2> > d_points;
+
+    RadialBasisRegistrationTest()
+    : s_points(srcPoints()),
+    d_points(destPoints())
+    {
+        ImageImportInfo info1("nuernberg-1991.png");
+        s_img.resize(info1.width(), info1.height());
+        importImage(info1, destImage(s_img));
+
+        ImageImportInfo info2("nuernberg-1995.png");
+        d_img.resize(info2.width(), info2.height());
+        importImage(info2, destImage(d_img));
+    }
+
+    void testIdentity()
+    {
+        /**
+         * First test: If point sets are equal -> identity matrix should be the result!
+         */
+        RadialBasisFunctor rbf;
+        Matrix<double> identity_weight_matrix = rbfMatrix2DFromCorrespondingPoints(s_points.begin(), s_points.end(), s_points.begin(),rbf);
+
+        //Reference
+        Matrix<double> m(69, 2, 0.0);
+
+        m(67,0) = 1;
+        m(68,1) = 1;
+        shouldEqualToleranceMatrices(identity_weight_matrix, m, rbf_test_epsilon);
+    }
+
+    void testEssential()
+    {
+        /**
+         * First test: If point sets are equal -> identity matrix should be the result!
+         */
+        RadialBasisFunctor rbf;
+        Matrix<double> weight_matrix = rbfMatrix2DFromCorrespondingPoints(s_points.begin(), s_points.end(), d_points.begin(),rbf);
+
+        for(int j=0; j< d_points.size(); j++)
+        {
+            double x = d_points[j][0];
+            double y = d_points[j][1];
+            //Affine part
+            double    sx = weight_matrix(point_count,0)+weight_matrix(point_count+1,0)*x+ weight_matrix(point_count+2,0)*y,
+                    sy = weight_matrix(point_count,1)+weight_matrix(point_count+1,1)*x+ weight_matrix(point_count+2,1)*y;
+
+            //RBS part
+            for(int i=0; i<d_points.size(); i++)
+            {
+                double weight = rbf(d_points[i], d_points[j]);
+                sx += weight_matrix(i,0)*weight;
+                sy += weight_matrix(i,1)*weight;
+            }
+            shouldEqualTolerance(sx, s_points[j][0], rbf_test_epsilon);
+            shouldEqualTolerance(sy, s_points[j][1], rbf_test_epsilon);
+        }
+
+        /**
+         * visual interpretation by means of the warped image:
+         */
+        BImage temp = d_img;
+        rbfWarpImage(SplineImageView<2,unsigned char>(srcImageRange(s_img)),
+                                        destImageRange(temp),
+                                        d_points.begin(), d_points.end(),
+                                        weight_matrix,
+                                        rbf);
+        std::string filename = std::string("res-rbf(") + RBFNameTraits<RadialBasisFunctor>::name() + std::string(").png");
+        exportImage(srcImageRange(temp), ImageExportInfo(filename.c_str()));
+    }
+};
+
+struct ThinPlateSplineRegistrationTest
+{
+    BImage s_img;
+    BImage d_img;
+
+    std::vector<TinyVector<double,2> > s_points;
+    std::vector<TinyVector<double,2> > d_points;
+
+    ThinPlateSplineRegistrationTest()
+    : s_points(srcPoints()),
+      d_points(destPoints())
+    {
+        ImageImportInfo info1("nuernberg-1991.png");
+        s_img.resize(info1.width(), info1.height());
+        importImage(info1, destImage(s_img));
+
+        ImageImportInfo info2("nuernberg-1995.png");
+        d_img.resize(info2.width(), info2.height());
+        importImage(info2, destImage(d_img));
+    }
+
+    void testInit()
+    {
+        /**
+         * First test: If point sets are equal -> identity matrix should be the result!
+         */
+        ThinPlateSplineFunctor rbf;
+        Matrix<double> weight_matrix = rbfMatrix2DFromCorrespondingPoints(s_points.begin(), s_points.end(), d_points.begin(),rbf);
+
+        //Reference
+        Matrix<double> m(69,2);
+        m(0,0)  = -0.001377498384002;        m(0,1)  =  0.009226600866451;
+        m(1,0)  =  0.000032503339089;        m(1,1)  = -0.001509720626847;
+        m(2,0)  =  0.000349849805277;        m(2,1)  =  0.001938153880867;
+        m(3,0)  = -0.001340286960980;        m(3,1)  =  0.000001064271251;
+        m(4,0)  =  0.000539325657797;        m(4,1)  = -0.000543378211795;
+        m(5,0)  =  0.000348484938355;        m(5,1)  = -0.000915966809432;
+        m(6,0)  =  0.000554791916605;        m(6,1)  =  0.001775753335912;
+        m(7,0)  = -0.000365505447921;        m(7,1)  = -0.001756188922282;
+        m(8,0)  =  0.000099526739683;        m(8,1)  = -0.003328881346579;
+        m(9,0)  = -0.000855945840757;        m(9,1)  =  0.003122855949267;
+        m(10,0) = -0.000273792030977;        m(10,1) =  0.000917143372878;
+        m(11,0) =  0.002653140382189;        m(11,1) = -0.000731506595669;
+        m(12,0) = -0.000069457355061;        m(12,1) = -0.003435613347967;
+        m(13,0) =  0.001058065031450;        m(13,1) =  0.004231105333029;
+        m(14,0) = -0.000424334717220;        m(14,1) =  0.052130535965185;
+        m(15,0) = -0.000981691205091;        m(15,1) = -0.020823555463346;
+        m(16,0) = -0.000678829351729;        m(16,1) = -0.003871154682503;
+        m(17,0) =  0.001657429743661;        m(17,1) = -0.004684537034900;
+        m(18,0) =  0.001836431431159;        m(18,1) = -0.035442938589403;
+        m(19,0) = -0.000251036604155;        m(19,1) =  0.000423307680013;
+        m(20,0) = -0.000458224650186;        m(20,1) = -0.001421408760879;
+        m(21,0) =  0.000713493348626;        m(21,1) = -0.000687257870581;
+        m(22,0) = -0.001296157341485;        m(22,1) =  0.001729551998941;
+        m(23,0) =  0.000179155018211;        m(23,1) =  0.002047551397835;
+        m(24,0) = -0.001276131259978;        m(24,1) = -0.006769539699348;
+        m(25,0) = -0.001669855759675;        m(25,1) = -0.001840405300212;
+        m(26,0) =  0.006625210595690;        m(26,1) =  0.004544925562541;
+        m(27,0) =  0.005061616020780;        m(27,1) = -0.000998799955481;
+        m(28,0) = -0.004699886019629;        m(28,1) = -0.001953236466070;
+        m(29,0) = -0.006707966667593;        m(29,1) = -0.005335617405465;
+        m(30,0) = -0.000008995171240;        m(30,1) =  0.003085439002388;
+        m(31,0) = -0.003332042704579;        m(31,1) =  0.007086300850810;
+        m(32,0) =  0.000931177328601;        m(32,1) = -0.002990278471355;
+        m(33,0) =  0.002247575545516;        m(33,1) =  0.003224790578197;
+        m(34,0) = -0.003940778852971;        m(34,1) = -0.002643673196841;
+        m(35,0) =  0.003378921135544;        m(35,1) =  0.005651350720849;
+        m(36,0) = -0.003256131814242;        m(36,1) = -0.004754825881629;
+        m(37,0) =  0.006689872663251;        m(37,1) =  0.004849334797544;
+        m(38,0) = -0.005304870007691;        m(38,1) = -0.008107337815761;
+        m(39,0) =  0.004746451338148;        m(39,1) =  0.000065750506455;
+        m(40,0) = -0.002867905561383;        m(40,1) =  0.003350233719098;
+        m(41,0) = -0.001059664485314;        m(41,1) = -0.002596464294288;
+        m(42,0) =  0.004792819318783;        m(42,1) = -0.000662922218361;
+        m(43,0) = -0.003831224776921;        m(43,1) =  0.002107270860370;
+        m(44,0) = -0.000170035532265;        m(44,1) =  0.000071254611424;
+        m(45,0) =  0.000293692366501;        m(45,1) = -0.000242570567639;
+        m(46,0) =  0.000812835564245;        m(46,1) =  0.000188878966033;
+        m(47,0) = -0.000365508959215;        m(47,1) =  0.000248625368764;
+        m(48,0) =  0.000059556845286;        m(48,1) =  0.000423880323634;
+        m(49,0) =  0.000006617506705;        m(49,1) =  0.000937127030016;
+        m(50,0) =  0.000260640568960;        m(50,1) =  0.001410021894571;
+        m(51,0) =  0.000022519101131;        m(51,1) = -0.000395009938888;
+        m(52,0) = -0.000695392842208;        m(52,1) = -0.000444357574640;
+        m(53,0) = -0.000497156317044;        m(53,1) =  0.001898946517854;
+        m(54,0) =  0.000233316447714;        m(54,1) = -0.002215381428407;
+        m(55,0) =  0.001607979140179;        m(55,1) = -0.001191652089368;
+        m(56,0) = -0.001806711090928;        m(56,1) = -0.000974487074949;
+        m(57,0) =  0.001122008742798;        m(57,1) = -0.003154750122584;
+        m(58,0) =  0.000000977433459;        m(58,1) =  0.001396272823941;
+        m(59,0) = -0.000271382198722;        m(59,1) =  0.001355857463705;
+        m(60,0) =  0.000417816858966;        m(60,1) =  0.000776812795073;
+        m(61,0) = -0.000050555955893;        m(61,1) =  0.002676273718959;
+        m(62,0) =  0.001117169088679;        m(62,1) =  0.003193743999999;
+        m(63,0) = -0.000317593888323;        m(63,1) = -0.004971039750199;
+        m(64,0) = -0.000544110734374;        m(64,1) =  0.002762020120260;
+        m(65,0) =  0.000616392901421;        m(65,1) =  0.002574136813928;
+        m(66,0) =  0.000539075187236;        m(66,1) =  0.000035460307110;
+        m(67,0) =  1.033807852169952;        m(67,1) = -0.676702412782481;
+        m(68,0) = -0.260446157273618;        m(68,1) =  1.130619201887931;
+
+        shouldEqualToleranceMatrices(weight_matrix, m, test_epsilon);
+    }
+};
+
+
+struct RadialBasisRegistrationTestSuite
+: public test_suite
+{
+    RadialBasisRegistrationTestSuite()
+    : test_suite("RadialBasisRegistrationTestSuite")
+    {
+        //TPS warping
+        add( testCase( &RadialBasisRegistrationTest<ThinPlateSplineFunctor>::testIdentity));
+        add( testCase( &RadialBasisRegistrationTest<ThinPlateSplineFunctor>::testEssential));
+        add( testCase( &ThinPlateSplineRegistrationTest::testInit));
+        //DistancePowerFunctor warping
+        add( testCase( &RadialBasisRegistrationTest<DistancePowerFunctor<1> >::testIdentity));
+        add( testCase( &RadialBasisRegistrationTest<DistancePowerFunctor<1> >::testEssential));
+        add( testCase( &RadialBasisRegistrationTest<DistancePowerFunctor<3> >::testIdentity));
+        add( testCase( &RadialBasisRegistrationTest<DistancePowerFunctor<3> >::testEssential));
+    }
+};
+
+
+
+struct RegistrationTestCollection
+: public test_suite
+{
+    RegistrationTestCollection()
+    : test_suite("RegistrationTestCollection")
+    {
+#ifdef HasFFTW3
+        add( new EstimateGlobalRotationTranslationTestSuite);
+#endif
+        add( new ProjectiveRegistrationTestSuite);
+        add( new PolynomialRegistrationTestSuite);
+        add( new RadialBasisRegistrationTestSuite);
+   }
+};
+
+int main(int argc, char ** argv)
+{
+    RegistrationTestCollection test;
+
+    int failed = test.run(testsToBeExecuted(argc, argv));
+
+    std::cout << test.report() << std::endl;
+
+    return (failed != 0);
+}
+
diff --git a/test/sampler/test.cxx b/test/sampler/test.cxx
index 380a3b8..d102f23 100644
--- a/test/sampler/test.cxx
+++ b/test/sampler/test.cxx
@@ -392,7 +392,7 @@ void SamplerTests::testSamplingWithReplacementChi2()
     The expectation value of a binomial distribution is n*p ==>
     The percentage of samples not used is (n*p)/k = p
     For large n p converges to 0.366 => numpositives should be
-    around 0.63 +/- 0.01 */
+    around 0.63 +/- 0.015 */
     totalDataCount = 10000;
     {
         Sampler<> sampler( totalDataCount, 
@@ -400,7 +400,7 @@ void SamplerTests::testSamplingWithReplacementChi2()
         sampler.sample();
         double numPositives = double(totalDataCount - sampler.oobIndices().size()) / totalDataCount;
 
-        shouldEqualTolerance (0, numPositives-0.63, 0.01);
+        shouldEqualTolerance (0, numPositives-0.63, 0.015);
     }
 }
 
diff --git a/test/simpleanalysis/test.cxx b/test/simpleanalysis/test.cxx
index 454df4d..3e092e7 100755
--- a/test/simpleanalysis/test.cxx
+++ b/test/simpleanalysis/test.cxx
@@ -29,7 +29,7 @@
 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
-/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
 
@@ -144,7 +144,7 @@ struct LabelingTest
     {
         Image res(img1);
         int count = labelImage(srcImageRange(img1), destImage(res), false);
-        
+
         should(2 == count);
 
         Image::ScanOrderIterator i1 = img1.begin();
@@ -265,10 +265,10 @@ struct LabelingTest
         regionImageToEdgeImage(View(tmp), View(res2), 1.0);
 
         static const double edges[] = {
-            0, 1, 1, 1, 0, 
-            1, 0, 0, 1, 0, 
-            1, 0, 0, 1, 0, 
-            1, 1, 1, 1, 0, 
+            0, 1, 1, 1, 0,
+            1, 0, 0, 1, 0,
+            1, 0, 0, 1, 0,
+            1, 1, 1, 1, 0,
             0, 0, 0, 0, 0};
 
         shouldEqualSequence(res2.begin(), res2.end(), edges);
@@ -647,6 +647,42 @@ struct EdgeDetectionTest
         }
     }
 
+    void cannyNegativeThresholdTest()
+    {
+        double scale = 1.0;
+        double threshold = -1.0;
+
+        try
+        {
+            std::vector<vigra::Edgel> edgels;
+            cannyEdgelListThreshold(View(imgCanny), edgels, scale, threshold);
+            failTest("No exception thrown in cannyEdgelListThreshold with negative gradient thresholds.");
+        }
+        catch(PreconditionViolation &)
+        {}
+
+        try
+        {
+            vigra::BImage result(40, 40);
+            result = 0;
+            cannyEdgeImageWithThinning(View(imgCanny), MultiArrayView<2, unsigned char>(result), scale, threshold, 1, false);
+            failTest("No exception thrown in cannyEdgeImageWithThinning with negative gradient thresholds.");
+        }
+        catch(PreconditionViolation &)
+        {}
+
+        try
+        {
+            std::vector<vigra::Edgel> edgels;
+            cannyEdgelList3x3Threshold(View(imgCanny),
+                                       edgels, scale, threshold);
+            failTest("No exception thrown in cannyEdgelList3x3Threshold with negative gradient thresholds.");
+        }
+        catch(PreconditionViolation &)
+        {}
+
+    }
+
     void cannyEdgelList3x3Test()
     {
         std::vector<vigra::Edgel> edgels;
@@ -838,12 +874,12 @@ struct EqualWithToleranceFunctor
     EqualWithToleranceFunctor(T tolerance = 2.0 * NumericTraits<T>::epsilon())
     : t(tolerance)
     {}
-    
+
     bool operator()(T l, T r) const
     {
         return abs(l-r) <= t;
     }
-    
+
     T t;
 };
 
@@ -955,7 +991,7 @@ struct LocalMinMaxTest
         should(4 == localMinima(vol, res2, LocalMinmaxOptions().neighborhood(0).markWith(1).allowPlateaus()));
         should(res == res2);
     }
-    
+
     void extendedLocalMinimum3DTest2()
     {
         Volume res(vol.shape()), res2(vol.shape());
@@ -1032,7 +1068,7 @@ struct LocalMinMaxTest
         should(3 == localMaxima(vol, res2, LocalMinmaxOptions().neighborhood(0).markWith(1).allowPlateaus()));
         should(res == res2);
     }
-    
+
     void extendedLocalMaximum3DTest2()
     {
         Volume res(vol.shape()), res2(vol.shape());
@@ -1081,7 +1117,7 @@ struct LocalMinMaxTest
         should(res == res2);
 
         res.init(0);
-        localMinima(srcImageRange(img), destImage(res), 
+        localMinima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().allowAtBorder());
         desired[8] = 1.0;
         desired[26] = 1.0;
@@ -1115,7 +1151,7 @@ struct LocalMinMaxTest
         should(res == res2);
 
         res.init(0);
-        localMinima(srcImageRange(img), destImage(res), 
+        localMinima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().neighborhood(0).allowAtBorder());
         desired[8] = 1.0;
         desired[26] = 1.0;
@@ -1152,13 +1188,13 @@ struct LocalMinMaxTest
         should(res == res2);
 
         res.init(0);
-        localMinima(srcImageRange(img), destImage(res), 
+        localMinima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().neighborhood(8).threshold(-1.0).allowAtBorder());
         desired[26] = 1.0;
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res2.init(0);
-        should(2 == localMinima(img, res2, 
+        should(2 == localMinima(img, res2,
                                 LocalMinmaxOptions().neighborhood(8).threshold(-1.0).allowAtBorder()));
         should(res == res2);
     }
@@ -1186,14 +1222,14 @@ struct LocalMinMaxTest
         should(res == res2);
 
         res.init(0);
-        localMaxima(srcImageRange(img), destImage(res), 
+        localMaxima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().allowAtBorder());
         desired[0] = 1.0;
         desired[63] = 1.0;
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res2.init(0);
-        should(4 == localMaxima(img, res2, 
+        should(4 == localMaxima(img, res2,
                                 LocalMinmaxOptions().allowAtBorder()));
         should(res == res2);
     }
@@ -1202,7 +1238,7 @@ struct LocalMinMaxTest
     {
         Image res(img.shape()), res2(img.shape());
 
-        localMaxima(srcImageRange(img), destImage(res), 
+        localMaxima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().neighborhood(4));
 
         double desired[] = {
@@ -1223,7 +1259,7 @@ struct LocalMinMaxTest
         should(res == res2);
 
         res.init(0);
-        localMaxima(srcImageRange(img), destImage(res), 
+        localMaxima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().neighborhood(DirectNeighborhood).allowAtBorder());
         desired[0] = 1.0;
         desired[27] = 1.0;
@@ -1231,7 +1267,7 @@ struct LocalMinMaxTest
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res2.init(0);
-        should(7 == localMaxima(img, res2, 
+        should(7 == localMaxima(img, res2,
                                 LocalMinmaxOptions().neighborhood(DirectNeighborhood).allowAtBorder()));
         should(res == res2);
     }
@@ -1240,7 +1276,7 @@ struct LocalMinMaxTest
     {
         Image res(img.shape()), res2(img.shape());
 
-        localMaxima(srcImageRange(img), destImage(res), 
+        localMaxima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().markWith(1.0).neighborhood(8).threshold(0.2));
 
         double desired[] = {
@@ -1261,13 +1297,13 @@ struct LocalMinMaxTest
         should(res == res2);
 
         res.init(0);
-        localMaxima(srcImageRange(img), destImage(res), 
+        localMaxima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().allowAtBorder().threshold(0.2));
         desired[63] = 1.0;
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res2.init(0);
-        should(2 == localMaxima(img, res2, 
+        should(2 == localMaxima(img, res2,
                                 LocalMinmaxOptions().neighborhood(IndirectNeighborhood).threshold(0.2).allowAtBorder()));
         should(res == res2);
     }
@@ -1292,23 +1328,23 @@ struct LocalMinMaxTest
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res.init(0);
-        localMinima(srcImageRange(img), destImage(res), 
+        localMinima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().allowPlateaus());
         shouldEqualSequence(res.begin(), res.end(), desired);
 
-        should(4 == localMinima(img, res2, 
+        should(4 == localMinima(img, res2,
                                 LocalMinmaxOptions().allowPlateaus()));
         should(res == res2);
 
         res.init(0);
-        localMinima(srcImageRange(img), destImage(res), 
+        localMinima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().allowAtBorder().allowPlateaus());
         desired[8] = 1.0;
         desired[26] = 1.0;
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res2.init(0);
-        should(6 == localMinima(img, res2, 
+        should(6 == localMinima(img, res2,
                                 LocalMinmaxOptions().allowAtBorder().allowPlateaus()));
         should(res == res2);
     }
@@ -1331,18 +1367,18 @@ struct LocalMinMaxTest
             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
 
         shouldEqualSequence(res.begin(), res.end(), desired);
- 
+
         res.init(0);
-        localMinima(srcImageRange(img), destImage(res), 
+        localMinima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().allowPlateaus().neighborhood(4));
         shouldEqualSequence(res.begin(), res.end(), desired);
 
-        should(7 == localMinima(img, res2, 
+        should(7 == localMinima(img, res2,
                                 LocalMinmaxOptions().allowPlateaus().neighborhood(0)));
         should(res == res2);
 
         res.init(0);
-        localMinima(srcImageRange(img), destImage(res), 
+        localMinima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().neighborhood(4).allowAtBorder().allowPlateaus());
         desired[8] = 1.0;
         desired[26] = 1.0;
@@ -1350,7 +1386,7 @@ struct LocalMinMaxTest
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res2.init(0);
-        should(10 == localMinima(img, res2, 
+        should(10 == localMinima(img, res2,
                                 LocalMinmaxOptions().allowAtBorder().allowPlateaus().neighborhood(4)));
         should(res == res2);
    }
@@ -1374,23 +1410,23 @@ struct LocalMinMaxTest
 
         shouldEqualSequence(res.begin(), res.end(), desired);
         res.init(0);
-        localMaxima(srcImageRange(img), destImage(res), 
+        localMaxima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().allowPlateaus());
         shouldEqualSequence(res.begin(), res.end(), desired);
 
-        should(4 == localMaxima(img, res2, 
+        should(4 == localMaxima(img, res2,
                                 LocalMinmaxOptions().allowPlateaus()));
         should(res == res2);
 
         res.init(0);
-        localMaxima(srcImageRange(img), destImage(res), 
+        localMaxima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().allowAtBorder().allowPlateaus());
         desired[0] = 1.0;
         desired[63] = 1.0;
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res2.init(0);
-        should(6 == localMaxima(img, res2, 
+        should(6 == localMaxima(img, res2,
                                 LocalMinmaxOptions().allowAtBorder().allowPlateaus()));
         should(res == res2);
    }
@@ -1415,16 +1451,16 @@ struct LocalMinMaxTest
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res.init(0);
-        localMaxima(srcImageRange(img), destImage(res), 
+        localMaxima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().allowPlateaus().neighborhood(4));
         shouldEqualSequence(res.begin(), res.end(), desired);
 
-        should(6 == localMaxima(img, res2, 
+        should(6 == localMaxima(img, res2,
                                 LocalMinmaxOptions().allowPlateaus().neighborhood(DirectNeighborhood)));
         should(res == res2);
 
         res.init(0);
-        localMaxima(srcImageRange(img), destImage(res), 
+        localMaxima(srcImageRange(img), destImage(res),
                     LocalMinmaxOptions().neighborhood(4).allowAtBorder().allowPlateaus());
         desired[0] = 1.0;
         desired[27] = 1.0;
@@ -1432,7 +1468,7 @@ struct LocalMinMaxTest
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         res2.init(0);
-        should(9 == localMaxima(img, res2, 
+        should(9 == localMaxima(img, res2,
                                 LocalMinmaxOptions().allowAtBorder().allowPlateaus().neighborhood(4)));
         should(res == res2);
    }
@@ -1456,7 +1492,7 @@ struct LocalMinMaxTest
         extendedLocalMaxima(srcImageRange(img), destImage(res), 1.0,
                             EightNeighborCode(),
                             EqualWithToleranceFunctor<Image::value_type>(0.2));
-        
+
         static const double desired[] = {
             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
@@ -1510,7 +1546,7 @@ struct WatershedsTest
         IntImage res(img.shape()), res2(img.shape());
 
         /*******************************************************************/
-        
+
         static const double desired[] = {
             1.0,  1.0,  1.0,  2.0,  3.0,  3.0,  3.0,  3.0,  4.0,
             1.0,  1.0,  1.0,  2.0,  2.0,  3.0,  3.0,  3.0,  4.0,
@@ -1523,12 +1559,12 @@ struct WatershedsTest
             7.0,  7.0,  7.0,  5.0,  5.0,  5.0,  5.0,  5.0,  5.0};
 
         int count = watershedsUnionFind(srcImageRange(img), destImage(res));
-        
+
         shouldEqual(7, count);
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         /*******************************************************************/
-        
+
         // break ties explicitly to make the test independent of tie breaking rules
         img(3,1) -= 0.01;
         img(3,2) -= 0.01;
@@ -1538,14 +1574,14 @@ struct WatershedsTest
         img(8,5) += 0.01;
 
         static const double desiredSeeds[] = {
-            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,  1.0,  1.0,  
-            0.0,  2.0,  0.0,  3.0,  0.0,  1.0,  0.0,  1.0,  1.0,  
-            0.0,  0.0,  0.0,  3.0,  0.0,  0.0,  0.0,  1.0,  1.0,  
-            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,  
-            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  
-            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  
-            0.0,  0.0,  4.0,  4.0,  4.0,  0.0,  5.0,  0.0,  0.0,  
-            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  
+            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,  1.0,  1.0,
+            0.0,  2.0,  0.0,  3.0,  0.0,  1.0,  0.0,  1.0,  1.0,
+            0.0,  0.0,  0.0,  3.0,  0.0,  0.0,  0.0,  1.0,  1.0,
+            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,
+            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,
+            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,
+            0.0,  0.0,  4.0,  4.0,  4.0,  0.0,  5.0,  0.0,  0.0,
+            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,
             0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0};
 
 
@@ -1560,16 +1596,16 @@ struct WatershedsTest
         shouldEqualSequence(res2.begin(), res2.end(), desiredSeeds);
 
         /*******************************************************************/
-        
+
         static const double desiredRG[] = {
-            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  3.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  3.0,  3.0,  3.0,  3.0,  1.0,  1.0,  1.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  1.0,  1.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,  
+            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  3.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  3.0,  3.0,  3.0,  3.0,  1.0,  1.0,  1.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  1.0,  1.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,
             4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0};
 
         count = watershedsRegionGrowing(srcImageRange(img), destImage(res));
@@ -1578,16 +1614,16 @@ struct WatershedsTest
         shouldEqualSequence(res.begin(), res.end(), desiredRG);
 
         /*******************************************************************/
-        
+
         static const double desiredRGC[] = {
-            2.0,  2.0,  0.0,  3.0,  0.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  0.0,  3.0,  0.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  0.0,  3.0,  0.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,  
-            0.0,  0.0,  0.0,  4.0,  4.0,  0.0,  5.0,  0.0,  0.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  0.0,  5.0,  5.0,  5.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  0.0,  5.0,  5.0,  5.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  0.0,  0.0,  0.0,  0.0,  
+            2.0,  2.0,  0.0,  3.0,  0.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  0.0,  3.0,  0.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  0.0,  3.0,  0.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,
+            0.0,  0.0,  0.0,  4.0,  4.0,  0.0,  5.0,  0.0,  0.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  0.0,  5.0,  5.0,  5.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  0.0,  5.0,  5.0,  5.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  0.0,  0.0,  0.0,  0.0,
             4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  4.0};
 
         res.init(0);
@@ -1603,16 +1639,16 @@ struct WatershedsTest
         should(res == res2);
 
         /*******************************************************************/
-        
+
         static const double desiredTRG[] = {
-            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  3.0,  3.0,  3.0,  5.0,  1.0,  1.0,  1.0,  
-            4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,  1.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,  
-            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,  
+            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  3.0,  3.0,  3.0,  5.0,  1.0,  1.0,  1.0,
+            4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,  1.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,
+            4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0,  5.0,  5.0,
             4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  4.0,  5.0,  5.0};
 
         res.init(0);
@@ -1648,7 +1684,7 @@ struct WatershedsTest
         IntImage res(img.shape()), res2(img.shape());
 
         /*******************************************************************/
-        
+
         static const double desired[] = {
             1.0,  1.0,  1.0,  2.0,  2.0,  3.0,  4.0,  4.0,  5.0,
             1.0,  1.0,  1.0,  2.0,  2.0,  3.0,  3.0,  4.0,  5.0,
@@ -1666,7 +1702,7 @@ struct WatershedsTest
         shouldEqualSequence(res.begin(), res.end(), desired);
 
         /*******************************************************************/
-        
+
         // break ties explicitly to make the test independent of tie breaking rules
         img(3,0) += 0.01;
         img(3,4) += 0.01;
@@ -1679,14 +1715,14 @@ struct WatershedsTest
         img(8,8) += 0.01;
 
         static const double desiredSeeds[] = {
-            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,  1.0,  1.0,  
-            0.0,  2.0,  0.0,  3.0,  0.0,  4.0,  0.0,  1.0,  1.0,  
-            0.0,  0.0,  0.0,  3.0,  0.0,  0.0,  0.0,  1.0,  1.0,  
-            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,  
-            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  
-            0.0,  0.0,  0.0,  0.0,  0.0,  5.0,  0.0,  0.0,  0.0,  
-            0.0,  0.0,  6.0,  6.0,  6.0,  0.0,  7.0,  0.0,  0.0,  
-            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  
+            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,  1.0,  1.0,
+            0.0,  2.0,  0.0,  3.0,  0.0,  4.0,  0.0,  1.0,  1.0,
+            0.0,  0.0,  0.0,  3.0,  0.0,  0.0,  0.0,  1.0,  1.0,
+            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  1.0,
+            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,
+            0.0,  0.0,  0.0,  0.0,  0.0,  5.0,  0.0,  0.0,  0.0,
+            0.0,  0.0,  6.0,  6.0,  6.0,  0.0,  7.0,  0.0,  0.0,
+            0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,
             0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0};
 
         res.init(0);
@@ -1700,16 +1736,16 @@ struct WatershedsTest
         shouldEqualSequence(res2.begin(), res2.end(), desiredSeeds);
 
         /*******************************************************************/
-        
+
         static const double desiredRG[] = {
-            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  3.0,  3.0,  4.0,  4.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  3.0,  3.0,  3.0,  4.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  2.0,  3.0,  5.0,  5.0,  1.0,  1.0,  1.0,  
-            6.0,  6.0,  6.0,  6.0,  5.0,  5.0,  5.0,  1.0,  1.0,  
-            6.0,  6.0,  6.0,  6.0,  5.0,  5.0,  5.0,  7.0,  7.0,  
-            6.0,  6.0,  6.0,  6.0,  6.0,  7.0,  7.0,  7.0,  7.0,  
-            6.0,  6.0,  6.0,  6.0,  6.0,  6.0,  7.0,  7.0,  7.0,  
+            2.0,  2.0,  2.0,  3.0,  3.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  3.0,  3.0,  4.0,  4.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  3.0,  3.0,  3.0,  4.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  2.0,  3.0,  5.0,  5.0,  1.0,  1.0,  1.0,
+            6.0,  6.0,  6.0,  6.0,  5.0,  5.0,  5.0,  1.0,  1.0,
+            6.0,  6.0,  6.0,  6.0,  5.0,  5.0,  5.0,  7.0,  7.0,
+            6.0,  6.0,  6.0,  6.0,  6.0,  7.0,  7.0,  7.0,  7.0,
+            6.0,  6.0,  6.0,  6.0,  6.0,  6.0,  7.0,  7.0,  7.0,
             6.0,  6.0,  6.0,  6.0,  6.0,  6.0,  7.0,  7.0,  7.0};
 
         count = watershedsRegionGrowing(srcImageRange(img), destImage(res), FourNeighborCode());
@@ -1718,16 +1754,16 @@ struct WatershedsTest
         shouldEqualSequence(res.begin(), res.end(), desiredRG);
 
         /*******************************************************************/
-        
+
         static const double desiredRGC[] = {
-            2.0,  2.0,  2.0,  0.0,  0.0,  0.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  0.0,  3.0,  0.0,  4.0,  0.0,  1.0,  1.0,  
-            2.0,  2.0,  0.0,  3.0,  0.0,  0.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  2.0,  0.0,  5.0,  5.0,  0.0,  1.0,  1.0,  
-            0.0,  0.0,  0.0,  0.0,  5.0,  5.0,  5.0,  0.0,  0.0,  
-            6.0,  6.0,  6.0,  6.0,  0.0,  5.0,  0.0,  7.0,  7.0,  
-            6.0,  6.0,  6.0,  6.0,  6.0,  0.0,  7.0,  7.0,  7.0,  
-            6.0,  6.0,  6.0,  6.0,  6.0,  0.0,  7.0,  7.0,  7.0,  
+            2.0,  2.0,  2.0,  0.0,  0.0,  0.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  0.0,  3.0,  0.0,  4.0,  0.0,  1.0,  1.0,
+            2.0,  2.0,  0.0,  3.0,  0.0,  0.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  2.0,  0.0,  5.0,  5.0,  0.0,  1.0,  1.0,
+            0.0,  0.0,  0.0,  0.0,  5.0,  5.0,  5.0,  0.0,  0.0,
+            6.0,  6.0,  6.0,  6.0,  0.0,  5.0,  0.0,  7.0,  7.0,
+            6.0,  6.0,  6.0,  6.0,  6.0,  0.0,  7.0,  7.0,  7.0,
+            6.0,  6.0,  6.0,  6.0,  6.0,  0.0,  7.0,  7.0,  7.0,
             6.0,  6.0,  6.0,  6.0,  6.0,  6.0,  0.0,  7.0,  7.0};
 
         res.init(0);
@@ -1743,16 +1779,16 @@ struct WatershedsTest
         should(res == res2);
 
         /*******************************************************************/
-        
+
         static const double desiredTRG[] = {
-            2.0,  2.0,  2.0,  3.0,  1.0,  1.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  2.0,  3.0,  3.0,  4.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  3.0,  3.0,  3.0,  4.0,  1.0,  1.0,  1.0,  
-            2.0,  2.0,  2.0,  3.0,  6.0,  5.0,  7.0,  1.0,  1.0,  
-            6.0,  6.0,  6.0,  6.0,  6.0,  5.0,  7.0,  7.0,  1.0,  
-            6.0,  6.0,  6.0,  6.0,  6.0,  5.0,  7.0,  7.0,  7.0,  
-            6.0,  6.0,  6.0,  6.0,  6.0,  7.0,  7.0,  7.0,  7.0,  
-            6.0,  6.0,  6.0,  6.0,  6.0,  6.0,  7.0,  7.0,  7.0,  
+            2.0,  2.0,  2.0,  3.0,  1.0,  1.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  2.0,  3.0,  3.0,  4.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  3.0,  3.0,  3.0,  4.0,  1.0,  1.0,  1.0,
+            2.0,  2.0,  2.0,  3.0,  6.0,  5.0,  7.0,  1.0,  1.0,
+            6.0,  6.0,  6.0,  6.0,  6.0,  5.0,  7.0,  7.0,  1.0,
+            6.0,  6.0,  6.0,  6.0,  6.0,  5.0,  7.0,  7.0,  7.0,
+            6.0,  6.0,  6.0,  6.0,  6.0,  7.0,  7.0,  7.0,  7.0,
+            6.0,  6.0,  6.0,  6.0,  6.0,  6.0,  7.0,  7.0,  7.0,
             6.0,  6.0,  6.0,  6.0,  6.0,  6.0,  6.0,  6.0,  6.0};
 
         res.init(0);
@@ -2115,7 +2151,7 @@ struct NoiseNormalizationTest
         vigra::ImageImportInfo info("noiseNormalizationTest.xv");
         vigra_precondition(info.width() == 400 && info.height() == 20,
            "NoiseNormalizationTest: input image has wrong size.");
-           
+
         u8image.resize(info.size());
         importImage(info, destImage(u8image));
         image.resize(info.size());
@@ -2127,7 +2163,7 @@ struct NoiseNormalizationTest
             importImage(info, destImage(rgb, dband));
         }
     }
-    
+
     template <class Iterator, class Accessor>
     void checkVariance(Iterator ul, Accessor const & a, double tolerance)
     {
@@ -2142,14 +2178,14 @@ struct NoiseNormalizationTest
                     sum2 += sq(a(ul, Diff2D(x, y)));
                 }
             }
-            
+
             sum /= 400.0;
             sum2 /= 400.0;
-            
+
             shouldEqualTolerance(VIGRA_CSTD::sqrt(sum2 - sq(sum))-1.0, 0.0, tolerance);
        }
     }
-    
+
     void testParametricNoiseNormalizationU8()
     {
         GrayImage res(image.size());
@@ -2162,7 +2198,7 @@ struct NoiseNormalizationTest
         quadraticNoiseNormalization(srcImageRange(u8image), destImage(res));
         checkVariance(res.upperLeft(), res.accessor(), 0.1);
     }
-  
+
     void testParametricNoiseNormalization()
     {
         GrayImage res(image.size());
@@ -2175,7 +2211,7 @@ struct NoiseNormalizationTest
         quadraticNoiseNormalization(View(image), View(res));
         checkVariance(res.upperLeft(), res.accessor(), 0.1);
    }
-  
+
     void testParametricNoiseNormalizationRGB()
     {
         RGBImage res(rgb.size());
@@ -2204,24 +2240,24 @@ struct NoiseNormalizationTest
             checkVariance(res.upperLeft(), dband, 0.1);
         }
     }
-  
+
     void testNonparametricNoiseNormalizationU8()
     {
-        GrayImage res(image.size());        
+        GrayImage res(image.size());
         nonparametricNoiseNormalization(srcImageRange(u8image), destImage(res));
         checkVariance(res.upperLeft(), res.accessor(), 0.1);
     }
-  
+
     void testNonparametricNoiseNormalization()
     {
-        GrayImage res(image.size());        
+        GrayImage res(image.size());
         nonparametricNoiseNormalization(srcImageRange(image), destImage(res));
         checkVariance(res.upperLeft(), res.accessor(), 0.1);
    }
-  
+
     void testNonparametricNoiseNormalizationRGB()
     {
-        RGBImage res(rgb.size());        
+        RGBImage res(rgb.size());
         nonparametricNoiseNormalization(srcImageRange(rgb), destImage(res));
         for(unsigned int band = 0; band < 3; ++band)
         {
@@ -2237,17 +2273,17 @@ struct SlantedEdgeMTFTest
     typedef vigra::MultiArray<2, double> Image;
     typedef vigra::ArrayVector<vigra::TinyVector<double, 2> > Result;
     typedef Result::value_type Pair;
-    
+
     Image image;
     Result reference;
 
     SlantedEdgeMTFTest()
     {
         vigra::ImageImportInfo info("slantedEdgeMTF.xv");
-           
+
         image.reshape(info.shape());
         importImage(info, destImage(image));
-        
+
         reference.push_back(Pair(0, 1));
         reference.push_back(Pair(0.0564351, 0.981739));
         reference.push_back(Pair(0.11287, 0.929577));
@@ -2266,20 +2302,20 @@ struct SlantedEdgeMTFTest
         reference.push_back(Pair(0.846526, 0.021419));
         reference.push_back(Pair(0.902961, 0));
     }
-    
+
     void testSlantedEdgeMTF()
     {
         Result res;
         slantedEdgeMTF(image, res);
-        
+
         shouldEqual(res.size(), reference.size());
-        
+
         for(unsigned int k = 0; k < res.size(); ++k)
         {
             shouldEqualTolerance(res[k][0], reference[k][0], 1e-5);
             shouldEqualTolerance(res[k][1], reference[k][1], 1e-5);
         }
-        
+
         shouldEqualTolerance(mtfFitGaussian(res), 0.5, 1e-2);
     }
 };
@@ -2291,7 +2327,7 @@ struct AffineRegistrationTest
     typedef vigra::MultiArrayView<2, double> View;
     typedef vigra::TinyVector<double, 2> Vector2;
     typedef vigra::ArrayVector<Vector2> PointList;
-    
+
     Image image;
 
     AffineRegistrationTest()
@@ -2300,22 +2336,22 @@ struct AffineRegistrationTest
         image.resize(info.size());
         importImage(info, destImage(image));
     }
-    
+
     void testCorrespondingPoints()
     {
         Matrix<double> point(3,1), res(3,1);
         point(2,0) = 1.0;
-        
+
         PointList src(3), dest(3);
-        src[0] = Vector2(1.6, 2.9);     
-        src[1] = Vector2(-1.3, -4.0);     
-        src[2] = Vector2(7.1, -0.4);     
-        dest[0] = Vector2(-2.9, 1.6);     
-        dest[1] = Vector2(12.6, -3.4);     
+        src[0] = Vector2(1.6, 2.9);
+        src[1] = Vector2(-1.3, -4.0);
+        src[2] = Vector2(7.1, -0.4);
+        dest[0] = Vector2(-2.9, 1.6);
+        dest[1] = Vector2(12.6, -3.4);
         dest[2] = Vector2(-3.3, 4.2);
-        
+
         for(int k=1; k<=3; ++k)
-        {     
+        {
             Matrix<double> a = affineMatrix2DFromCorrespondingPoints(src.begin(), src.begin()+k, dest.begin());
             for(int i=0; i<k; ++i)
             {
@@ -2334,25 +2370,25 @@ struct AffineRegistrationTest
         Matrix<double> m = translationMatrix2D(Vector2(5.0, 10.0));
         Image timg(image.size());
         affineWarpImage(SplineImageView<2, double>(srcImageRange(image)), destImageRange(timg), m);
-        
+
         Matrix<double> estimated = identityMatrix<double>(3);
         estimateTranslation(srcImageRange(image), srcImageRange(timg), estimated,
                             AffineMotionEstimationOptions<1>().highestPyramidLevel(3));
-        
+
         for(int i=0; i<9; ++i)
             shouldEqualTolerance(m.data()[i] - estimated.data()[i], 0.0, 1e-6);
-        
+
         estimated = identityMatrix<double>(3);
         estimateTranslation(View(image), View(timg), estimated,
                             AffineMotionEstimationOptions<1>().highestPyramidLevel(3));
-        
+
         for(int i=0; i<9; ++i)
             shouldEqualTolerance(m.data()[i] - estimated.data()[i], 0.0, 1e-6);
     }
 
     void testSimilarityRegistration()
     {
-        Matrix<double> m = translationMatrix2D(Vector2(5.0, 10.0)) * 
+        Matrix<double> m = translationMatrix2D(Vector2(5.0, 10.0)) *
                              rotationMatrix2DDegrees(5.0)* scalingMatrix2D(0.9);
         Image timg(image.size());
         affineWarpImage(SplineImageView<2, double>(srcImageRange(image)), destImageRange(timg), m);
@@ -2360,42 +2396,42 @@ struct AffineRegistrationTest
         Matrix<double> estimated = identityMatrix<double>(3);
         estimateSimilarityTransform(srcImageRange(image), srcImageRange(timg), estimated,
                             AffineMotionEstimationOptions<>().useLaplacianPyramid(false));
-        
+
         for(int i=0; i<9; ++i)
             shouldEqualTolerance(m.data()[i] - estimated.data()[i], 0.0, 1e-6);
 
         estimated = identityMatrix<double>(3);
-        estimateSimilarityTransform(srcImageRange(image), 
+        estimateSimilarityTransform(srcImageRange(image),
                             srcIterRange(timg.upperLeft(), timg.lowerRight()-Diff2D(20,20)), estimated,
                             AffineMotionEstimationOptions<>().useLaplacianPyramid(true));
-        
+
         for(int i=0; i<9; ++i)
             shouldEqualTolerance(m.data()[i] , estimated.data()[i], 1e-2);
 
         estimated = identityMatrix<double>(3);
         estimateSimilarityTransform(View(image),View(timg).subarray(Shape2(), Shape2(-20)), estimated,
                             AffineMotionEstimationOptions<>().useLaplacianPyramid(true));
-        
+
         for(int i=0; i<9; ++i)
             shouldEqualTolerance(m.data()[i] , estimated.data()[i], 1e-2);
     }
 
     void testAffineRegistration()
     {
-        Matrix<double> m = translationMatrix2D(Vector2(5.0, 10.0)) * 
+        Matrix<double> m = translationMatrix2D(Vector2(5.0, 10.0)) *
                              rotationMatrix2DDegrees(5.0)* scalingMatrix2D(1.0, 0.9);
         Image timg(image.size());
         affineWarpImage(SplineImageView<2, double>(srcImageRange(image)), destImageRange(timg), m);
 
         Matrix<double> estimated = identityMatrix<double>(3);
         estimateAffineTransform(srcImageRange(image), srcImageRange(timg), estimated);
-        
+
         for(int i=0; i<9; ++i)
             shouldEqualTolerance(m.data()[i] - estimated.data()[i], 0.0, 1e-6);
 
         estimated = identityMatrix<double>(3);
         estimateAffineTransform(View(image), View(timg), estimated);
-        
+
         for(int i=0; i<9; ++i)
             shouldEqualTolerance(m.data()[i] - estimated.data()[i], 0.0, 1e-6);
     }
@@ -2423,6 +2459,7 @@ struct SimpleAnalysisTestSuite
         add( testCase( &EdgeDetectionTest::beautifyCrackEdgeTest));
         add( testCase( &EdgeDetectionTest::closeGapsInCrackEdgeTest));
         add( testCase( &EdgeDetectionTest::cannyEdgelListTest));
+        add( testCase( &EdgeDetectionTest::cannyNegativeThresholdTest));
         add( testCase( &EdgeDetectionTest::cannyEdgelList3x3Test));
         add( testCase( &EdgeDetectionTest::cannyEdgeImageTest));
         add( testCase( &EdgeDetectionTest::cannyEdgeImageWithThinningTest));
diff --git a/test/slic2d/slic.xv b/test/slic2d/slic.xv
index 979b4b6..8128044 100644
Binary files a/test/slic2d/slic.xv and b/test/slic2d/slic.xv differ
diff --git a/test/slic2d/test.cxx b/test/slic2d/test.cxx
index e79cec1..77318b9 100644
--- a/test/slic2d/test.cxx
+++ b/test/slic2d/test.cxx
@@ -111,7 +111,9 @@ struct SlicTest
 
         int seedDistance = 8;
         // compute seeds automatically
-        slicSuperpixels(lennaImage, labels, 20.0, seedDistance, SlicOptions().minSize(0).iterations(40));
+        int maxlabel = slicSuperpixels(lennaImage, labels, 20.0, seedDistance, SlicOptions().minSize(0).iterations(40));
+
+        shouldEqual(maxlabel, 245);
 
         // exportImage(srcImageRange(labels), ImageExportInfo("slic.xv"));
         importImage(ImageImportInfo("slic.xv"), destImage(labels_ref));
diff --git a/test/threadpool/CMakeLists.txt b/test/threadpool/CMakeLists.txt
new file mode 100644
index 0000000..2e9deb1
--- /dev/null
+++ b/test/threadpool/CMakeLists.txt
@@ -0,0 +1,2 @@
+VIGRA_ADD_TEST(test_threadpool test.cxx)
+
diff --git a/test/threadpool/test.cxx b/test/threadpool/test.cxx
new file mode 100644
index 0000000..dbf4234
--- /dev/null
+++ b/test/threadpool/test.cxx
@@ -0,0 +1,257 @@
+/************************************************************************/
+/*                                                                      */
+/*        Copyright 2014-2015 by Ullrich Koethe and Philip Schill       */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+#include <vigra/unittest.hxx>
+#include <vigra/threadpool.hxx>
+#include <vigra/timing.hxx>
+#include <numeric>
+
+using namespace vigra;
+
+struct ThreadPoolTests
+{
+    void test_threadpool()
+    {
+        size_t const n = 10000;
+        std::vector<int> v(n);
+        ThreadPool pool(4);
+        for (size_t i = 0; i < v.size(); ++i)
+        {
+            pool.enqueue(
+                [&v, i](size_t thread_id)
+                {
+                    v[i] = 0;
+                    for (size_t k = 0; k < i+1; ++k)
+                    {
+                        v[i] += k;
+                    }
+                }
+            );
+        }
+        pool.waitFinished();
+
+        std::vector<int> v_expected(n);
+        for (size_t i = 0; i < v_expected.size(); ++i)
+            v_expected[i] = i*(i+1)/2;
+
+        shouldEqualSequence(v.begin(), v.end(), v_expected.begin());
+    }
+
+    void test_threadpool_exception()
+    {
+        bool caught = false;
+        std::string exception_string = "the test exception";
+        std::vector<int> v(10000);
+        ThreadPool pool(4);
+        std::vector<std::future<void> > futures;
+        for (size_t i = 0; i < v.size(); ++i)
+        {
+            futures.emplace_back(
+                pool.enqueue(
+                    [&v, &exception_string, i](size_t thread_id)
+                    {
+                        v[i] = thread_id;
+                        if (i == 5000)
+                            throw std::runtime_error(exception_string);
+                    }
+                )
+            );
+        }
+        try
+        {
+            for (auto & fut : futures)
+                fut.get();
+        }
+        catch (std::runtime_error & ex)
+        {
+            if (ex.what() == exception_string)
+                caught = true;
+        }
+        should(caught);
+    }
+
+    void test_parallel_foreach()
+    {
+        size_t const n = 10000;
+        std::vector<int> v_in(n);
+        std::iota(v_in.begin(), v_in.end(), 0);
+        std::vector<int> v_out(n);
+        parallel_foreach(4, v_in.begin(), v_in.end(),
+            [&v_out](size_t thread_id, int x)
+            {
+                v_out[x] = x*(x+1)/2;
+            }
+        );
+
+        std::vector<int> v_expected(n);
+        for (size_t i = 0; i < v_expected.size(); ++i)
+            v_expected[i] = i*(i+1)/2;
+
+        shouldEqualSequence(v_out.begin(), v_out.end(), v_expected.begin());
+    }
+
+    void test_parallel_foreach_exception()
+    {
+        size_t const n = 10000;
+        std::vector<int> v_in(n);
+        std::iota(v_in.begin(), v_in.end(), 0);
+        std::vector<int> v_out(n);
+        bool caught = false;
+        std::string exception_string = "the test exception";
+        try
+        {
+            parallel_foreach(4, v_in.begin(), v_in.end(),
+                [&v_out, &exception_string](size_t thread_id, int x)
+                {
+                    if (x == 5000)
+                        throw std::runtime_error(exception_string);
+                    v_out[x] = x;
+                }
+            );
+        }
+        catch (std::runtime_error & ex)
+        {
+            if (ex.what() == exception_string)
+                caught = true;
+        }
+        should(caught);
+    }
+
+    void test_parallel_foreach_sum()
+    {
+        size_t const n_threads = 4;
+        size_t const n = 2000;
+        std::vector<size_t> input(n);
+        std::iota(input.begin(), input.end(), 0);
+        std::vector<size_t> results(n_threads, 0);
+
+        parallel_foreach(n_threads, input.begin(), input.end(),
+            [&results](size_t thread_id, size_t x)
+            {
+                results[thread_id] += x;
+            }
+        );
+
+        size_t const sum = std::accumulate(results.begin(), results.end(), 0);
+        should(sum == (n*(n-1))/2);
+    }
+
+    void test_parallel_foreach_sum_serial()
+    {
+        //size_t const n_threads = 4;
+        size_t const n = 2000;
+        std::vector<size_t> input(n);
+        std::iota(input.begin(), input.end(), 0);
+        std::vector<size_t> results(1, 0);
+
+        parallel_foreach(ParallelOptions::NoThreads, input.begin(), input.end(),
+            [&results](size_t thread_id, size_t x)
+            {
+                results[thread_id] += x;
+            }
+        );
+
+        size_t const sum = std::accumulate(results.begin(), results.end(), 0);
+        should(sum == (n*(n-1))/2);
+    }
+
+    void test_parallel_foreach_sum_auto()
+    {
+        ParallelOptions opt;
+        opt.numThreads(ParallelOptions::Auto);
+
+        size_t const n = 2000;
+        std::vector<size_t> input(n);
+        std::iota(input.begin(), input.end(), 0);
+        std::vector<size_t> results(opt.getActualNumThreads(), 0);
+
+        parallel_foreach(opt.getNumThreads(), input.begin(), input.end(),
+            [&results](size_t thread_id, size_t x)
+            {
+                results[thread_id] += x;
+            }
+        );
+
+        size_t const sum = std::accumulate(results.begin(), results.end(), 0);
+        should(sum == (n*(n-1))/2);
+    }
+
+    void test_parallel_foreach_timing()
+    {
+        size_t const n_threads = 4;
+        size_t const n = 300000000;
+        std::vector<size_t> input(n);
+        std::iota(input.begin(), input.end(), 0);
+
+        USETICTOC;
+
+        std::vector<size_t> results(n_threads, 0);
+        TIC;
+        parallel_foreach(n_threads, input.begin(), input.end(),
+            [&results](size_t thread_id, size_t x)
+            {
+                results[thread_id] += 1;
+            }
+        );
+        std::cout << "parallel_foreach took " << TOCS << std::endl;
+
+        size_t const sum = std::accumulate(results.begin(), results.end(), 0);
+        should(sum == n);
+    }
+};
+
+struct ThreadPoolTestSuite : public test_suite
+{
+    ThreadPoolTestSuite()
+        :
+        test_suite("ThreadPool test")
+    {
+        add(testCase(&ThreadPoolTests::test_threadpool));
+        add(testCase(&ThreadPoolTests::test_threadpool_exception));
+        add(testCase(&ThreadPoolTests::test_parallel_foreach));
+        add(testCase(&ThreadPoolTests::test_parallel_foreach_exception));
+        add(testCase(&ThreadPoolTests::test_parallel_foreach_sum));
+        add(testCase(&ThreadPoolTests::test_parallel_foreach_sum_serial));
+        add(testCase(&ThreadPoolTests::test_parallel_foreach_sum_auto));
+        add(testCase(&ThreadPoolTests::test_parallel_foreach_timing));
+    }
+};
+
+int main(int argc, char** argv)
+{
+    ThreadPoolTestSuite threadpool_test;
+    int failed = threadpool_test.run(testsToBeExecuted(argc, argv));
+    std::cout << threadpool_test.report() << std::endl;
+    return (failed != 0);
+}
diff --git a/test/unsupervised/test.cxx b/test/unsupervised/test.cxx
index a2f5f2a..7d29b10 100644
--- a/test/unsupervised/test.cxx
+++ b/test/unsupervised/test.cxx
@@ -74,7 +74,7 @@ public:
 
         prepareRows(features, features, ZeroMean);
 
-        principleComponents(features, fz, zv);
+        principalComponents(features, fz, zv);
 
         Matrix<double> model = fz*zv;
         shouldEqualTolerance(squaredNorm(model-features), 1530214.34284834, 1e-10);
@@ -85,7 +85,7 @@ public:
         char hdf5group_3[] = "ZV";
         writeHDF5(hdf5File_2, hdf5group_2, fz);
         writeHDF5(hdf5File_2, hdf5group_3, zv);
-#endif    
+#endif
     }
 
     void testPLSADecomposition()
@@ -147,7 +147,7 @@ public:
 
         // test if reconstruction is close to original
         // tricky - how to properly test that? it will never be identical!
-        Matrix<double> model = fz*zv; 
+        Matrix<double> model = fz*zv;
         double meanError = (features - model).squaredNorm() / columnCount(features);
         should ( meanError < 5000 );
 
@@ -157,7 +157,7 @@ public:
         char hdf5group_3[] = "ZV";
         writeHDF5(hdf5File_2, hdf5group_2, fz);
         writeHDF5(hdf5File_2, hdf5group_3, zv);
-#endif    
+#endif
     }
 };
 
diff --git a/test/utilities/CMakeLists.txt b/test/utilities/CMakeLists.txt
index a9c37f1..3ab06cf 100644
--- a/test/utilities/CMakeLists.txt
+++ b/test/utilities/CMakeLists.txt
@@ -1 +1,7 @@
-VIGRA_ADD_TEST(test_utilities test.cxx)
+
+IF(ZLIB_FOUND)
+  ADD_DEFINITIONS(-DHasZLIB)
+ENDIF(ZLIB_FOUND)
+
+
+VIGRA_ADD_TEST(test_utilities test.cxx LIBRARIES vigraimpex)
diff --git a/test/utilities/test.cxx b/test/utilities/test.cxx
index 2ea5a39..e195eed 100755
--- a/test/utilities/test.cxx
+++ b/test/utilities/test.cxx
@@ -29,7 +29,7 @@
 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
-/*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
 /*                                                                      */
 /************************************************************************/
 
@@ -38,12 +38,20 @@
 #include <iterator>
 #include <algorithm>
 #include <queue>
+#include <set>
+
 #include "vigra/unittest.hxx"
 #include "vigra/accessor.hxx"
 #include "vigra/array_vector.hxx"
 #include "vigra/copyimage.hxx"
 #include "vigra/sized_int.hxx"
-#include "vigra/bucket_queue.hxx"
+
+#include "vigra/priority_queue.hxx"
+#include "vigra/algorithm.hxx"
+#include "vigra/compression.hxx"
+#include "vigra/multi_blocking.hxx"
+
+#include "vigra/any.hxx"
 
 using namespace vigra;
 
@@ -54,18 +62,18 @@ struct ArrayVectorTest
     typedef Vector::iterator Iterator;
     typedef Vector::const_iterator ConstIterator;
     typedef StandardValueAccessor<value_type> Accessor;
-    
+
     Vector vector_;
 
     ArrayVectorTest()
     {}
-    
+
     void testAccessor()
     {
         vector_.resize(3, 0);
         Iterator i = vector_.begin();
         ConstIterator ci = const_cast<Vector const &>(vector_).begin();
-        
+
         StandardValueAccessor<value_type> sva;
         StandardConstValueAccessor<value_type> scva;
         sva.set(3, i);
@@ -83,7 +91,7 @@ struct ArrayVectorTest
         shouldEqual(sva(i, 2), 5);
         shouldEqual(scva(i, 2), 5);
         shouldEqual(scva(ci, 2), 5);
-        
+
         StandardAccessor<value_type> sa;
         StandardConstAccessor<value_type> sca;
         sa.set(6, i);
@@ -101,12 +109,12 @@ struct ArrayVectorTest
         shouldEqual(sa(i, 2), 8);
         shouldEqual(sca(i, 2), 8);
         shouldEqual(sca(ci, 2), 8);
-        
+
         Vector varray[] = { vector_, vector_, vector_ };
         Vector  * v = varray;
         Vector const * cv = varray;
         int k;
-        
+
         VectorComponentAccessor<Vector> vca(0);
         for(k = 0; k<2; ++k, vca.setIndex(k))
         {
@@ -123,7 +131,7 @@ struct ArrayVectorTest
             shouldEqual(v[1][k], 3 + k);
             shouldEqual(v[2][k], 3 + k);
         }
-        
+
         VectorComponentValueAccessor<Vector> vcva(0);
         for(k = 0; k<2; ++k, vcva.setIndex(k))
         {
@@ -209,16 +217,37 @@ struct ArrayVectorTest
     void testBackInsertion()
     {
         static value_type data[] = { 0, 1, 2, 3, 4 };
-        
+
         shouldEqual(vector_.size(), 0u);
-        
+
         Accessor a;
         copyLine(data, data + 5, a, std::back_inserter(vector_), a);
-        
+
         shouldEqual(vector_.size(), 5u);
         shouldEqualSequence(vector_.begin(), vector_.end(), data);
     }
 
+    void testBackInsertion_failedOnVC14()
+    {
+        // regression test for bug appearing with VC14,
+        // see https://github.com/ukoethe/vigra/issues/256
+
+        shouldEqual(vector_.size(), 0u);
+
+        // the bug is triggered when reserve()ing a capacity of 1024,
+        // which results in a memory block of 4096 bytes and thus
+        // reaches a "big allocation" threshold in VC14's
+        // std::allocator
+        const unsigned int N = 1030u;
+        const value_type value = 42;
+
+        std::fill_n(std::back_inserter(vector_), N, value);
+
+        shouldEqual(vector_.size(), N);
+        shouldEqual(vector_[0], value);
+        shouldEqual(vector_[N-1], value);
+    }
+
     void testAmbiguousConstructor()
     {
         ArrayVector<std::ptrdiff_t> a(2, std::ptrdiff_t(1));
@@ -226,6 +255,9 @@ struct ArrayVectorTest
     }
 };
 
+
+
+
 struct BucketQueueTest
 {
     struct Priority
@@ -235,10 +267,10 @@ struct BucketQueueTest
             return (int)v;
         }
     };
-    
+
     ArrayVector<double> data;
     ArrayVector<int> idata;
-    
+
     BucketQueueTest()
     {
         data.push_back(1.1);
@@ -247,76 +279,76 @@ struct BucketQueueTest
         data.push_back(2.2);
         data.push_back(3.6);
         data.push_back(4.5);
-        
+
         idata.resize(data.size());
         std::transform(data.begin(), data.end(), idata.begin(), Priority());
     }
-    
+
     void testDescending()
     {
         std::priority_queue<int> queue;
         BucketQueue<int> bqueue;
-        
+
         for(unsigned int k=0; k<idata.size(); ++k)
         {
             queue.push(idata[k]);
             bqueue.push(idata[k], idata[k]);
         }
-        
+
         shouldEqual(idata.size(), bqueue.size());
         shouldEqual(false, bqueue.empty());
-        
+
         for(unsigned int k=0; k<idata.size(); ++k)
         {
             shouldEqual(queue.top(), bqueue.top());
             queue.pop();
             bqueue.pop();
         }
-        
+
         shouldEqual(0u, bqueue.size());
-        shouldEqual(true, bqueue.empty());        
+        shouldEqual(true, bqueue.empty());
     }
-    
+
     void testAscending()
     {
         std::priority_queue<int, std::vector<int>, std::greater<int> > queue;
         BucketQueue<int, true> bqueue;
-        
+
         for(unsigned int k=0; k<idata.size(); ++k)
         {
             queue.push(idata[k]);
             bqueue.push(idata[k], idata[k]);
         }
-        
+
         shouldEqual(idata.size(), bqueue.size());
         shouldEqual(false, bqueue.empty());
-        
+
         for(unsigned int k=0; k<idata.size(); ++k)
         {
             shouldEqual(queue.top(), bqueue.top());
             queue.pop();
             bqueue.pop();
         }
-        
+
         shouldEqual(0u, bqueue.size());
-        shouldEqual(true, bqueue.empty());        
+        shouldEqual(true, bqueue.empty());
     }
-    
+
     void testDescendingMapped()
     {
         Priority priority;
         std::priority_queue<int> queue;
         MappedBucketQueue<double, Priority> bqueue;
-        
+
         for(unsigned int k=0; k<data.size(); ++k)
         {
             queue.push(idata[k]);
             bqueue.push(data[k]);
         }
-        
+
         shouldEqual(data.size(), bqueue.size());
         shouldEqual(false, bqueue.empty());
-        
+
         for(unsigned int k=0; k<data.size(); ++k)
         {
             shouldEqual(queue.top(), priority(bqueue.top()));
@@ -332,26 +364,26 @@ struct BucketQueueTest
             queue.pop();
             bqueue.pop();
         }
-        
+
         shouldEqual(0u, bqueue.size());
-        shouldEqual(true, bqueue.empty());        
+        shouldEqual(true, bqueue.empty());
     }
-    
+
     void testAscendingMapped()
     {
         Priority priority;
         std::priority_queue<int, std::vector<int>, std::greater<int> > queue;
         MappedBucketQueue<double, Priority, true> bqueue;
-        
+
         for(unsigned int k=0; k<data.size(); ++k)
         {
             queue.push(idata[k]);
             bqueue.push(data[k]);
         }
-        
+
         shouldEqual(data.size(), bqueue.size());
         shouldEqual(false, bqueue.empty());
-        
+
         for(unsigned int k=0; k<data.size(); ++k)
         {
             shouldEqual(queue.top(), priority(bqueue.top()));
@@ -367,12 +399,677 @@ struct BucketQueueTest
             queue.pop();
             bqueue.pop();
         }
-        
+
         shouldEqual(0u, bqueue.size());
-        shouldEqual(true, bqueue.empty());        
+        shouldEqual(true, bqueue.empty());
+    }
+};
+
+
+struct ChangeablePriorityQueueTest
+{
+    typedef ChangeablePriorityQueue<float, std::less<float>    > MinQueueType;
+    typedef ChangeablePriorityQueue<float, std::greater<float> > MaxQueueType;
+
+    ChangeablePriorityQueueTest()
+    {
+
+    }
+
+
+    void testMinQueue(){
+        const float tol=0.001f;
+        {
+            MinQueueType q(4);
+
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => NONE
+            // 2 => NONE
+            // 3 => NONE
+            should(q.empty());
+            shouldEqual(q.size(),0);
+            should(!q.contains(0));
+            should(!q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+
+
+
+            q.push(0,3.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => NONE
+            // 2 => NONE
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),1);
+            should( q.contains(0));
+            should(!q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            //shouldEqualTolerance(q.priority(1),3.0, tol);
+            //shouldEqualTolerance(q.priority(2),3.0, tol);
+            //shouldEqualTolerance(q.priority(3),3.0, tol);
+            shouldEqual(q.top(),0);
+            shouldEqualTolerance(q.topPriority(),3.0,tol);
+
+
+            q.push(2,2.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => NONE
+            // 2 => 2.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),2);
+            should( q.contains(0));
+            should(!q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            //shouldEqualTolerance(q.priority(1),3.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),3.0, tol);
+            shouldEqual(q.top(),2);
+            shouldEqualTolerance(q.topPriority(),2.0,tol);
+
+
+            q.push(1,3.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 3.0
+            // 2 => 2.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),3);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),3.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),3.0, tol);
+            shouldEqual(q.top(),2);
+            shouldEqualTolerance(q.topPriority(),2.0,tol);
+
+
+            q.push(3,0.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 3.0
+            // 2 => 2.0
+            // 3 => 0.0
+            should(!q.empty());
+            shouldEqual(q.size(),4);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should( q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),3.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            shouldEqualTolerance(q.priority(3),0.0, tol);
+            shouldEqual(q.top(),3);
+            shouldEqualTolerance(q.topPriority(),0.0,tol);
+
+            q.pop();
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 3.0
+            // 2 => 2.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),3);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),3.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),0.0, 0.01);
+            shouldEqual(q.top(),2);
+            shouldEqualTolerance(q.topPriority(),2.0,tol);
+
+
+            q.push(1,1.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 1.0
+            // 2 => 2.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),3);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),1.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),0.0, 0.01);
+            shouldEqual(q.top(),1);
+            shouldEqualTolerance(q.topPriority(),1.0,tol);
+
+            q.push(1,4.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 4.0
+            // 2 => 2.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),3);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),0.0, 0.01);
+            shouldEqual(q.top(),2);
+            shouldEqualTolerance(q.topPriority(),2.0,tol);
+
+
+            q.push(0,1.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 1.0
+            // 1 => 4.0
+            // 2 => 2.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),3);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),1.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),0.0, 0.01);
+            shouldEqual(q.top(),0);
+            shouldEqualTolerance(q.topPriority(),1.0,tol);
+
+
+            q.pop();
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => 4.0
+            // 2 => 2.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),2);
+            should(!q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            //shouldEqualTolerance(q.priority(0),1.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),0.0, 0.01);
+            shouldEqual(q.top(),2);
+            shouldEqualTolerance(q.topPriority(),2.0,tol);
+
+
+            q.pop();
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => 4.0
+            // 2 => NONE
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),1);
+            should(!q.contains(0));
+            should( q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+            //shouldEqualTolerance(q.priority(0),1.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            //shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),0.0, 0.01);
+            shouldEqual(q.top(),1);
+            shouldEqualTolerance(q.topPriority(),4.0,tol);
+
+
+            q.pop();
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => NONE
+            // 2 => NONE
+            // 3 => NONE
+            should(q.empty());
+            shouldEqual(q.size(),0);
+            should(!q.contains(0));
+            should(!q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+            //shouldEqualTolerance(q.priority(0),1.0, tol);
+            //shouldEqualTolerance(q.priority(1),4.0, tol);
+            //shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),0.0, 0.01);
+            //shouldEqual(q.top(),1);
+            //shouldEqualTolerance(q.topPriority(),4.0,tol);
+
+        }
+
+    }
+
+    void testMaxQueue(){
+        const float tol=0.001f;
+        {
+            MaxQueueType q(4);
+
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => NONE
+            // 2 => NONE
+            // 3 => NONE
+            should(q.empty());
+            shouldEqual(q.size(),0);
+            should(!q.contains(0));
+            should(!q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+
+
+
+            q.push(0,3.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => NONE
+            // 2 => NONE
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),1);
+            should( q.contains(0));
+            should(!q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            //shouldEqualTolerance(q.priority(1),3.0, tol);
+            //shouldEqualTolerance(q.priority(2),3.0, tol);
+            //shouldEqualTolerance(q.priority(3),3.0, tol);
+            shouldEqual(q.top(),0);
+            shouldEqualTolerance(q.topPriority(),3.0,tol);
+
+
+            q.push(2,2.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => NONE
+            // 2 => 2.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),2);
+            should( q.contains(0));
+            should(!q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            //shouldEqualTolerance(q.priority(1),3.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),3.0, tol);
+            shouldEqual(q.top(),0);
+            shouldEqualTolerance(q.topPriority(),3.0,tol);
+
+
+            q.push(1,4.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 4.0
+            // 2 => 2.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),3);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            //shouldEqualTolerance(q.priority(3),3.0, tol);
+            shouldEqual(q.top(),1);
+            shouldEqualTolerance(q.topPriority(),4.0,tol);
+
+
+            q.push(3,5.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 4.0
+            // 2 => 2.0
+            // 3 => 5.0
+            should(!q.empty());
+            shouldEqual(q.size(),4);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should( q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            shouldEqualTolerance(q.priority(3),5.0, tol);
+            shouldEqual(q.top(),3);
+            shouldEqualTolerance(q.topPriority(),5.0,tol);
+
+
+            q.push(3,2.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 4.0
+            // 2 => 2.0
+            // 3 => 2.0
+            should(!q.empty());
+            shouldEqual(q.size(),4);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should( q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            shouldEqualTolerance(q.priority(3),2.0, tol);
+            shouldEqual(q.top(),1);
+            shouldEqualTolerance(q.topPriority(),4.0,tol);
+
+
+            q.push(1,0.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 0.0
+            // 2 => 2.0
+            // 3 => 2.0
+            should(!q.empty());
+            shouldEqual(q.size(),4);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should( q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),0.0, tol);
+            shouldEqualTolerance(q.priority(2),2.0, tol);
+            shouldEqualTolerance(q.priority(3),2.0, tol);
+            shouldEqual(q.top(),0);
+            shouldEqualTolerance(q.topPriority(),3.0,tol);
+
+            q.push(2,5.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 0.0
+            // 2 => 5.0
+            // 3 => 2.0
+            should(!q.empty());
+            shouldEqual(q.size(),4);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should( q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),0.0, tol);
+            shouldEqualTolerance(q.priority(2),5.0, tol);
+            shouldEqualTolerance(q.priority(3),2.0, tol);
+            shouldEqual(q.top(),2);
+            shouldEqualTolerance(q.topPriority(),5.0,tol);
+
+            q.push(3,1.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 0.0
+            // 2 => 5.0
+            // 3 => 1.0
+            should(!q.empty());
+            shouldEqual(q.size(),4);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should( q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),0.0, tol);
+            shouldEqualTolerance(q.priority(2),5.0, tol);
+            shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),2);
+            shouldEqualTolerance(q.topPriority(),5.0,tol);
+
+
+            q.pop();
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 3.0
+            // 1 => 0.0
+            // 2 => NONE
+            // 3 => 1.0
+            should(!q.empty());
+            shouldEqual(q.size(),3);
+            should( q.contains(0));
+            should( q.contains(1));
+            should(!q.contains(2));
+            should( q.contains(3));
+            shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),0.0, tol);
+            //shouldEqualTolerance(q.priority(2),5.0, tol);
+            shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),0);
+            shouldEqualTolerance(q.topPriority(),3.0,tol);
+
+
+
+            q.pop();
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => 0.0
+            // 2 => NONE
+            // 3 => 1.0
+            should(!q.empty());
+            shouldEqual(q.size(),2);
+            should(!q.contains(0));
+            should( q.contains(1));
+            should(!q.contains(2));
+            should( q.contains(3));
+            //shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),0.0, tol);
+            //shouldEqualTolerance(q.priority(2),5.0, tol);
+            shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),3);
+            shouldEqualTolerance(q.topPriority(),1.0,tol);
+
+
+            q.pop();
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => 0.0
+            // 2 => NONE
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),1);
+            should(!q.contains(0));
+            should( q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+            //shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),0.0, tol);
+            //shouldEqualTolerance(q.priority(2),5.0, tol);
+            //shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),1);
+            shouldEqualTolerance(q.topPriority(),0.0,tol);
+
+            q.pop();
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => NONE
+            // 2 => NONE
+            // 3 => NONE
+            should(q.empty());
+            shouldEqual(q.size(),0);
+            should(!q.contains(0));
+            should(!q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+            //shouldEqualTolerance(q.priority(0),3.0, tol);
+            //shouldEqualTolerance(q.priority(1),0.0, tol);
+            //shouldEqualTolerance(q.priority(2),5.0, tol);
+            //shouldEqualTolerance(q.priority(3),1.0, tol);
+            //shouldEqual(q.top(),1);
+            //shouldEqualTolerance(q.topPriority(),0.0,tol);
+
+            q.push(2,1.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => NONE
+            // 2 => 1.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),1);
+            should(!q.contains(0));
+            should(!q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            //shouldEqualTolerance(q.priority(0),3.0, tol);
+            //shouldEqualTolerance(q.priority(1),0.0, tol);
+            shouldEqualTolerance(q.priority(2),1.0, tol);
+            //shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),2);
+            shouldEqualTolerance(q.topPriority(),1.0,tol);
+
+
+            q.push(2,3.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => NONE
+            // 2 => 3.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),1);
+            should(!q.contains(0));
+            should(!q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            //shouldEqualTolerance(q.priority(0),3.0, tol);
+            //shouldEqualTolerance(q.priority(1),0.0, tol);
+            shouldEqualTolerance(q.priority(2),3.0, tol);
+            //shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),2);
+            shouldEqualTolerance(q.topPriority(),3.0,tol);
+
+
+            q.push(1,4.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => NONE
+            // 1 => 4.0
+            // 2 => 3.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),2);
+            should(!q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            //shouldEqualTolerance(q.priority(0),3.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            shouldEqualTolerance(q.priority(2),3.0, tol);
+            //shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),1);
+            shouldEqualTolerance(q.topPriority(),4.0,tol);
+
+
+            q.push(0,2.0);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 2.0
+            // 1 => 4.0
+            // 2 => 3.0
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),3);
+            should( q.contains(0));
+            should( q.contains(1));
+            should( q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),2.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            shouldEqualTolerance(q.priority(2),3.0, tol);
+            //shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),1);
+            shouldEqualTolerance(q.topPriority(),4.0,tol);
+
+
+            q.deleteItem(2);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 2.0
+            // 1 => 4.0
+            // 2 => NONE
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),2);
+            should( q.contains(0));
+            should( q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),2.0, tol);
+            shouldEqualTolerance(q.priority(1),4.0, tol);
+            //shouldEqualTolerance(q.priority(2),3.0, tol);
+            //shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),1);
+            shouldEqualTolerance(q.topPriority(),4.0,tol);
+
+
+            q.deleteItem(1);
+            // CURRENT VALUES
+            //-----------------
+            // 0 => 2.0
+            // 1 => 4.0
+            // 2 => NONE
+            // 3 => NONE
+            should(!q.empty());
+            shouldEqual(q.size(),1);
+            should( q.contains(0));
+            should(!q.contains(1));
+            should(!q.contains(2));
+            should(!q.contains(3));
+            shouldEqualTolerance(q.priority(0),2.0, tol);
+            //shouldEqualTolerance(q.priority(1),4.0, tol);
+            //shouldEqualTolerance(q.priority(2),3.0, tol);
+            //shouldEqualTolerance(q.priority(3),1.0, tol);
+            shouldEqual(q.top(),0);
+            shouldEqualTolerance(q.topPriority(),2.0,tol);
+
+        }
+
     }
 };
 
+
+
 struct SizedIntTest
 {
     void testSizedInt()
@@ -392,25 +1089,25 @@ struct MetaprogrammingTest
 {
     struct TrueResult {};
     struct FalseResult {};
-    
-    struct Derived 
-    : public TrueResult 
+
+    struct Derived
+    : public TrueResult
     {
         typedef TrueResult result_type;
         typedef TrueResult value_type;
     };
-    
+
     void testInt()
     {
         shouldEqual(MetaInt<1>::value, 1);
         shouldEqual((MetaMax<1,2>::value), 2);
         shouldEqual((MetaMin<1,2>::value), 1);
     }
- 
+
     void testLogic()
     {
         shouldEqual(VigraTrueType::value, true);
-        shouldEqual(VigraFalseType::value, false);        
+        shouldEqual(VigraFalseType::value, false);
         should(typeid(Not<VigraFalseType>::type) == typeid(VigraTrueType));
         should(typeid(Not<VigraTrueType>::type) == typeid(VigraFalseType));
         should(typeid(And<VigraTrueType, VigraTrueType>::type) == typeid(VigraTrueType));
@@ -426,7 +1123,7 @@ struct MetaprogrammingTest
         should(typeid(IfBool<true, TrueResult, FalseResult>::type) == typeid(TrueResult));
         should(typeid(IfBool<false, TrueResult, FalseResult>::type) == typeid(FalseResult));
     }
- 
+
     void testTypeTools()
     {
         should(typeid(IsSameType<TrueResult, TrueResult>::type) == typeid(VigraTrueType));
@@ -458,12 +1155,56 @@ struct MetaprogrammingTest
         should(typeid(UnqualifiedType<int*&>::type) == typeid(int));
         should(typeid(UnqualifiedType<const int*&>::type) == typeid(int));
     }
+
+#if 0
+    struct FinallyTester
+    {
+        mutable int & v_;
+
+        FinallyTester(int & v)
+            : v_(v)
+        {}
+
+        void sq() const
+        {
+            v_ = v_*v_;
+        }
+    };
+#endif
+
+    void testFinally()
+    {
+        std::cout << "testFinally() is disabled because many compilers do not yet support it." << std::endl;
+#if 0
+        int v = 0;
+        {
+            FinallyTester finally_tester(v);
+            VIGRA_FINALLY(finally_tester.sq());
+
+            VIGRA_FINALLY({
+                v = 3;
+            });
+            shouldEqual(v, 0);
+        }
+        shouldEqual(v, 9);
+
+        try {
+            VIGRA_FINALLY(v = 2);
+
+            throw std::runtime_error("");
+
+            VIGRA_FINALLY(v = 3);
+        }
+        catch(std::runtime_error &) {}
+        shouldEqual(v, 2);
+#endif
+    }
 };
 
 void stringTest()
 {
     std::string s;
-    s << "Hallo " << 1 << " " << 2.0 << " " << false;
+    s = s << "Hallo " << 1 << " " << 2.0 << " " << false;
     shouldEqual(s, std::string("Hallo 1 2 0"));
 
     shouldEqual(asString(1), "1");
@@ -474,12 +1215,322 @@ void stringTest()
     shouldEqual(normalizeString("AluFr iNsta< Z89>"), "alufrinsta<z89>");
 }
 
+struct CompressionTest
+{
+    ArrayVector<char> data;
+
+    CompressionTest()
+    : data(1000000)
+    {
+        linearSequence(data.begin(), data.end(), 0);
+    }
+
+    void testZLIB()
+    {
+        ArrayVector<char> compressed;
+    #ifdef HasZLIB
+        compress(data.begin(), data.size(), compressed, ZLIB);
+
+        shouldEqual(compressed.size(), 4206);
+
+        ArrayVector<char> decompressed(data.size());
+
+        uncompress(compressed.begin(), compressed.size(),
+                   decompressed.begin(), decompressed.size(), ZLIB);
+
+        shouldEqualSequence(data.begin(), data.end(), decompressed.begin());
+    #else
+        try
+        {
+            compress(data.begin(), data.size(), compressed, ZLIB);
+            failTest("missing ZLIB did not throw exception.");
+        }
+        catch(ContractViolation & c)
+        {
+            std::string expected("\nPrecondition violation!\ncompress(): VIGRA was compiled without ZLIB compression.");
+            std::string message(c.what());
+            should(0 == expected.compare(message.substr(0,expected.size())));
+        }
+
+    #endif
+    }
+
+    void testLZ4()
+    {
+        ArrayVector<char> compressed;
+        compress(data.begin(), data.size(), compressed, LZ4);
+
+        shouldEqual(compressed.size(), 4187);
+
+        ArrayVector<char> decompressed(data.size());
+
+        uncompress(compressed.begin(), compressed.size(),
+                   decompressed.begin(), decompressed.size(), LZ4);
+
+        shouldEqualSequence(data.begin(), data.end(), decompressed.begin());
+    }
+
+    void testNoCompression()
+    {
+        ArrayVector<char> compressed;
+        compress(data.begin(), data.size(), compressed, NO_COMPRESSION);
+
+        shouldEqual(compressed.size(), data.size());
+
+        ArrayVector<char> decompressed(data.size());
+
+        uncompress(compressed.begin(), compressed.size(),
+                   decompressed.begin(), decompressed.size(), NO_COMPRESSION);
+
+        shouldEqualSequence(data.begin(), data.end(), decompressed.begin());
+    }
+};
+
+
+struct MultiBlockingTest
+{
+    void test2d()
+    {
+        typedef MultiBlocking<2> Mb;
+        typedef Mb::Shape Shape;
+        typedef Mb::Block Block;
+        typedef Mb::Block Block;
+
+        typedef Mb::BlockWithBorder BlockWithBorder;
+        typedef Mb::BlockWithBorderIter BlockWithBorderIter;
+        typedef Mb::BlockIter BlockIter;
+        {
+            Shape shape(10,11), blockShape(4,5);
+            Mb blocking(shape, blockShape);
+            shouldEqual(blocking.numBlocks(),9);
+
+
+            BlockWithBorderIter bwbIter  = blocking.blockWithBorderBegin(Shape(1));
+            BlockIter bIter = blocking.blockBegin();
+
+            // get the first block
+            shouldEqual(bIter[0].begin()[0], 0);
+            shouldEqual(bIter[0].begin()[1], 0);
+            shouldEqual(bIter[0].end()[0], 4);
+            shouldEqual(bIter[0].end()[1], 5);
+
+            // get the second block
+            const Block b1 = bIter[1];
+            shouldEqual(b1.begin()[0], 4);
+            shouldEqual(b1.begin()[1], 0);
+            shouldEqual(b1.end()[0], 8);
+            shouldEqual(b1.end()[1], 5);
+
+            // get the third block
+            Block b2 = bIter[2];
+            shouldEqual(b2.begin()[0], 8);
+            shouldEqual(b2.begin()[1], 0);
+            shouldEqual(b2.end()[0], 10);
+            shouldEqual(b2.end()[1], 5);
+
+            //  first block with border
+            const BlockWithBorder bb0 = bwbIter[0];
+            shouldEqual(bb0.core().begin()[0], 0);
+            shouldEqual(bb0.core().begin()[1], 0);
+            shouldEqual(bb0.core().end()[0], 4);
+            shouldEqual(bb0.core().end()[1], 5);
+
+            shouldEqual(bb0.border().begin()[0], 0);
+            shouldEqual(bb0.border().begin()[1], 0);
+            shouldEqual(bb0.border().end()[0], 5);
+            shouldEqual(bb0.border().end()[1], 6);
+
+            //  second block with border
+            const BlockWithBorder bb1 = bwbIter[1];
+            shouldEqual(bb1.core().begin()[0], 4);
+            shouldEqual(bb1.core().begin()[1], 0);
+            shouldEqual(bb1.core().end()[0], 8);
+            shouldEqual(bb1.core().end()[1], 5);
+
+            shouldEqual(bb1.border().begin()[0], 3);
+            shouldEqual(bb1.border().begin()[1], 0);
+            shouldEqual(bb1.border().end()[0], 9);
+            shouldEqual(bb1.border().end()[1], 6);
+
+            //  third block with border
+            const BlockWithBorder bb2 = bwbIter[2];
+            shouldEqual(bb2.core().begin()[0], 8);
+            shouldEqual(bb2.core().begin()[1], 0);
+            shouldEqual(bb2.core().end()[0], 10);
+            shouldEqual(bb2.core().end()[1], 5);
+
+            shouldEqual(bb2.border().begin()[0], 7);
+            shouldEqual(bb2.border().begin()[1], 0);
+            shouldEqual(bb2.border().end()[0], 10);
+            shouldEqual(bb2.border().end()[1], 6);
+        }
+    }
+
+
+    void test2dWithRoi()
+    {
+        typedef MultiBlocking<2> Mb;
+        typedef Mb::Shape Shape;
+        //typedef Mb::Block Block;
+        typedef Mb::BlockIter BlockIter;
+        //typedef Mb::BlockWithBorder BlockWithBorder;
+        {
+
+
+            Shape shape(13,14), blockShape(4,5), roiBegin(1,2), roiEnd(9,11);
+            Mb blocking(shape, blockShape, roiBegin, roiEnd);
+            shouldEqual(blocking.numBlocks(),4);
+
+            BlockIter bIter = blocking.blockBegin();
+
+            shouldEqual(bIter[0].begin(), Shape(1,2));
+            shouldEqual(bIter[0].end(),   Shape(5,7));
+            shouldEqual(bIter[1].begin(), Shape(5,2));
+            shouldEqual(bIter[1].end(),   Shape(9,7));
+            shouldEqual(bIter[2].begin(), Shape(1,7));
+            shouldEqual(bIter[2].end(),   Shape(5,11));
+            shouldEqual(bIter[3].begin(), Shape(5,7));
+            shouldEqual(bIter[3].end(),   Shape(9,11));
+        }
+    }
+
+    void test2dIterator()
+    {
+        typedef MultiBlocking<2> Mb;
+        typedef Mb::Shape Shape;
+        //typedef  Mb::Block Block;
+        typedef Mb::BlockWithBorder BlockWithBorder;
+        typedef  Mb::BlockWithBorderIter BlockWithBorderIter;
+        {
+            Shape shape(13,14), blockShape(4,5), roiBegin(1,2), roiEnd(9,11), width(2,3);
+            Mb blocking(shape, blockShape, roiBegin, roiEnd);
+            shouldEqual(blocking.numBlocks(),4);
+
+            {
+                std::vector<BlockWithBorder> bwbVec(blocking.blockWithBorderBegin(width),
+                                                    blocking.blockWithBorderEnd(width));
+                shouldEqual(bwbVec.size(),4);
+            }
+
+            BlockWithBorderIter begin  = blocking.blockWithBorderBegin(width);
+            BlockWithBorderIter end    = begin.getEndIterator();
+            shouldEqual(begin+4==end, true);
+        }
+    }
+};
+
+struct AnyTest
+{
+    void test()
+    {
+        Any a(10), b = a, c;
+
+        should(bool(a));
+        shouldNot(bool(c));
+        should(c == false);
+        should(false == c);
+        shouldNot(a.empty());
+        should(c.empty());
+        should(a == b);
+        shouldNot(a != b);
+        shouldNot(a == c);
+        should(a != c);
+
+        should(a.is_type<int>());
+        should(a.is_readable<int>());
+        should(a.is_readable<float>());
+        shouldNot(c.is_type<int>());
+
+        c = a;
+        should(a == c);
+        shouldNot(a != c);
+        should(c.is_type<int>());
+
+        shouldEqual(a.get<int>(), 10);
+        shouldEqual(b.get<int>(), 10);
+
+        b.release();
+        shouldNot(bool(b));
+        should(b.empty());
+
+        try {
+            a.get<float>();
+            failTest("no exception thrown");
+        }
+        catch(std::exception & e)
+        {
+            std::string expected("\nPrecondition violation!\nAny::get(): object is not an instance of the target type.");
+            std::string message(e.what());
+            should(0 == expected.compare(message.substr(0,expected.size())));
+        }
+
+        try {
+            b.get<int>();
+            failTest("no exception thrown");
+        }
+        catch(std::exception & e)
+        {
+            std::string expected("\nPrecondition violation!\nAny::get(): object empty.");
+            std::string message(e.what());
+            should(0 == expected.compare(message.substr(0,expected.size())));
+        }
+
+        shouldEqual(a.read<unsigned int>(), 10u);
+        shouldEqual(a.read<float>(), 10.0f);
+        shouldEqual(a.read<double>(), 10.0);
+
+        a.get<int>() = 11;
+        shouldEqual(a.get<int>(), 11);
+
+        a = 12.25;
+        shouldEqual(a.get<double>(), 12.25);
+
+        try {
+            a.get<int>();
+            failTest("no exception thrown");
+        }
+        catch(std::exception & e)
+        {
+            std::string expected("\nPrecondition violation!\nAny::get(): object is not an instance of the target type.");
+            std::string message(e.what());
+            should(0 == expected.compare(message.substr(0,expected.size())));
+        }
+
+        shouldEqual(a.read<int>(), 12);
+        shouldEqual(a.read<unsigned int>(), 12u);
+        shouldEqual(a.read<float>(), 12.25f);
+
+        swap(a, c);
+        shouldEqual(a.get<int>(), 10);
+        shouldEqual(c.get<double>(), 12.25);
+
+        typedef std::shared_ptr<int> P;
+        Any s(P(new int(5))), t(s);
+        shouldEqual(s.get<P>().get(), t.get<P>().get());
+        shouldEqual(*(s.get<P>()), 5);
+        try {
+            s.read<int>();
+            failTest("no exception thrown");
+        }
+        catch(std::exception & e)
+        {
+            std::string expected("\nPrecondition violation!\nAny::read(): object is not covertible to the target type.");
+            std::string message(e.what());
+            should(0 == expected.compare(message.substr(0,expected.size())));
+        }
+    }
+};
+
 struct UtilitiesTestSuite
 : public vigra::test_suite
 {
     UtilitiesTestSuite()
     : vigra::test_suite("UtilitiesTestSuite")
     {
+        add( testCase( &MultiBlockingTest::test2d));
+        add( testCase( &MultiBlockingTest::test2dWithRoi));
+        add( testCase( &MultiBlockingTest::test2dIterator));
+
         add( testCase( &ArrayVectorTest::testAccessor));
         add( testCase( &ArrayVectorTest::testBackInsertion));
         add( testCase( &ArrayVectorTest::testAmbiguousConstructor));
@@ -487,11 +1538,19 @@ struct UtilitiesTestSuite
         add( testCase( &BucketQueueTest::testAscending));
         add( testCase( &BucketQueueTest::testDescendingMapped));
         add( testCase( &BucketQueueTest::testAscendingMapped));
+        add( testCase( &ChangeablePriorityQueueTest::testMinQueue));
+        add( testCase( &ChangeablePriorityQueueTest::testMaxQueue));
         add( testCase( &SizedIntTest::testSizedInt));
         add( testCase( &MetaprogrammingTest::testInt));
         add( testCase( &MetaprogrammingTest::testLogic));
         add( testCase( &MetaprogrammingTest::testTypeTools));
+        add( testCase( &MetaprogrammingTest::testFinally));
         add( testCase( &stringTest));
+        add( testCase( &CompressionTest::testZLIB));
+        add( testCase( &CompressionTest::testLZ4));
+        add( testCase( &CompressionTest::testNoCompression));
+
+        add( testCase( &AnyTest::test));
     }
 };
 
diff --git a/test/volumelabeling/test.cxx b/test/volumelabeling/test.cxx
index f7ab6dd..2281c33 100644
--- a/test/volumelabeling/test.cxx
+++ b/test/volumelabeling/test.cxx
@@ -267,7 +267,12 @@ struct VolumeLabelingTest
 
         should(18 == labelMultiArray(vol4, res2, DirectNeighborhood));
         should(res == res2);
-    }
+ 
+        res2 = 0;
+        should(18 == labelMultiArray(vol4, res2, 
+                                     LabelOptions().neighborhood(DirectNeighborhood)));
+        should(res == res2);
+   }
 
     void labelingSixWithBackgroundTest1()
     {
@@ -295,6 +300,11 @@ struct VolumeLabelingTest
         should(res == res2);
 
         res2 = 0;
+        should(4 == labelMultiArray(vol5, res2, 
+                                    LabelOptions().neighborhood(DirectNeighborhood).ignoreBackgroundValue(0)));
+        should(res == res2);
+
+        res2 = 0;
         should(4 == labelVolumeWithBackground(vol5, res2, NeighborCode3DSix(), 0));
         should(res == res2);
     }
diff --git a/test/watersheds3d/test.cxx b/test/watersheds3d/test.cxx
index 98410b9..fa0b3d5 100644
--- a/test/watersheds3d/test.cxx
+++ b/test/watersheds3d/test.cxx
@@ -465,8 +465,92 @@ struct Watersheds3dTest
 
         labelVolume2.init(0);
         max_region_label = watershedsMultiArray(vol, labelVolume2, DirectNeighborhood, WatershedOptions().unionFind());
-        shouldEqual(8, max_region_label);
-        should(labelVolume == labelVolume2);
+        
+        static const int correct_direct_labeling_raw[] =
+        {
+            1, 1, 1, 1, 2, 2, 2, 2, 
+            1, 1, 1, 1, 2, 2, 2, 2, 
+            1, 1, 3, 3, 4, 4, 2, 2, 
+            1, 1, 3, 3, 4, 4, 2, 2, 
+            5, 5, 6, 6, 7, 7, 8, 8, 
+            5, 5, 6, 6, 7, 7, 8, 8, 
+            5, 5, 5, 5, 8, 8, 8, 8, 
+            5, 5, 5, 5, 8, 8, 8, 8, 
+
+            1, 1, 1, 1, 2, 2, 2, 2, 
+            1, 1, 1, 1, 2, 2, 2, 2, 
+            1, 1, 3, 3, 4, 4, 2, 2, 
+            1, 1, 3, 3, 4, 4, 2, 2, 
+            5, 5, 6, 6, 7, 7, 8, 8, 
+            5, 5, 6, 6, 7, 7, 8, 8, 
+            5, 5, 5, 5, 8, 8, 8, 8, 
+            5, 5, 5, 5, 8, 8, 8, 8, 
+
+            1, 1, 3, 3, 4, 4, 2, 2, 
+            1, 1, 3, 3, 4, 4, 2, 2, 
+            3, 3, 3, 3, 4, 4, 4, 4, 
+            3, 3, 3, 3, 4, 4, 4, 4, 
+            6, 6, 6, 6, 7, 7, 7, 7, 
+            6, 6, 6, 6, 7, 7, 7, 7, 
+            5, 5, 6, 6, 7, 7, 8, 8, 
+            5, 5, 6, 6, 7, 7, 8, 8, 
+
+            1, 1, 3, 3, 4, 4, 2, 2, 
+            1, 1, 3, 3, 4, 4, 2, 2, 
+            3, 3, 3, 3, 4, 4, 4, 4, 
+            3, 3, 3, 3, 4, 4, 4, 4, 
+            6, 6, 6, 6, 7, 7, 7, 7, 
+            6, 6, 6, 6, 7, 7, 7, 7, 
+            5, 5, 6, 6, 7, 7, 8, 8, 
+            5, 5, 6, 6, 7, 7, 8, 8, 
+
+            9, 9, 10, 10, 11, 11, 12, 12, 
+            9, 9, 10, 10, 11, 11, 12, 12, 
+            10, 10, 10, 10, 11, 11, 11, 11, 
+            10, 10, 10, 10, 11, 11, 11, 11, 
+            13, 13, 13, 13, 14, 14, 14, 14, 
+            13, 13, 13, 13, 14, 14, 14, 14, 
+            15, 15, 13, 13, 14, 14, 16, 16, 
+            15, 15, 13, 13, 14, 14, 16, 16, 
+
+            9, 9, 10, 10, 11, 11, 12, 12, 
+            9, 9, 10, 10, 11, 11, 12, 12, 
+            10, 10, 10, 10, 11, 11, 11, 11, 
+            10, 10, 10, 10, 11, 11, 11, 11, 
+            13, 13, 13, 13, 14, 14, 14, 14, 
+            13, 13, 13, 13, 14, 14, 14, 14, 
+            15, 15, 13, 13, 14, 14, 16, 16, 
+            15, 15, 13, 13, 14, 14, 16, 16, 
+
+            9, 9, 9, 9, 12, 12, 12, 12, 
+            9, 9, 9, 9, 12, 12, 12, 12, 
+            9, 9, 10, 10, 11, 11, 12, 12, 
+            9, 9, 10, 10, 11, 11, 12, 12, 
+            15, 15, 13, 13, 14, 14, 16, 16, 
+            15, 15, 13, 13, 14, 14, 16, 16, 
+            15, 15, 15, 15, 16, 16, 16, 16, 
+            15, 15, 15, 15, 16, 16, 16, 16, 
+
+            9, 9, 9, 9, 12, 12, 12, 12, 
+            9, 9, 9, 9, 12, 12, 12, 12, 
+            9, 9, 10, 10, 11, 11, 12, 12, 
+            9, 9, 10, 10, 11, 11, 12, 12, 
+            15, 15, 13, 13, 14, 14, 16, 16, 
+            15, 15, 13, 13, 14, 14, 16, 16, 
+            15, 15, 15, 15, 16, 16, 16, 16, 
+            15, 15, 15, 15, 16, 16, 16, 16
+        };
+        i=correct_direct_labeling_raw;
+        IntVolume correct_direct_labeling(Shape3(w,h,d));
+        for(IntVolume::iterator iter=correct_direct_labeling.begin(); 
+            iter!=correct_direct_labeling.end();
+            ++iter, ++i)
+        {
+            *iter=*i;
+        }
+
+        shouldEqual(16, max_region_label);
+        should(correct_direct_labeling == labelVolume2);
 
         labelVolume2.init(0);
         max_region_label = watershedsMultiArray(vol, labelVolume2, IndirectNeighborhood, WatershedOptions().unionFind());
diff --git a/vigranumpy/CMakeLists.txt b/vigranumpy/CMakeLists.txt
index 78bec61..19b068b 100644
--- a/vigranumpy/CMakeLists.txt
+++ b/vigranumpy/CMakeLists.txt
@@ -7,12 +7,6 @@ IF(VIGRANUMPY_DEPENDENCIES_FOUND)
 
     INCLUDE_DIRECTORIES(${VIGRANUMPY_INCLUDE_DIRS})
 
-    # configure boost's autolink magic to use the right library name
-    # (default on Windows is a mangled name like 'boost_python-vc110-mt-1_51.lib')
-    if("${Boost_PYTHON_LIBRARY}" MATCHES "boost_python\\.lib")
-        ADD_DEFINITIONS(-DBOOST_AUTO_LINK_NOMANGLE)
-    endif()
-        
     IF(HDF5_FOUND)
         ADD_DEFINITIONS(-DHasHDF5 ${HDF5_CPPFLAGS})
         INCLUDE_DIRECTORIES(${HDF5_INCLUDE_DIR})
@@ -24,7 +18,7 @@ IF(VIGRANUMPY_DEPENDENCIES_FOUND)
     IF(MSVC OR MINGW)
         ADD_DEFINITIONS(-DVIGRA_DLL)
     ENDIF ()
-    
+
     include(VIGRA_ADD_NUMPY_MODULE)
 
     ADD_SUBDIRECTORY(src)
@@ -35,44 +29,56 @@ IF(VIGRANUMPY_DEPENDENCIES_FOUND)
     IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/private/CMakeLists.txt)
         ADD_SUBDIRECTORY(private EXCLUDE_FROM_ALL)
     ENDIF()
-    
+
     IF(PYTHON_PLATFORM MATCHES "^windows$")
-        FILE(MAKE_DIRECTORY ${vigranumpy_tmp_dir}/dlls)    
-        GET_TARGET_PROPERTY(VIGRAIMPEX_LOCATION vigraimpex LOCATION)
+        FILE(MAKE_DIRECTORY ${vigranumpy_tmp_dir}/dlls)
         file(RELATIVE_PATH VIGRAIMPEX_DOCDIR ${vigranumpy_tmp_dir} ${DOCDIR})
-        
-        CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in
-                        ${CMAKE_CURRENT_BINARY_DIR}/setup.py
-                        @ONLY)
 
-        add_custom_target(PACKAGE_VIGRANUMPY 
+        if(CMAKE_MAJOR_VERSION LESS 3)
+            GET_TARGET_PROPERTY(VIGRAIMPEX_LOCATION vigraimpex LOCATION)
+            CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.cmake2.in
+                           ${CMAKE_CURRENT_BINARY_DIR}/setup.py
+                           @ONLY)
+        else()
+            CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in
+                           ${CMAKE_CURRENT_BINARY_DIR}/setup.py.in
+                           @ONLY)
+
+            # two-stage file configuration is necessary because certain target
+            # properties are only known at generation time (policy CMP0026)
+            file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/setup.py
+                          INPUT  ${CMAKE_CURRENT_BINARY_DIR}/setup.py.in
+                          CONDITION $<CONFIG:Release>)
+        endif()
+
+        add_custom_target(PACKAGE_VIGRANUMPY
                            COMMAND ${CMAKE_COMMAND} -E copy_directory ${DOCDIR} ${vigranumpy_tmp_dir}/doc
                            COMMAND python setup.py bdist_wininst
                            DEPENDS check
                            WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-                           COMMENT "Creating vigranumpy setup in ${CMAKE_CURRENT_BINARY_DIR}/dist")        
+                           COMMENT "Creating vigranumpy setup in ${CMAKE_CURRENT_BINARY_DIR}/dist")
     ENDIF()
-    
+
     set(VIGRANUMPY_CONFIG_INSTALL_PATH lib${LIB_SUFFIX}/vigranumpy)
-    
+
     set(VIGRANUMPY_INCLUDE_RELATIVE "")
     foreach(PATH ${CMAKE_INSTALL_PREFIX}/include ${VIGRANUMPY_INCLUDE_DIRS})
         file(RELATIVE_PATH RELPATH ${CMAKE_INSTALL_PREFIX}/${VIGRANUMPY_CONFIG_INSTALL_PATH} ${PATH})
         set(VIGRANUMPY_INCLUDE_RELATIVE ${VIGRANUMPY_INCLUDE_RELATIVE} ${RELPATH})
     endforeach(PATH)
-    
+
     set(VIGRANUMPY_LIBRARIES_RELATIVE "")
     foreach(PATH ${VIGRANUMPY_LIBRARIES})
         if(EXISTS ${PATH})
             file(RELATIVE_PATH RELPATH ${CMAKE_INSTALL_PREFIX}/${VIGRANUMPY_CONFIG_INSTALL_PATH} ${PATH})
             set(VIGRANUMPY_LIBRARIES_RELATIVE ${VIGRANUMPY_LIBRARIES_RELATIVE} ${RELPATH})
         else()
-            # If ${PATH} is not referring to a path, it is probably a keyword like 
-            # "optimized" or "debug" (e.g. on the Mac). We then pass it on unchanged. 
+            # If ${PATH} is not referring to a path, it is probably a keyword like
+            # "optimized" or "debug" (e.g. on the Mac). We then pass it on unchanged.
             set(VIGRANUMPY_LIBRARIES_RELATIVE ${VIGRANUMPY_LIBRARIES_RELATIVE} ${PATH})
         endif()
     endforeach(PATH)
-    
+
     CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/config/VigranumpyConfig.cmake.in
             ${PROJECT_BINARY_DIR}/lib/vigranumpy/CMake/VigranumpyConfig.cmake
             @ONLY IMMEDIATE)
diff --git a/vigranumpy/docsrc/CMakeLists.txt b/vigranumpy/docsrc/CMakeLists.txt
index 547cf81..cf98661 100644
--- a/vigranumpy/docsrc/CMakeLists.txt
+++ b/vigranumpy/docsrc/CMakeLists.txt
@@ -20,15 +20,33 @@ IF(PYTHON_SPHINX)
         ${SPHINX_OPTS})
     file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/_static)
     configure_file(_static/vigra-icon.ico ${CMAKE_CURRENT_BINARY_DIR}/_static/vigra-icon.ico COPYONLY)
-    
-    DEPENDENCY_PATH(VIGRAIMPEX_PATH vigraimpex)
-    STRING(REGEX REPLACE "/vigra$" "" VIGRANUMPY_TMP_PATH ${vigranumpy_tmp_dir})   
-    
-    CONFIGURE_FILE(
-        ${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in
-        ${CMAKE_CURRENT_BINARY_DIR}/conf.py
-        @ONLY)
-    
+
+    STRING(REGEX REPLACE "/vigra$" "" VIGRANUMPY_TMP_PATH ${vigranumpy_tmp_dir})
+
+    if(CMAKE_MAJOR_VERSION LESS 3)
+        DEPENDENCY_PATH(VIGRAIMPEX_PATH vigraimpex)
+        CONFIGURE_FILE(
+            ${CMAKE_CURRENT_SOURCE_DIR}/conf.py.cmake2.in
+            ${CMAKE_CURRENT_BINARY_DIR}/conf.py
+            @ONLY)
+    else()
+        CONFIGURE_FILE(
+            ${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in
+            ${CMAKE_CURRENT_BINARY_DIR}/conf.py.in
+            @ONLY)
+
+        # two-stage file configuration is necessary because certain target
+        # properties are only known at generation time (policy CMP0026)
+        if(MSVC)
+            file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/conf.py
+                          INPUT  ${CMAKE_CURRENT_BINARY_DIR}/conf.py.in
+                          CONDITION $<CONFIG:Release>)
+        else()
+            file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/conf.py
+                          INPUT  ${CMAKE_CURRENT_BINARY_DIR}/conf.py.in)
+        endif()
+    endif()
+
     # VIGRA_CONFIGURATION is 'release' or 'debug' on Windows, nothing on Linux
     # variable CMAKE_CFG_INTDIR contains a dot '.' for a Windows nmake build, or
     #                           '$(OutDir)' for a VisualStudio build (OutDir will be
@@ -51,7 +69,7 @@ IF(PYTHON_SPHINX)
 
 ELSE(PYTHON_SPHINX)
     # no vigranumpy documentation if sphinx not available
-    ADD_CUSTOM_TARGET (doc_python 
+    ADD_CUSTOM_TARGET (doc_python
         ${CMAKE_COMMAND} -E echo
         "Cannot generate Python documentation for vigranumpy. "
         "(sphinx-build not found)"
diff --git a/vigranumpy/docsrc/conf.py.in b/vigranumpy/docsrc/conf.py.cmake2.in
similarity index 99%
copy from vigranumpy/docsrc/conf.py.in
copy to vigranumpy/docsrc/conf.py.cmake2.in
index ee5b7ca..679b8fa 100644
--- a/vigranumpy/docsrc/conf.py.in
+++ b/vigranumpy/docsrc/conf.py.cmake2.in
@@ -234,7 +234,7 @@ replace_file=open("./c_api_replaces.txt")
 for l in replace_file:
     replacement=l.split(":")
     k = replacement[0].rfind('.')
-    if k >= 0:        
+    if k >= 0:
         rst_epilog += """
     .. |%s| replace:: %s
 """% (replacement[0],replacement[0][k+1:])
diff --git a/vigranumpy/docsrc/conf.py.in b/vigranumpy/docsrc/conf.py.in
index ee5b7ca..003e342 100644
--- a/vigranumpy/docsrc/conf.py.in
+++ b/vigranumpy/docsrc/conf.py.in
@@ -11,7 +11,7 @@
 # All configuration values have a default; values that are commented out
 # serve to show the default.
 
-import sys, os
+import sys, os, re
 
 # silent lots of 'arg is not a Python function' warnings
 import inspect
@@ -43,9 +43,9 @@ for a in sys.argv:
     if a.startswith(match):
         outdir = '/' + a[len(match):]
 
-vigraimpex_path=r'@VIGRAIMPEX_PATH@%s' % outdir
+vigraimpex_path = re.sub('/Release$', outdir, r'$<TARGET_FILE_DIR:vigraimpex>')
 print "vigraimpex path:", vigraimpex_path
-os.environ['PATH'] = os.pathsep.join([vigraimpex_path, os.environ['PATH']])
+os.environ['PATH'] = os.pathsep.join([vigraimpex_path.replace('/', os.sep), os.environ['PATH']])
 
 
 # If extensions (or modules to document with autodoc) are in another directory,
@@ -234,7 +234,7 @@ replace_file=open("./c_api_replaces.txt")
 for l in replace_file:
     replacement=l.split(":")
     k = replacement[0].rfind('.')
-    if k >= 0:        
+    if k >= 0:
         rst_epilog += """
     .. |%s| replace:: %s
 """% (replacement[0],replacement[0][k+1:])
diff --git a/vigranumpy/docsrc/index.rst b/vigranumpy/docsrc/index.rst
index b4e5e52..3ca8378 100644
--- a/vigranumpy/docsrc/index.rst
+++ b/vigranumpy/docsrc/index.rst
@@ -3,6 +3,7 @@
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
 
+
 Vigranumpy Reference
 ====================
 
@@ -524,7 +525,60 @@ method proposed by Foerstner.
 .. automodule:: vigra.noise
    :members:
 
-   
+
+Histogram and Channel Representation
+------------------------------------
+
+The module vigra.histogram provides histograms and channel representation
+
+.. automodule:: vigra.histogram
+   :members:
+
+
+
+Graphs and Algorithms on Graphs
+-------------------------------
+
+The module vigra.graphs provides graphs and graph algorithms
+
+.. automodule:: vigra.graphs
+   :members:
+
+.. autoclass:: vigra.graphs.GridGraphUndirected2d
+   :members:
+
+.. autoclass:: vigra.graphs.GridGraphUndirected3d
+   :members:
+
+.. autoclass:: vigra.graphs.AdjacencyListGraph
+    :members:
+
+.. autoclass:: vigra.graphs.RegionAdjacencyGraph
+    :members:
+
+.. autoclass:: vigra.graphs.GridRegionAdjacencyGraph
+    :members:
+
+
+.. autoclass:: vigra.graphs.ShortestPathPathDijkstra
+    :members:
+
+
+
+Utilities 
+----------------------------------
+
+The module vigra.utilities provides  utilities and tools
+like priority queues with changeable priorities
+
+.. automodule:: vigra.utilities
+   :members:
+    
+
+
+
+
+
 .. _sec-own-modules:
 
 Writing Your Own C++ Modules
diff --git a/vigranumpy/examples/100075.jpg b/vigranumpy/examples/100075.jpg
new file mode 100644
index 0000000..70a1fa4
Binary files /dev/null and b/vigranumpy/examples/100075.jpg differ
diff --git a/vigranumpy/examples/12003.jpg b/vigranumpy/examples/12003.jpg
new file mode 100755
index 0000000..2957db8
Binary files /dev/null and b/vigranumpy/examples/12003.jpg differ
diff --git a/vigranumpy/examples/12074.jpg b/vigranumpy/examples/12074.jpg
new file mode 100755
index 0000000..4ee984b
Binary files /dev/null and b/vigranumpy/examples/12074.jpg differ
diff --git a/vigranumpy/examples/69015.jpg b/vigranumpy/examples/69015.jpg
new file mode 100755
index 0000000..58134db
Binary files /dev/null and b/vigranumpy/examples/69015.jpg differ
diff --git a/vigranumpy/examples/VigraGraphs.ipynb b/vigranumpy/examples/VigraGraphs.ipynb
new file mode 100644
index 0000000..6305736
--- /dev/null
+++ b/vigranumpy/examples/VigraGraphs.ipynb
@@ -0,0 +1,309 @@
+     {
+ "metadata": {
+  "name": "Vigra Graphs"
+ },
+ "nbformat": 3,
+ "nbformat_minor": 0,
+ "worksheets": [
+  {
+   "cells": [
+    {
+     "cell_type": "heading",
+     "level": 1,
+     "metadata": {},
+     "source": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "# to make matplotlib figures nice\n",
+      "import matplotlib\n",
+      "matplotlib.rcParams['savefig.dpi'] = 2 * matplotlib.rcParams['savefig.dpi']"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 9
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Import vigra and graph submodule, and import numpy from vigra"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "import vigra\n",
+      "from vigra import graphs\n",
+      "from vigra import numpy"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [],
+     "prompt_number": 10
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Read in an image"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "# load image and convert to LAB\n",
+      "filepath = '12003.jpg'\n",
+      "img = vigra.impex.readImage(filepath)\n",
+      "imgLab = vigra.colors.transform_RGB2Lab(img)\n",
+      "vigra.imshow(img,show=False)\n",
+      "vigra.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "display_data",
+       "png": "iVBORw0KGgoAAAANSUhEUgAAAuUAAAH3CAYAAAAczCHzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAWJQAAFiUBSVIk8AAAIABJREFUeJzsvUmsbVtWpveNWay19znnVq/ixYs6IIhIhNNW4gKBbAkk\nIjvZwI3sWbKFZAshjImmhUS4Ax03EbhHz13csIQQCEMnZMJCslLpxARBUEX57nvv3nuKvfdasxjD\njTH3uQFJKkMBzhco1/90Gu8Ue6+91pxz/OMf/xhXzMzYsGHDhg0bNmzYsGHD+4bwfl/Ahg0bNmzY\nsGHDhg3/vmMj5Rs2bNiwYcOGDRs2vM/YSPmGDRs2bNiwYcOGDe8zNlK+YcOGDRs2bNiwYcP7jI2U\nb9iwYcOGDRs2bNjwPmMj5Rs2bNiwYcOGDRs2vM/YSPmGDRs2bNiwYcOGDe8zNlK+YcOGDRs2bNiw\nYcP7jI2Ub [...]
+      }
+     ],
+     "prompt_number": 11
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Compute gradient magnitude on image which shape*2-1"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "# compute gradient on interpolated image\n",
+      "sigmaGradMag = 2.0 \n",
+      "imgLabBig = vigra.resize(imgLab, [imgLab.shape[0]*2-1, imgLab.shape[1]*2-1])\n",
+      "gradMag = vigra.filters.gaussianGradientMagnitude(imgLabBig, sigmaGradMag)\n",
+      "vigra.imshow(gradMag,show=False)\n",
+      "vigra.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "display_data",
+       "png": "iVBORw0KGgoAAAANSUhEUgAAAuYAAAH3CAYAAAD3+5rwAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAWJQAAFiUBSVIk8AAAIABJREFUeJzsnUmPpNlZtu8YMoaMMSNyzqyq7mr3YGMQiI1lVoDEmt/A\nCiFAeA3CK/gDCJb8BJYIYVlmYwlLLMCGHtxdU3dlVkZmRmbMkTF/i9R18o5TaT7czfe5rX6PFKrK\nGN73vOc8w/3cz3POSa1Wq5WSlrSkJS1pSUta0pKWtKT9Qlv6F92BpCUtaUlLWtKSlrSkJS1pCTBP\nWtKSlrSkJS1pSUta0r4ULQHmSUta0pKWtKQlLWlJS9qXoCXAPGlJS1rSkpa0pCUtaUn7ErQEmCct\naUlLWtKSlrSkJS1pX4KWAPOkJS1pSUta0pKWtKQl7UvQEmCetKQlLWlJS1rSkpa0pH0JWgLMk5a0\npCUtaUlLW [...]
+      }
+     ],
+     "prompt_number": 12
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Get oversegmentation"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "# get super-pixels with slic on LAB image\n",
+      "superpixelDiameter = 20 # super-pixel size\n",
+      "slicWeight = 10.0       # SLIC color - spatial weight\n",
+      "imgLab = vigra.colors.transform_RGB2Lab(img)\n",
+      "labels, nseg = vigra.analysis.slicSuperpixels(imgLab, slicWeight,\n",
+      "                                              superpixelDiameter)\n",
+      "labels = vigra.analysis.labelImage(labels)\n",
+      "# A random colormap for matplotlib\n",
+      "cmap = matplotlib.colors.ListedColormap ( numpy.random.rand ( 256,3))\n",
+      "pylab.imshow ( labels.squeeze().swapaxes(0,1), cmap = cmap)\n",
+      "pylab.show()\n",
+      "\n",
+      "vigra.segShow(img,labels,alpha=0.0)\n",
+      "vigra.show()\n"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "display_data",
+       "png": "iVBORw0KGgoAAAANSUhEUgAAAuUAAAH3CAYAAAAczCHzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAWJQAAFiUBSVIk8AAAIABJREFUeJzsvXl0XNd95/m5b6u9sO8AQRJcRVISN1GLJVmLZdmyvMaO\n246TiRMnHneStsfTM+mkTzJ9Mk7OTCY96UnbPcl0ZKc7TjvtJY4tW7tkLZREiZK4byBAEiD2rQq1\nvvXOH0UCBLGDBRRIvs85OuLD225VvXfv9/7u736vkFJKfHx8fHx8fHx8fHxKhlLqAvj4+Pj4+Pj4\n+Pjc7Pii3MfHx8fHx8fHx6fE+KLcx8fHx8fHx8fHp8T4otzHx8fHx8fHx8enxPii3MfHx8fHx8fH\nx6fE+KLcx8fHx8fHx8fHp8T4otzHx8fHx8fHx8enxPii3MfHx8fHx8fHx6fE+KLcx8fHx8fHx8fH\np8T4otzHx [...]
+      },
+      {
+       "output_type": "display_data",
+       "png": "iVBORw0KGgoAAAANSUhEUgAAAuYAAAH3CAYAAAD3+5rwAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAWJQAAFiUBSVIk8AAAIABJREFUeJzsvHm0NllV5vnb55yIeN977zfmPA/kRIJAAsU8CGqioEiL\nQqNS2JQlqIgithZqicOSUlTERrCrbShUWnGisG0xBROQQUlMi3lIICEzgY8cv+kOb0Scc/auP3bc\nm2hbq1xiF0mveNa6K/O7w/vGG3HOPs9+9rO3mJkxY8aMGTNmzJgxY8aMLyvCl/sCZsyYMWPGjBkz\nZsyYMRPzGTNmzJgxY8aMGTPuEZiJ+YwZM2bMmDFjxowZ9wDMxHzGjBkzZsyYMWPGjHsAZmI+Y8aM\nGTNmzJgxY8Y9ADMxnzFjxowZM2bMmDHjHoCZmM+YMWPGjBkzZsyYcQ/ATMxnzJgxY8aMGTNmzLgH\nYCbmM2bMm [...]
+      }
+     ],
+     "prompt_number": 13
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Get a 2d grid graph"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "gridGraph = graphs.gridGraph(img.shape[0:2])\n",
+      "print gridGraph"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "Nodes: 154401 Edges: 308000 maxNodeId: 154400 maxEdgeId: 308801\n"
+       ]
+      }
+     ],
+     "prompt_number": 15
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Compute a region adjacency graph from oversegmentation labeling and grid graph"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "# get region adjacency graph from super-pixel labels\n",
+      "rag = graphs.regionAdjacencyGraph(gridGraph, labels)\n",
+      "print rag"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "Nodes: 702 Edges: 1799 maxNodeId: 702 maxEdgeId: 1798\n"
+       ]
+      }
+     ],
+     "prompt_number": 16
+    },
+    {
+     "cell_type": "raw",
+     "metadata": {},
+     "source": [
+      "Get edge weight for grid graph"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "gridGraphEdgeIndicator = graphs.edgeFeaturesFromInterpolatedImage(gridGraph,\n",
+      "                                                                  gradMag)\n",
+      "\n",
+      "print gridGraphEdgeIndicator.shape"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "(481, 321, 2)\n"
+       ]
+      }
+     ],
+     "prompt_number": 18
+    },
+    {
+     "cell_type": "raw",
+     "metadata": {},
+     "source": [
+      "Get edge weight and node features accumulated from grid graph edge weights and node features"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "# accumulate edge weights grid graph edge weights\n",
+      "edgeWeights = rag.accumulateEdgeFeatures(gridGraphEdgeIndicator)\n",
+      "\n",
+      "# accumulate node features from grid graph node map\n",
+      "# which is just a plain image (with channels)\n",
+      "nodeFeatures = rag.accumulateNodeFeatures(imgLab)\n",
+      "\n",
+      "print edgeWeights.shape\n",
+      "print nodeFeatures.shape\n"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "(1799,)\n",
+        "(703, 3)\n"
+       ]
+      }
+     ],
+     "prompt_number": 19
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "# do agglomerativeClustering\n",
+      "beta = 0.5              # node vs edge weight\n",
+      "nodeNumStop = 50        # desired num. nodes in result\n",
+      "labels = graphs.agglomerativeClustering(graph=rag, edgeWeights=edgeWeights,\n",
+      "                                        beta=beta, nodeFeatures=nodeFeatures,\n",
+      "                                        nodeNumStop=nodeNumStop)\n",
+      "# show result \n",
+      "imgLabels =rag.projectLabelsToBaseGraph(labels)\n",
+      "cmap = matplotlib.colors.ListedColormap ( numpy.random.rand ( 256,3))\n",
+      "pylab.imshow ( imgLabels.squeeze().swapaxes(0,1), cmap = cmap)\n",
+      "pylab.show()\n",
+      "\n",
+      "rag.show(img,labels)\n",
+      "vigra.show()\n"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "display_data",
+       "png": "iVBORw0KGgoAAAANSUhEUgAAAuUAAAH3CAYAAAAczCHzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAWJQAAFiUBSVIk8AAAIABJREFUeJzs3XmU3Fd16Pvv+f1qruq5W92tWbJmWbKw5NmWJ8xoYwcM\nhhAIITe5JA94OCSX+1ay4N61IOsmeTzWfSGYBxl4eWG4DAYMBmNjjAdZNh4lj5Kseeh5qvk3nvdH\ntbrVVre6uru6a+j9WauXVFW/YZe6VLXr/PbZR2mtNUIIIYQQQoiyMcodgBBCCCGEEIudJOVCCCGE\nEEKUmSTlQgghhBBClJkk5UIIIYQQQpSZJOVCCCGEEEKUmSTlQgghhBBClJkk5UIIIYQQQpSZJOVC\nCCGEEEKUmSTlQgghhBBClJkk5UIIIYQQQpSZJOVCCCGEEEKUmSTlQgghhBBClJkk5UIIIYQQQpRZ\n1STlp06d4 [...]
+      },
+      {
+       "output_type": "display_data",
+       "png": "iVBORw0KGgoAAAANSUhEUgAAAuYAAAH3CAYAAAD3+5rwAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAWJQAAFiUBSVIk8AAAIABJREFUeJzsvVuMbdl1nveNeVlr76o699MXtrpJdlNNtiSHulsMFceg\nHBGOHcCSkzgviRFLfhAEQRGNXIAoEJMAEhIkL4kgvSQRbCAX2RDkh9iyLJomI4mxaDMSQ8WkaKol\nNS/Nbp7uc6pO1d57rTXnHCMPY1a1pNCwICpmM1k/cHC6T51TtWqtueb8x///Y5SYmbFixYoVK1as\nWLFixYovK8KX+wJWrFixYsWKFStWrFixEvMVK1asWLFixYoVK14XWIn5ihUrVqxYsWLFihWvA6zE\nfMWKFStWrFixYsWK1wFWYr5ixYoVK1asWLFixesAKzFfsWLFihUrVqxYseJ1gJWYr1ixYsWKFStW\nrFjxOsBKz [...]
+      }
+     ],
+     "prompt_number": 28
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    }
+   ],
+   "metadata": {}
+  }
+ ]
+}
diff --git a/vigranumpy/examples/blocking.py b/vigranumpy/examples/blocking.py
new file mode 100644
index 0000000..b3860fd
--- /dev/null
+++ b/vigranumpy/examples/blocking.py
@@ -0,0 +1,34 @@
+import vigra
+from vigra import graphs
+from vigra import numpy
+from vigra import Timer
+from vigra import blockwise as bw
+
+
+
+
+numpy.random.seed(42)
+
+# input
+shape = (500, 500, 500)
+
+data = numpy.random.rand(*shape).astype('float32')
+
+print "make options object"
+options = bw.BlockwiseConvolutionOptions3D()
+print type(options)
+
+sigma = 1.0
+options.stdDev = (sigma, )*3
+options.blockShape = (128, )*3
+
+print "stddev",options.stdDev
+print "call blockwise filter"
+
+with vigra.Timer("AllThread"):
+	res = bw.gaussianSmooth(data, options)
+with vigra.Timer("1thread"):
+	resRef = vigra.gaussianSmoothing(data, sigma)
+
+
+print numpy.sum(numpy.abs(res-resRef))
diff --git a/vigranumpy/examples/eccentricity_transform.py b/vigranumpy/examples/eccentricity_transform.py
new file mode 100644
index 0000000..0f1ab06
--- /dev/null
+++ b/vigranumpy/examples/eccentricity_transform.py
@@ -0,0 +1,26 @@
+import vigra
+import numpy
+import matplotlib.pyplot as plt
+
+f = "islands.png"
+cmap = plt.get_cmap("afmhot")
+
+# Compute labeled iamge.
+img = numpy.squeeze(vigra.readImage(f))
+lbl = numpy.array(vigra.analysis.labelImage(img))
+
+# Compute the eccentricity transform.
+ecc = vigra.filters.eccentricityTransform(lbl)
+plt.imshow(numpy.swapaxes(ecc, 1, 0), cmap=cmap)
+plt.show()
+
+# Compute the eccentricity centers and draw them into the image.
+centers = vigra.filters.eccentricityCenters(lbl)
+m = ecc.max()
+for c in centers[1:]:
+    ecc[c] = m
+plt.imshow(numpy.swapaxes(ecc, 1, 0), cmap=cmap)
+plt.show()
+
+# # Compute the transformation and the centers in one step:
+# ecc, centers = vigra.filters.eccentricityTransformWithCenters(lbl)
diff --git a/vigranumpy/examples/gaussian_rank.py b/vigranumpy/examples/gaussian_rank.py
new file mode 100644
index 0000000..3a6c2f3
--- /dev/null
+++ b/vigranumpy/examples/gaussian_rank.py
@@ -0,0 +1,17 @@
+import vigra
+from vigra import graphs
+
+filepath = '12003.jpg' 
+img = vigra.impex.readImage(filepath).astype('float32')
+imgM = img.copy()
+
+sigmaS = 1.0
+sigmaB = 5.0
+
+with vigra.Timer("compute rank"):
+    for c in range(3):
+        print "channel",c
+        imgC = img[:, :, c].squeeze()
+        imgM[:,:,c] = vigra.histogram.gaussianRankOrder(imgC,sigmas=(sigmaS, sigmaS, sigmaB), ranks=(0.5,), bins=100).squeeze()
+vigra.imshow(vigra.taggedView(imgM,'xyc'))
+vigra.show()
diff --git a/vigranumpy/examples/graph_3cycles.py b/vigranumpy/examples/graph_3cycles.py
new file mode 100644
index 0000000..88104b0
--- /dev/null
+++ b/vigranumpy/examples/graph_3cycles.py
@@ -0,0 +1,49 @@
+import vigra
+import vigra.graphs as graphs
+import pylab
+import numpy
+import matplotlib
+
+# parameter:
+filepath = '100075.jpg'   # input image path
+sigmaGradMag = 3.0       # sigma Gaussian gradient
+superpixelDiameter = 100  # super-pixel size
+slicWeight = 50.0        # SLIC color - spatial weight
+
+# load image and convert to LAB
+img = vigra.impex.readImage(filepath)
+
+# get super-pixels with slic on LAB image
+imgLab = vigra.colors.transform_RGB2Lab(img)
+labels, nseg = vigra.analysis.slicSuperpixels(imgLab, slicWeight,
+                                              superpixelDiameter)
+labels = vigra.analysis.labelImage(labels)
+
+# compute gradient
+imgLabBig = vigra.resize(imgLab, [imgLab.shape[0]*2-1, imgLab.shape[1]*2-1])
+gradMag    = vigra.filters.gaussianGradientMagnitude(imgLab, sigmaGradMag)
+gradMagBig = vigra.filters.gaussianGradientMagnitude(imgLabBig, sigmaGradMag*2.0)
+
+
+
+# get 2D grid graph and  edgeMap for grid graph
+# from gradMag of interpolated image
+gridGraph = graphs.gridGraph(img.shape[0:2])
+gridGraphEdgeIndicator = graphs.edgeFeaturesFromInterpolatedImage(gridGraph,
+                                                                  gradMagBig)
+
+# get region adjacency graph from super-pixel labels
+rag = graphs.regionAdjacencyGraph(gridGraph, labels)
+
+
+cycles = graphs.find3CyclesEdges(rag)
+
+
+for c in range(cycles.shape[0]):
+    cic = cycles[c,:]
+
+
+    f = numpy.zeros(rag.edgeNum)
+    f[cic] = 1
+    rag.showEdgeFeature(img, f)
+    vigra.show()
diff --git a/vigranumpy/examples/graph_agglomerative_clustering.py b/vigranumpy/examples/graph_agglomerative_clustering.py
new file mode 100644
index 0000000..22c727d
--- /dev/null
+++ b/vigranumpy/examples/graph_agglomerative_clustering.py
@@ -0,0 +1,69 @@
+import vigra
+from vigra import graphs
+from vigra import numpy
+import pylab
+# parameter
+filepath = '12003.jpg'  # input image path
+sigmaGradMag = 5.0      # sigma Gaussian gradient
+superpixelDiameter = 10 # super-pixel size
+slicWeight = 10.0       # SLIC color - spatial weight
+beta = 0.5              # node vs edge weight
+nodeNumStop = 50        # desired num. nodes in result
+
+
+# load image and convert to LAB
+img = vigra.impex.readImage(filepath)
+
+# get super-pixels with slic on LAB image
+imgLab = vigra.colors.transform_RGB2Lab(img)
+labels, nseg = vigra.analysis.slicSuperpixels(imgLab, slicWeight,
+                                              superpixelDiameter)
+labels = vigra.analysis.labelImage(labels)
+
+# compute gradient on interpolated image
+imgLabBig = vigra.resize(imgLab, [imgLab.shape[0]*2-1, imgLab.shape[1]*2-1])
+gradMag = vigra.filters.gaussianGradientMagnitude(imgLabBig, sigmaGradMag)
+
+# get 2D grid graph and  edgeMap for grid graph
+# from gradMag of interpolated image
+gridGraph = graphs.gridGraph(img.shape[0:2])
+gridGraphEdgeIndicator = graphs.edgeFeaturesFromInterpolatedImage(gridGraph,
+                                                                  gradMag)
+# get region adjacency graph from super-pixel labels
+rag = graphs.regionAdjacencyGraph(gridGraph, labels)
+
+# accumulate edge weights from gradient magnitude
+edgeWeights = rag.accumulateEdgeFeatures(gridGraphEdgeIndicator)
+
+# accumulate node features from grid graph node map
+# which is just a plain image (with channels)
+nodeFeatures = rag.accumulateNodeFeatures(imgLab)
+
+# do agglomerativeClustering
+labels = graphs.agglomerativeClustering(graph=rag, edgeWeights=edgeWeights,
+                                        beta=beta, nodeFeatures=nodeFeatures,
+                                        nodeNumStop=nodeNumStop,wardness=0.8)
+
+# show result
+f = pylab.figure()
+ax1 = f.add_subplot(2, 2, 1)
+vigra.imshow(gradMag,show=False)
+ax1.set_title("Input Image")
+pylab.axis('off')
+
+ax2 = f.add_subplot(2, 2, 2)
+rag.show(img)
+ax2.set_title("Over-Segmentation")
+pylab.axis('off')
+
+ax3 = f.add_subplot(2, 2, 3)
+rag.show(img, labels)
+ax3.set_title("Result-Segmentation")
+pylab.axis('off')
+
+ax4 = f.add_subplot(2, 2, 4)
+rag.showNested(img, labels)
+ax4.set_title("Result-Segmentation")
+pylab.axis('off')
+
+vigra.show()
diff --git a/vigranumpy/examples/graph_felzenszwalb.py b/vigranumpy/examples/graph_felzenszwalb.py
new file mode 100644
index 0000000..0a2e1cc
--- /dev/null
+++ b/vigranumpy/examples/graph_felzenszwalb.py
@@ -0,0 +1,43 @@
+import vigra
+import vigra.graphs as graphs
+
+# parameter:
+filepath = '12003.jpg'   # input image path
+sigmaGradMag = 2.0       # sigma Gaussian gradient
+superpixelDiameter = 10  # super-pixel size
+slicWeight = 10.0        # SLIC color - spatial weight
+k = 10                   # free parameter in felzenszwalbs method
+nodeNumStop = 500        # desired num. nodes in result
+
+# load image and convert to LAB
+img = vigra.impex.readImage(filepath)
+
+# get super-pixels with slic on LAB image
+imgLab = vigra.colors.transform_RGB2Lab(img)
+labels, nseg = vigra.analysis.slicSuperpixels(imgLab, slicWeight,
+                                              superpixelDiameter)
+labels = vigra.analysis.labelImage(labels)
+
+# compute gradient on interpolated image
+imgLabBig = vigra.resize(imgLab, [imgLab.shape[0]*2-1, imgLab.shape[1]*2-1])
+gradMag = vigra.filters.gaussianGradientMagnitude(imgLabBig, sigmaGradMag)
+
+# get 2D grid graph and  edgeMap for grid graph
+# from gradMag of interpolated image
+gridGraph = graphs.gridGraph(img.shape[0:2])
+gridGraphEdgeIndicator = graphs.edgeFeaturesFromInterpolatedImage(gridGraph,
+                                                                  gradMag)
+
+# get region adjacency graph from super-pixel labels
+rag = graphs.regionAdjacencyGraph(gridGraph, labels)
+
+# accumulate edge weights from gradient magnitude
+edgeWeights = rag.accumulateEdgeFeatures(gridGraphEdgeIndicator)
+
+# do the segmentation with felzenszwalbs method
+labels   = graphs.felzenszwalbSegmentation(rag, edgeWeights, 
+                                           k=50,nodeNumStop=nodeNumStop)
+
+
+rag.show(img, labels)
+vigra.show()
diff --git a/vigranumpy/examples/graph_smoothing.py b/vigranumpy/examples/graph_smoothing.py
new file mode 100644
index 0000000..ed44bcf
--- /dev/null
+++ b/vigranumpy/examples/graph_smoothing.py
@@ -0,0 +1,20 @@
+import vigra
+from vigra import graphs
+
+# parameter:
+filepath = '12003.jpg'   # input image path
+sigmaGradMag = 2.0       # sigma Gaussian gradient
+superpixelDiameter = 10  # super-pixel size
+slicWeight = 10.0        # SLIC color - spatial weight
+gamma = 0.15             # exp(-gamma * edgeIndicator)
+edgeThreshold = 2.5      # values higher are considered as edges
+scale = 1.0              # how much smoothing
+iterations = 10          # how man smoothing iterations
+
+# load image and convert to LAB
+img = vigra.impex.readImage(filepath)
+
+res = vigra.filters.nonlinearDiffusion(img, 1.9, 20.0)
+
+vigra.imshow(res)
+vigra.show()
\ No newline at end of file
diff --git a/vigranumpy/examples/graph_watersheds.py b/vigranumpy/examples/graph_watersheds.py
new file mode 100644
index 0000000..1858a2f
--- /dev/null
+++ b/vigranumpy/examples/graph_watersheds.py
@@ -0,0 +1,61 @@
+import vigra
+import vigra.graphs as graphs
+import pylab
+
+
+# parameter:
+filepath = '100075.jpg'   # input image path
+sigmaGradMag = 3.0       # sigma Gaussian gradient
+superpixelDiameter = 10  # super-pixel size
+slicWeight = 10.0        # SLIC color - spatial weight
+
+# load image and convert to LAB
+img = vigra.impex.readImage(filepath)
+
+# get super-pixels with slic on LAB image
+imgLab = vigra.colors.transform_RGB2Lab(img)
+labels, nseg = vigra.analysis.slicSuperpixels(imgLab, slicWeight,
+                                              superpixelDiameter)
+labels = vigra.analysis.labelImage(labels)
+
+# compute gradient
+imgLabBig = vigra.resize(imgLab, [imgLab.shape[0]*2-1, imgLab.shape[1]*2-1])
+gradMag    = vigra.filters.gaussianGradientMagnitude(imgLab, sigmaGradMag)
+gradMagBig = vigra.filters.gaussianGradientMagnitude(imgLabBig, sigmaGradMag*2.0)
+
+vigra.imshow(gradMagBig)
+vigra.show()
+
+# get 2D grid graph and  edgeMap for grid graph
+# from gradMag of interpolated image
+gridGraph = graphs.gridGraph(img.shape[0:2])
+gridGraphEdgeIndicator = graphs.edgeFeaturesFromInterpolatedImage(gridGraph,
+                                                                  gradMagBig)
+
+# get region adjacency graph from super-pixel labels
+rag = graphs.regionAdjacencyGraph(gridGraph, labels)
+
+
+# accumulate edge  and ndie weights from gradient magnitude
+ragEdgeWeights = rag.accumulateEdgeFeatures(gridGraphEdgeIndicator)
+ragNodeWeights = rag.accumulateNodeFeatures(gradMag)
+
+# generate seeds
+seeds = graphs.nodeWeightedWatershedsSeeds(rag, ragNodeWeights)
+
+# node weighted watersheds
+labelsNodeWeighted  = graphs.nodeWeightedWatersheds(rag, ragNodeWeights, seeds)
+
+# edge weighted watersheds
+labelsEdgeWeighted  = graphs.edgeWeightedWatersheds(rag, ragEdgeWeights, seeds)
+
+
+f = pylab.figure()
+ax0 = f.add_subplot(1, 2, 0)
+rag.showNested(img, labelsNodeWeighted)
+ax0.set_title("node weighted")
+
+ax1 = f.add_subplot(1, 2, 1)
+rag.showNested(img, labelsEdgeWeighted)
+ax1.set_title("edge weighted")
+pylab.show()
diff --git a/vigranumpy/examples/grid_graph_shortestpath.py b/vigranumpy/examples/grid_graph_shortestpath.py
new file mode 100644
index 0000000..2e24be1
--- /dev/null
+++ b/vigranumpy/examples/grid_graph_shortestpath.py
@@ -0,0 +1,150 @@
+import vigra
+import vigra.graphs as vigraph
+import pylab
+import numpy
+np=numpy
+import sys
+import matplotlib
+import pylab as plt
+import math
+from matplotlib.widgets import Slider, Button, RadioButtons
+
+def makeWeights(gamma):
+    global hessian,gradmag,gridGraph
+    print "hessian",hessian.min(),hessian.max()
+    print "raw ",raw.min(),raw.max()
+    wImg= numpy.exp((gradmag**0.5)*gamma*-1.0)#**0.5
+    wImg = numpy.array(wImg).astype(numpy.float32)
+    w=vigra.graphs.implicitMeanEdgeMap(gridGraph,wImg)
+    return w
+
+def makeVisuImage(path,img):
+    coords = (path[:,0],path[:,1])
+    visuimg =img.copy()
+    iR=visuimg[:,:,0]
+    iG=visuimg[:,:,1]
+    iB=visuimg[:,:,2]
+    iR[coords]=255
+    iG[coords]=0
+    iB[coords]=0
+    visuimg-=visuimg.min()
+    visuimg/=visuimg.max()  
+    return visuimg
+
+
+
+
+f       = '100075.jpg'
+f       = '69015.jpg'
+#f       = "/media/tbeier/GSP1RMCPRFR/iso.03530.png"
+img     = vigra.impex.readImage(f)
+
+
+print img.shape
+
+if(img.shape[2]==1):
+    img    = numpy.concatenate([img]*3,axis=2)
+    imgLab = img
+    imgLab = vigra.taggedView(imgLab,'xyc')
+else:
+    imgLab = vigra.colors.transform_RGB2Lab(img)
+sigma   = 1.0
+
+
+imgLab-=imgLab.min()
+imgLab/=imgLab.max()
+imgLab*=255
+
+img-=img.min()
+img/=img.max()
+img*=255
+
+print imgLab.shape
+
+
+print "interpolate image"
+imgLabSmall = imgLab
+
+# make a few edge weights
+
+gradmag = numpy.squeeze(vigra.filters.gaussianGradientMagnitude(imgLabSmall,sigma))
+hessian = numpy.squeeze(vigra.filters.hessianOfGaussianEigenvalues(imgLabSmall[:,:,0],sigma))[:,:,0]
+hessian-=hessian.min()
+raw     = 256-imgLabSmall[:,:,0].copy()
+gridGraph  = vigraph.gridGraph(imgLab.shape[:2],False)  
+
+
+
+weights  = makeWeights(3.0)
+
+
+pathFinder = vigraph.ShortestPathPathDijkstra(gridGraph)
+
+
+visuimg =img.copy()
+ax = plt.gca()
+fig = plt.gcf()
+visuimg-=visuimg.min()
+visuimg/=visuimg.max()
+implot = ax.imshow(numpy.swapaxes(visuimg,0,1),cmap='gray')
+
+clickList=[]
+frozen = False
+
+
+axslider   = plt.axes([0.0, 0.00, 0.4, 0.075])
+axfreeze   = plt.axes([0.6, 0.00, 0.1, 0.075])
+axunfreeze = plt.axes([0.8, 0.00, 0.1, 0.075])
+bfreeze    = Button(axfreeze, 'freeze')
+bunfreeze  = Button(axunfreeze, 'unfrease and clear')
+sgamma     = Slider(axslider, 'gamma', 0.01, 5.0, valinit=1.0)
+
+def onclick(event):
+    global clickList
+    global weights
+    global img
+    if event.xdata != None and event.ydata != None:
+        xRaw,yRaw = event.xdata,event.ydata
+        if not frozen and xRaw >=0.0 and yRaw>=0.0 and xRaw<img.shape[0] and yRaw<img.shape[1]:
+            x,y = long(math.floor(event.xdata)),long(math.floor(event.ydata))
+            clickList.append((x,y))
+            if len(clickList)==2:
+                source = gridGraph.coordinateToNode(clickList[0])
+                target = gridGraph.coordinateToNode(clickList[1])
+                weights  = makeWeights(sgamma.val)
+                #path = pathFinder.run(weights, source,target).path(pathType='coordinates')
+                path = pathFinder.run(weights, source).path(pathType='coordinates',target=target)
+                visuimg = makeVisuImage(path,img)
+                implot.set_data(numpy.swapaxes(visuimg,0,1))
+                plt.draw()
+            
+
+def freeze(event):
+    global frozen
+    frozen=True
+
+def unfreeze(event):
+    global frozen,clickList
+    frozen=False
+    clickList = []
+
+def onslide(event):
+    global img,gradmag,weights,clickList,sgamma
+    weights  = makeWeights(sgamma.val)
+    print "onslide",clickList
+    if len(clickList)>=2:
+        print "we have  path"
+        source = gridGraph.coordinateToNode(clickList[0])
+        target = gridGraph.coordinateToNode(clickList[1])
+        path = pathFinder.run(weights, source,target).path(pathType='coordinates')
+        visuimg = makeVisuImage(path,img)
+        implot.set_data(numpy.swapaxes(visuimg,0,1))
+        plt.draw()
+
+
+bfreeze.on_clicked(freeze)
+bunfreeze.on_clicked(unfreeze)
+sgamma.on_changed(onslide)
+
+cid = fig.canvas.mpl_connect('button_press_event', onclick)
+plt.show()
diff --git a/vigranumpy/examples/islands.png b/vigranumpy/examples/islands.png
new file mode 100644
index 0000000..4e889e8
Binary files /dev/null and b/vigranumpy/examples/islands.png differ
diff --git a/vigranumpy/examples/merge_graph.py b/vigranumpy/examples/merge_graph.py
new file mode 100644
index 0000000..578b5de
--- /dev/null
+++ b/vigranumpy/examples/merge_graph.py
@@ -0,0 +1,68 @@
+import vigra
+from vigra import graphs
+from vigra import numpy
+import pylab
+# parameter
+filepath = '12003.jpg'  # input image path
+sigmaGradMag = 2.0      # sigma Gaussian gradient
+superpixelDiameter = 10 # super-pixel size
+slicWeight = 10.0       # SLIC color - spatial weight
+beta = 0.5              # node vs edge weight
+nodeNumStop = 50        # desired num. nodes in result
+
+
+# load image and convert to LAB
+img = vigra.impex.readImage(filepath)
+
+# get super-pixels with slic on LAB image
+imgLab = vigra.colors.transform_RGB2Lab(img)
+labels, nseg = vigra.analysis.slicSuperpixels(imgLab, slicWeight,
+                                              superpixelDiameter)
+labels = vigra.analysis.labelImage(labels)
+
+
+gridGraph = graphs.gridGraph(img.shape[0:2])
+rag = graphs.regionAdjacencyGraph(gridGraph, labels)
+
+# get the merge graph
+mg = graphs.mergeGraph(rag)
+
+
+
+
+
+
+# do n runs where we erase k edges in each run
+
+n = 3
+k = 200
+for r in range(n):
+
+    erased = 0 
+
+    while(erased<k):
+
+        # get a random edge
+        randEdgeId = numpy.random.randint(rag.edgeNum)
+
+        print "random edge:",randEdgeId
+        # edge could be gone 
+        # -since we could have merged it already
+        # - or due to transitivity of other merges
+        if mg.hasEdgeId(randEdgeId):
+            mg.contractEdge(mg.edgeFromId(randEdgeId))
+            erased+=1
+
+    # get the segmentation
+    # (brand new c++ function for max speed)
+    labels = mg.graphLabels()
+
+    # view results
+    rag.show(img,labels)
+    vigra.show()
+
+    # get the result as pixels wise labeling
+    asImage = rag.projectLabelsToGridGraph(labels)
+    asImage = vigra.taggedView(asImage, "xy")
+    
+    
diff --git a/vigranumpy/examples/non_local_mean_2d_color.py b/vigranumpy/examples/non_local_mean_2d_color.py
new file mode 100644
index 0000000..d1ed9b7
--- /dev/null
+++ b/vigranumpy/examples/non_local_mean_2d_color.py
@@ -0,0 +1,19 @@
+import vigra
+from vigra import numpy
+from matplotlib import pylab
+from time import time
+import multiprocessing
+
+
+path = "12003.jpg"
+data = vigra.impex.readImage(path).astype(numpy.float32)
+data = vigra.taggedView(100*numpy.random.rand(*data.shape),'xyc').astype('float32') + data
+data /= 2.0
+vigra.imshow(data)
+vigra.show()
+cpus = multiprocessing.cpu_count()
+policy = vigra.filters.NormPolicy(sigma=10.0, meanDist=300.7, varRatio=0.9)
+res = vigra.filters.nonLocalMean2d(data,policy=policy,searchRadius=8,patchRadius=2,nThreads=cpus+1,stepSize=1,verbose=True,sigmaMean=1.0)
+res = vigra.taggedView(res,'xyc')
+vigra.imshow(res)
+vigra.show()
diff --git a/vigranumpy/examples/rag_features.py b/vigranumpy/examples/rag_features.py
new file mode 100644
index 0000000..cbf4123
--- /dev/null
+++ b/vigranumpy/examples/rag_features.py
@@ -0,0 +1,19 @@
+from vigra import *
+
+
+
+
+ 
+
+def computeFeatures():
+    pass
+
+
+
+class FilterList(object):
+    def __init__(self, shape):
+        pass
+
+
+
+filterList = FilterList()
diff --git a/vigranumpy/examples/shock_filter.py b/vigranumpy/examples/shock_filter.py
new file mode 100644
index 0000000..2da5fe7
--- /dev/null
+++ b/vigranumpy/examples/shock_filter.py
@@ -0,0 +1,25 @@
+import vigra
+from vigra import graphs
+
+filepath = '12003.jpg' 
+img = vigra.impex.readImage(filepath).astype('float32')[:,:,0]
+
+
+
+res = vigra.filters.shockFilter(img,sigma=1.5, rho=10.0, updwindFactorH=1.0, iterations=5)
+res = res.squeeze()
+
+
+import numpy as np
+import pylab
+import matplotlib.cm as cm
+import Image
+
+f = pylab.figure()
+for n, arr in enumerate([img,res]):
+    arr= arr.squeeze()
+    #f.add_subplot(2, 1, n)  # this line outputs images on top of each other
+    f.add_subplot(1, 2, n)  # this line outputs images side-by-side
+    pylab.imshow(arr,cmap=cm.Greys_r)
+pylab.title('( III x) image')
+pylab.show()
diff --git a/vigranumpy/lib/__init__.py b/vigranumpy/lib/__init__.py
index 5618ddf..8d1772c 100644
--- a/vigranumpy/lib/__init__.py
+++ b/vigranumpy/lib/__init__.py
@@ -33,7 +33,14 @@
 #
 #######################################################################
 
-import sys, os
+import sys, os, time, math
+from numbers import Number
+from multiprocessing import cpu_count
+try:
+    import pylab
+except Exception, e:
+    pass
+
 
 _vigra_path = os.path.abspath(os.path.dirname(__file__))
 _vigra_doc_path = _vigra_path + '/doc/vigranumpy/index.html'
@@ -95,8 +102,11 @@ The following sub-modules group related functionality:
 * learning   (machine learning and classification)
 * noise      (noise estimation and normalization)
 * geometry   (geometric algorithms, e.g. convex hull)
+* histogram  (histograms and channel representation)
+* graphs     (grid graphs / graphs / graph algorithms)
+* utilities  (priority queues)
 ''' % _vigra_doc_path
- 
+
 from __version__ import version
 import vigranumpycore
 import arraytypes
@@ -109,43 +119,79 @@ import colors
 import noise
 import geometry
 import optimization
+import histogram
+import graphs
+import utilities
+import blockwise
 
 sampling.ImagePyramid = arraytypes.ImagePyramid
 
+
+
+class Timer:
+    def __init__(self, name, verbose=True):
+        self.name = name
+        self.verbose = verbose
+
+    def __enter__(self):
+        if self.verbose:
+            print self.name, "..."
+        self.start = time.time()
+        return self
+
+    def __exit__(self, *args):
+        self.end = time.time()
+        self.interval = self.end - self.start
+        if self.verbose  :
+            print "... took ", self.interval, "sec"
+
+
+
+
+
+
+
 try:
     import fourier
 except Exception, e:
-    _fallbackModule('vigra.fourier', 
+    _fallbackModule('vigra.fourier',
     '''
     %s
-    
+
     Make sure that the fftw3 libraries are found during compilation and import.
     They may be downloaded at http://www.fftw.org/.''' % str(e))
     import fourier
 
 # import most frequently used functions
 from arraytypes import *
-standardArrayType = arraytypes.VigraArray 
+standardArrayType = arraytypes.VigraArray
 defaultAxistags = arraytypes.VigraArray.defaultAxistags
 
+from vigranumpycore import ChunkedArrayFull, ChunkedArrayLazy, ChunkedArrayCompressed, ChunkedArrayTmpFile, Compression
+try:
+    from vigranumpycore import ChunkedArrayHDF5, HDF5Mode
+except:
+    pass
+
+
 from impex import readImage, readVolume
 
 def readHDF5(filenameOrGroup, pathInFile, order=None):
     '''Read an array from an HDF5 file.
-    
+
        'filenameOrGroup' can contain a filename or a group object
-       referring to an already open HDF5 file. 'pathInFile' is the name 
-       of the dataset to be read, including intermediate groups. If the 
-       first argument is a group object, the path is relative to this 
+       referring to an already open HDF5 file. 'pathInFile' is the name
+       of the dataset to be read, including intermediate groups. If the
+       first argument is a group object, the path is relative to this
        group, otherwise it is relative to the file's root group.
-       
+
        If the dataset has an attribute 'axistags', the returned array
-       will have type :class:`~vigra.VigraArray` and will be transposed 
+       will have type :class:`~vigra.VigraArray` and will be transposed
        into the given 'order' ('vigra.VigraArray.defaultOrder'
-       will be used if no order is given).  Otherwise, the returned 
-       array is a plain 'numpy.ndarray'. In this case, order='F' will 
+       will be used if no order is given).  Otherwise, the returned
+       array is a plain 'numpy.ndarray'. In this case, order='F' will
        return the array transposed into Fortran order.
-       
+
        Requirements: the 'h5py' module must be installed.
     '''
     import h5py
@@ -176,8 +222,9 @@ def readHDF5(filenameOrGroup, pathInFile, order=None):
         if file is not None:
             file.close()
     return data
-        
-def writeHDF5(data, filenameOrGroup, pathInFile, compression=None):
+
+
+def writeHDF5(data, filenameOrGroup, pathInFile, compression=None, chunks=None):
     '''Write an array to an HDF5 file.
 
        'filenameOrGroup' can contain a filename or a group object
@@ -195,9 +242,14 @@ def writeHDF5(data, filenameOrGroup, pathInFile, compression=None):
        gzip (standard compression),
        szip (available if HDF5 is compiled with szip. Faster compression, limited types),
        lzf (very fast compression, all types).
-       The 'lzf' compression filter is many times faster than 'gzip' 
+       The 'lzf' compression filter is many times faster than 'gzip'
        at the cost of a lower compresion ratio.
 
+       Chunking is disabled by default. When 'chunks' is set to True
+       chunking is enabled and a chunk shape is determined automatically.
+       Alternatively a chunk shape can be specified explicitly by passing
+       a tuple of the desired shape.
+
        Requirements: the 'h5py' module must be installed.
     '''
     import h5py
@@ -229,13 +281,13 @@ def writeHDF5(data, filenameOrGroup, pathInFile, compression=None):
             data = data.transposeToNumpyOrder()
         except:
             pass
-        dataset = group.create_dataset(levels[-1], data=data, compression=compression)
+        dataset = group.create_dataset(levels[-1], data=data, compression=compression, chunks=chunks)
         if hasattr(data, 'axistags'):
             dataset.attrs['axistags'] = data.axistags.toJSON()
     finally:
         if file is not None:
             file.close()
-        
+
 impex.readHDF5 = readHDF5
 readHDF5.__module__ = 'vigra.impex'
 impex.writeHDF5 = writeHDF5
@@ -244,6 +296,36 @@ writeHDF5.__module__ = 'vigra.impex'
 from filters import convolve, gaussianSmoothing
 from sampling import resize
 
+def gaussianDerivative(array, sigma, orders, out=None, window_size=0.0):
+    '''
+        Convolve 'array' with a Gaussian derivate kernel of the given 'orders'.
+        'orders' must contain a list of integers >= 0 for each non-channel axis.
+        Each channel of the array is treated independently. If 'sigma' is a single
+        value, the kernel size is equal in each dimension. If 'sigma' is a tuple
+        or list of values of appropriate length, a different size is used for each axis.
+
+        'window_size' specifies the ratio between the filter scale and the size of
+        the filter window. Use values around 2.0 to speed-up the computation for the
+        price of increased cut-off error, and values >= 4.0 for vary accurate results.
+        The window size is automatically determined for the default value 0.0.
+    '''
+    if hasattr(array, 'dropChannelAxis'):
+        if array.dropChannelAxis().ndim != len(orders):
+            raise RuntimeError("gaussianDerivative(): len(orders) doesn't match array dimension.")
+    else:
+        if array.ndim == len(orders):
+            raise RuntimeError("gaussianDerivative(): len(orders) doesn't match array dimension.")
+    try:
+        len(sigma)
+    except:
+        sigma = [sigma]*len(orders)
+    kernels = tuple([filters.gaussianDerivativeKernel(s, o, window_size=window_size) \
+                     for s, o in zip(sigma, orders)])
+    return filters.convolve(array, kernels, out)
+
+filters.gaussianDerivative = gaussianDerivative
+gaussianDerivative.__module__ = 'vigra.filters'
+
 # import enums
 CLOCKWISE = sampling.RotationDirection.CLOCKWISE
 COUNTER_CLOCKWISE = sampling.RotationDirection.COUNTER_CLOCKWISE
@@ -251,7 +333,7 @@ UPSIDE_DOWN = sampling.RotationDirection.UPSIDE_DOWN
 CompleteGrow = analysis.SRGType.CompleteGrow
 KeepContours = analysis.SRGType.KeepContours
 StopAtThreshold = analysis.SRGType.StopAtThreshold
- 
+
 _selfdict = globals()
 def searchfor(searchstring):
    '''Scan all vigra modules to find classes and functions containing
@@ -264,35 +346,152 @@ def searchfor(searchstring):
             print attr+"."+cont
 
 # FIXME: use axistags here
-def imshow(image):
+def imshow(image,show=True, **kwargs):
     '''Display a scalar or RGB image by means of matplotlib.
        If the image does not have one or three channels, an exception is raised.
-       The image will be automatically scaled to the range 0...255 when its dtype 
-       is not already 'uint8'.
+       The image will be automatically scaled to the range 0...255 when its dtype
+       is not already 'uint8' and neither 'cmap' nor 'norm' are specified in kwargs
     '''
     import matplotlib.pylab
-    
+
     if not hasattr(image, 'axistags'):
-        return matplotlib.pyplot.imshow(image)
-    
+        plot = matplotlib.pyplot.imshow(image, **kwargs)
+        if show:
+            matplotlib.pylab.show()
+        return plot
+
+
     image = image.transposeToNumpyOrder()
     if image.channels == 1:
         image = image.dropChannelAxis().view(numpy.ndarray)
-        plot = matplotlib.pyplot.imshow(image, cmap=matplotlib.cm.gray, \
-                                         norm=matplotlib.cm.colors.Normalize())
-        matplotlib.pylab.show()
+        if 'cmap' in kwargs.keys():
+            cmap = kwargs.pop('cmap')
+        else:
+            cmap = matplotlib.cm.gray
+        if 'norm' in kwargs.keys():
+            norm = kwargs.pop('norm')
+        else:
+            norm = matplotlib.cm.colors.Normalize()
+        plot = matplotlib.pyplot.imshow(image, cmap=cmap, norm=norm, **kwargs)
+        if show:
+            matplotlib.pylab.show()
         return plot
     elif image.channels == 3:
         if image.dtype != numpy.uint8:
             out = image.__class__(image.shape, dtype=numpy.uint8, axistags=image.axistags)
             image = colors.linearRangeMapping(image, newRange=(0.0, 255.0), out=out)
-        plot = matplotlib.pyplot.imshow(image.view(numpy.ndarray))
-        matplotlib.pylab.show()
+        plot = matplotlib.pyplot.imshow(image.view(numpy.ndarray), **kwargs)
+        if show:
+            matplotlib.pylab.show()
         return plot
     else:
         raise RuntimeError("vigra.imshow(): Image must have 1 or 3 channels.")
 
-        
+
+def multiImshow(images,shape, show=True):
+    nImg = len(images)
+    f = pylab.figure()
+
+    s = tuple(shape)
+    for c,iname in enumerate(images.keys()):
+        data,itype = images[iname]
+        if itype == 'img':
+
+            ax1 = f.add_subplot(s[0],s[1],c+1)
+            imshow(data,show=False)
+            ax1.set_title(iname)
+            pylab.axis('off')
+    if show :
+        pylab.show()
+
+def segShow(img,labels,edgeColor=(0,0,0),alpha=0.3,show=False,returnImg=False,r=0):
+
+    img = numpy.squeeze(img)
+    if img.ndim ==2:
+        img = numpy.concatenate( [ img[:,:,None]]*3 ,axis=2).astype(numpy.float32)
+        img = taggedView(img, 'xyc')
+
+    labels = numpy.squeeze(labels)
+    crackedEdges = analysis.regionImageToCrackEdgeImage(labels+1).squeeze()
+    #print "cracked shape",crackedEdges.shape
+    whereEdge    =  numpy.where(crackedEdges==0)
+    whereNoEdge  =  numpy.where(crackedEdges!=0)
+    crackedEdges[whereEdge] = 1
+    crackedEdges[whereNoEdge] = 0
+
+    if r>0 :
+        res = filters.discDilation(crackedEdges.astype(numpy.uint8),int(r) )
+        whereEdge  =  numpy.where(res==1)
+
+    imgToDisplay = resize(img,numpy.squeeze(crackedEdges).shape)
+    imgToDisplay-=imgToDisplay.min()
+    imgToDisplay/=imgToDisplay.max()
+    for c in range(3):
+        ic = imgToDisplay[:,:,c]
+        ic[whereEdge]=(1.0-alpha)*edgeColor[c] + alpha*ic[whereEdge]
+
+    if returnImg:
+        return imgToDisplay
+    return imshow(imgToDisplay,show=show)
+
+def nestedSegShow(img,labels,edgeColors=None,scale=1,show=False,returnImg=False):
+
+    shape=(labels.shape[0]*scale,labels.shape[1]*scale)
+    if scale!=1:
+        img=vigra.resize(img,shape)
+
+
+
+
+    assert numpy.squeeze(labels).ndim==3
+    nSegs  = labels.shape[2]
+
+
+    if edgeColors is None :
+      edgeColors=numpy.ones([nSegs,4])
+
+      a  =numpy.array([0,0,0.0,0.6],dtype=numpy.float32)
+      b  =numpy.array([1,0,0,0.4],dtype=numpy.float32)
+
+      for s in range(nSegs):
+        f=float(s)/float(nSegs-1)
+        edgeColors[s,:]=f*b + (1.0-f)*a
+
+    tShape=(img.shape[0]*2-1,img.shape[1]*2-1)
+
+    imgToDisplay = resize(img,tShape)
+    imgToDisplay-=imgToDisplay.min()
+    imgToDisplay/=imgToDisplay.max()
+
+    imgIn = imgToDisplay.copy()
+
+    for si in range(nSegs):
+        l = labels[:,:,si].copy()
+        if scale!=1:
+            l=resize(l.astype(numpy.float32),shape,order=0).astype(numpy.uint32)
+
+        crackedEdges = analysis.regionImageToCrackEdgeImage(l)
+        whereEdge    = numpy.where(crackedEdges==0)
+
+
+        if len(edgeColors[si])<4:
+            alpha = 0.0
+        else:
+            alpha = edgeColors[si,3]
+        for c in range(3):
+            icI = imgIn[:,:,c]
+            ic  = imgToDisplay[:,:,c]
+            ic[whereEdge]=(1.0-alpha) * edgeColors[si,c] + alpha*icI[whereEdge]
+    if returnImg:
+        return imgToDisplay
+    return imshow(imgToDisplay,show=show)
+
+
+def show():
+    import matplotlib.pylab
+    matplotlib.pylab.show()
+
+
 # auto-generate code for additional Kernel generators:
 def _genKernelFactories(name):
     for oldName in dir(eval('filters.'+name)):
@@ -305,9 +504,9 @@ def _genKernelFactories(name):
         newName = newPrefix + 'Kernel'
         if name == 'Kernel2D':
             newName += '2D'
-        code = '''def %(newName)s(*args):
+        code = '''def %(newName)s(*args, **kw):
         k = filters.%(name)s()
-        k.%(oldName)s(*args)
+        k.%(oldName)s(*args, **kw)
         return k
 %(newName)s.__doc__ = filters.%(name)s.%(oldName)s.__doc__
 filters.%(newName)s=%(newName)s
@@ -324,91 +523,205 @@ def _genWatershedsUnionFind():
         '''Compute watersheds of an image using the union find algorithm.
            If 'neighborhood' is 'None', it defaults to 8-neighborhood for 2D inputs
            and 6-neighborhood for 3D inputs.
-           
+
            Calls :func:`watersheds` with parameters::\n\n
                 watersheds(image, neighborhood=neighborhood, method='UnionFind', out=out)
         '''
         if neighborhood is None:
             neighborhood = 8 if image.spatialDimensions == 2 else 6
-                
+
         return analysis.watersheds(image, neighborhood=neighborhood, method='UnionFind', out=out)
-    
+
     watershedsUnionFind.__module__ = 'vigra.analysis'
     analysis.watershedsUnionFind = watershedsUnionFind
 
 _genWatershedsUnionFind()
 del _genWatershedsUnionFind
 
+
+
+# define watershedsReoptimization)
+def _genWatershedsReoptimization():
+    def watershedsReoptimization(labels,edgeIndicator,shrinkN,out=None,visu=False):
+        # do unseeding
+
+        #if visu :
+        #  import matplotlib,numpy
+        #  import pylab
+        #  # A random colormap for matplotlib
+        #  cmap = matplotlib.colors.ListedColormap ( numpy.random.rand ( 256,3))
+        #  pylab.imshow ( numpy.swapaxes(labels,0,1) , cmap = cmap)
+        #  pylab.show()
+
+
+        seeds=analysis.segToSeeds(labels,long(shrinkN))
+
+        if visu :
+          import matplotlib,numpy
+          import pylab
+          # A random colormap for matplotlib
+          cmap = matplotlib.colors.ListedColormap ( numpy.random.rand ( 256,3))
+          pylab.imshow ( numpy.swapaxes(seeds,0,1) , cmap = cmap)
+          pylab.show()
+
+
+
+        #if seeds.ndim==2:
+        #    seeds=analysis.labelImageWithBackground(seeds)
+        #elif seeds.ndim==3:
+        #    seeds=analysis.labelVolumeWithBackground(seeds)
+        #else :
+        #    raise RuntimeError("only implemented for 2d and 3d")
+
+        if visu :
+          import matplotlib,numpy
+          import pylab
+          # A random colormap for matplotlib
+          cmap = matplotlib.colors.ListedColormap ( numpy.random.rand ( 256,3))
+          pylab.imshow ( numpy.swapaxes(seeds,0,1) , cmap = cmap)
+          pylab.show()
+
+        return analysis.watersheds(edgeIndicator,seeds=seeds,out=out)
+
+    watershedsReoptimization.__module__ = 'vigra.analysis'
+    analysis.watershedsReoptimization = watershedsReoptimization
+
+_genWatershedsReoptimization()
+del _genWatershedsReoptimization
+
+
 # define tensor convenience functions
 def _genTensorConvenienceFunctions():
-    def hessianOfGaussianEigenvalues(image, scale, out=None, 
+    def hessianOfGaussianEigenvalues(image, scale, out=None,
                                      sigma_d=0.0, step_size=1.0, window_size=0.0, roi=None):
         '''Compute the eigenvalues of the Hessian of Gaussian at the given scale
            for a scalar image or volume.
-           
+
            Calls :func:`hessianOfGaussian` and :func:`tensorEigenvalues`.
         '''
-        
-        hessian = filters.hessianOfGaussian(image, scale, 
-                                            sigma_d=sigma_d, step_size=step_size, 
+
+        hessian = filters.hessianOfGaussian(image, scale,
+                                            sigma_d=sigma_d, step_size=step_size,
                                             window_size=window_size, roi=roi)
         return filters.tensorEigenvalues(hessian, out=out)
-    
+
     hessianOfGaussianEigenvalues.__module__ = 'vigra.filters'
     filters.hessianOfGaussianEigenvalues = hessianOfGaussianEigenvalues
 
-    def structureTensorEigenvalues(image, innerScale, outerScale, out=None, 
+    def structureTensorEigenvalues(image, innerScale, outerScale, out=None,
                                    sigma_d=0.0, step_size=1.0, window_size=0.0, roi=None):
         '''Compute the eigenvalues of the structure tensor at the given scales
            for a scalar or multi-channel image or volume.
-           
+
            Calls :func:`structureTensor` and :func:`tensorEigenvalues`.
         '''
 
-        st = filters.structureTensor(image, innerScale, outerScale, 
-                                     sigma_d=sigma_d, step_size=step_size, 
+        st = filters.structureTensor(image, innerScale, outerScale,
+                                     sigma_d=sigma_d, step_size=step_size,
                                      window_size=window_size, roi=roi)
         return filters.tensorEigenvalues(st, out=out)
-    
+
     structureTensorEigenvalues.__module__ = 'vigra.filters'
     filters.structureTensorEigenvalues = structureTensorEigenvalues
 
 _genTensorConvenienceFunctions()
 del _genTensorConvenienceFunctions
 
+
+
+
+
+# define tensor convenience functions
+def _genDistanceTransformFunctions():
+
+    def distanceTransform(array,background=True,norm=2,pixel_pitch=None, out=None):
+        if array.squeeze().ndim == 2:
+            return filters.distanceTransform2D(array,background=background,norm=norm,
+                                               pixel_pitch=pixel_pitch, out=out)
+        elif array.squeeze().ndim == 3:
+            return filters.distanceTransform3D(array.astype('float32'),background=background,norm=2)
+        else:
+            raise RuntimeError("distanceTransform is only implemented for 2D and 3D arrays")
+
+    distanceTransform.__module__ = 'vigra.filters'
+    filters.distanceTransform = distanceTransform
+
+
+
+_genDistanceTransformFunctions()
+del _genDistanceTransformFunctions
+
+
+
+
 # define feature convenience functions
 def _genFeaturConvenienceFunctions():
     def supportedFeatures(array):
         '''Return a list of feature names that are available for the given array. These feature
-           names are the valid inputs to a call of :func:`extractFeatures`. E.g., to compute 
+           names are the valid inputs to a call of :func:`extractFeatures`. E.g., to compute
            just the first two features in the list, use::
-           
+
                 f = vigra.analysis.supportedFeatures(array)
                 print "Computing features:", f[:2]
                 r = vigra.analysis.extractFeatures(array, features=f[:2])
         '''
-        
+
         return analysis.extractFeatures(array, None).supportedFeatures()
 
     supportedFeatures.__module__ = 'vigra.analysis'
     analysis.supportedFeatures = supportedFeatures
 
     def supportedRegionFeatures(array, labels):
-        '''Return a list of feature names that are available for the given array and label array. 
-           These feature names are the valid inputs to a call of 
-           :func:`extractRegionFeatures`. E.g., to compute just the first two features in the 
+        '''Return a list of feature names that are available for the given array and label array.
+           These feature names are the valid inputs to a call of
+           :func:`extractRegionFeatures`. E.g., to compute just the first two features in the
            list, use::
-           
+
                 f = vigra.analysis.supportedRegionFeatures(array, labels)
                 print "Computing features:", f[:2]
                 r = vigra.analysis.extractRegionFeatures(array, labels, features=f[:2])
         '''
-        
         return analysis.extractRegionFeatures(array, labels, None).supportedFeatures()
-    
+
     supportedRegionFeatures.__module__ = 'vigra.analysis'
     analysis.supportedRegionFeatures = supportedRegionFeatures
-    
+
+    def supportedConvexHullFeatures(labels):
+        '''Return a list of Convex Hull feature names that are available for the given 2D label array.
+           These Convex Hull feature names are the valid inputs to a call of
+           :func:`extractConvexHullFeatures`. E.g., to compute just the first two features in the
+           list, use::
+
+                f = vigra.analysis.supportedConvexHullFeatures(labels)
+                print "Computing Convex Hull features:", f[:2]
+                r = vigra.analysis.extractConvexHullFeatures(labels, features=f[:2])
+        '''
+        try:
+            return analysis.extractConvexHullFeatures(labels, list_features_only=True)
+        except:
+            return []
+
+    supportedConvexHullFeatures.__module__ = 'vigra.analysis'
+    analysis.supportedConvexHullFeatures = supportedConvexHullFeatures
+
+    def supportedSkeletonFeatures(labels):
+        '''Return a list of Skeleton feature names that are available for the given 2D label array.
+           These Skeleton feature names are the valid inputs to a call of
+           :func:`extractSkeletonFeatures`. E.g., to compute just the first two features in the
+           list, use::
+
+                f = vigra.analysis.supportedSkeletonFeatures(labels)
+                print "Computing Skeleton features:", f[:2]
+                r = vigra.analysis.extractSkeletonFeatures(labels, features=f[:2])
+        '''
+        try:
+            return analysis.extractSkeletonFeatures(labels, list_features_only=True)
+        except:
+            return []
+
+    supportedSkeletonFeatures.__module__ = 'vigra.analysis'
+    analysis.supportedSkeletonFeatures = supportedSkeletonFeatures
+
     # implement the read-only part of the 'dict' API in FeatureAccumulator and RegionFeatureAccumulator
     def __len__(self):
         return len(self.keys())
@@ -431,10 +744,1938 @@ def _genFeaturConvenienceFunctions():
     def iteritems(self):
         for k in self.keys():
             yield (k, self[k])
-    
+
     for k in ['__len__', '__iter__', 'has_key', 'values', 'items', 'iterkeys', 'itervalues', 'iteritems']:
         setattr(analysis.FeatureAccumulator, k, eval(k))
         setattr(analysis.RegionFeatureAccumulator, k, eval(k))
 
 _genFeaturConvenienceFunctions()
 del _genFeaturConvenienceFunctions
+
+
+MetricType = graphs.MetricType
+# define grid graph convenience functions
+# and extend grid graph classes
+def _genGridGraphConvenienceFunctions():
+
+    def gridGraph(shape,directNeighborhood=True):
+        '''Return a grid graph with certain shape.
+
+            Parameters:
+
+                - shape -- shape of the image
+                - directNeighborhood -- use  4 (True) or 8 (False) neighborhood (default: True)
+
+            Returns:
+
+                - grid graph
+
+            use::
+
+                >>> # 4-connected
+                >>> g = vigra.graps.gridGraph(shape=[10,20])
+                >>> g.nodeNum
+                200
+                >>> # 8-connected
+                >>> g = vigra.graps.gridGraph(shape=[10,20],directNeighborhood=False)
+
+        '''
+        if(len(shape)==2):
+            return graphs.GridGraphUndirected2d(shape,directNeighborhood)
+        elif(len(shape)==3):
+            return graphs.GridGraphUndirected3d(shape,directNeighborhood)
+        else:
+            raise RuntimeError("GridGraph is only implemented for 2d and 3d grids")
+
+    gridGraph.__module__ = 'vigra.graphs'
+    graphs.gridGraph = gridGraph
+
+    # extend grid graph via meta classes
+    for cls in [graphs.GridGraphUndirected2d, graphs.GridGraphUndirected3d] :
+
+        metaCls = cls.__class__
+
+        class gridGraphInjector(object):
+            class __metaclass__(metaCls):
+                def __init__(self, name, bases, dict):
+                    for b in bases:
+                        if type(b) not in (self, type):
+                            for k,v in dict.items():
+                                setattr(b,k,v)
+                    return type.__init__(self, name, bases, dict)
+
+        ##inject some methods in the point foo
+        class moreGridGraph(gridGraphInjector, cls):
+
+            @property
+            def shape(self):
+                """ shape of grid graph"""
+                return self.intrinsicNodeMapShape()
+
+
+            def nodeSize(self):
+                """ node map filled with 1.0"""
+                size = graphs.graphMap(self,item='node',dtype=numpy.float32)
+                size[:]=1
+                return size
+
+            def edgeLengths(self):
+                """ node map filled with 1.0"""
+                size = graphs.graphMap(self,item='edge',dtype=numpy.float32)
+                size[:]=1
+                return size
+
+            def mergeGraph(self):
+                if  len(self.shape)==2:
+                    mg = graphs.GridGraphUndirected2dMergeGraph(self)
+                else:
+                    mg =  graphs.GridGraphUndirected3dMergeGraph(self)
+                return mg
+
+
+    def isGridGraph(obj):
+        """ check if obj is gridGraph"""
+        return isinstance(obj,(graphs.GridGraphUndirected2d , graphs.GridGraphUndirected3d))
+    def isGridGraph2d(obj):
+        """ check if obj is gridGraph"""
+        return isinstance(obj,graphs.GridGraphUndirected2d)
+
+    isGridGraph.__module__ = 'vigra.graphs'
+    graphs.isGridGraph = isGridGraph
+
+    isGridGraph2d.__module__ = 'vigra.graphs'
+    graphs.isGridGraph2d = isGridGraph2d
+
+
+_genGridGraphConvenienceFunctions()
+del _genGridGraphConvenienceFunctions
+
+
+
+def _genGraphConvenienceFunctions():
+
+    def listGraph(nodes=0,edges=0):
+        ''' Return an empty directed graph
+
+            Parameters :
+
+                - nodes : number of nodes to reserveEdges
+                - edges : number of edges to reserve
+
+            Returns :
+
+                - graph
+        '''
+        return graphs.AdjacencyListGraph(nodes,edges)
+
+    listGraph.__module__ = 'vigra.graphs'
+    graphs.listGraph = listGraph
+
+    def intrinsicGraphMapShape(graph,item):
+        """ Intrinsic shape of node/edge/arc-map for a given graph.
+
+            Node edge and arc maps are stored in numpy arrays by default.
+            The instric shape may not be confused with the number
+            of nodes/edges/arcs. The instric shape is used to
+            allocate a numpy are which can store data for nodes/arcs/edgeSizes
+            of a given graph.
+
+            Parameters:
+
+                - graph : input graph to get the shape for
+
+                - item  : item must be ``'node'`` , ``'edge'`` or ``'arc'``
+
+            Returns:
+
+                - shape as tuple
+        """
+        if   item=='edge':
+            return graph.intrinsicEdgeMapShape()
+        elif item=='node':
+            return graph.intrinsicNodeMapShape()
+        elif item=='arc':
+            return graph.intrinsicArcMapShape()
+        else :
+            raise RuntimeError("%s is not valid,must be 'edge','node' or 'arc' "%item)
+
+    intrinsicGraphMapShape.__module__ = 'vigra.graphs'
+    graphs.intrinsicGraphMapShape = intrinsicGraphMapShape
+
+
+    def graphMap(graph,item,dtype=numpy.float32,channels=1,addChannelDim=False):
+        """ Return a graph map for a given graph item (``'node'`` , ``'edge'`` or ``'arc'``).
+
+            Parameters:
+
+                - graph    : graph to get a graph map for
+                - item     : ``'node'`` , ``'edge'`` or ``'arc'``
+                - dtype    : desired dtype
+                - channels : number of channels (default: 1)
+                - addChannelDim -- add an explicit channelDim :(default: False)
+                    only useful if channels == 1
+
+            Returns:
+
+                - graphmap as numpy.ndarray / VigraArray
+        """
+        s = intrinsicGraphMapShape(graph,item)
+        intrDim = len(s)
+        if(channels==1) and addChannelDim==False:
+            a=numpy.zeros(shape=s,dtype=dtype)
+            if intrDim == 1:
+                return taggedView(a,'x')
+            elif intrDim == 2:
+                return taggedView(a,'xy')
+            elif intrDim == 3:
+                return taggedView(a,'xyz')
+            elif intrDim == 4:
+                return taggedView(a,'xyzt')
+            else :
+                raise RuntimeError("graphs with intrisic dimension >4 are not supported")
+        else:
+            s = s+(channels,)
+            a=numpy.zeros(shape=s,dtype=dtype)
+            if intrDim == 1:
+                return taggedView(a,'xc')
+            elif intrDim == 2:
+                return taggedView(a,'xyc')
+            elif intrDim == 3:
+                return taggedView(a,'xyzc')
+            elif intrDim == 4:
+                return taggedView(a,'xyztc')
+            else :
+                raise RuntimeError("graphs with intrisic dimension >4 are not supported")
+
+
+
+    def graphMap2(graph,item,dtype=numpy.float32,channels=1,addChannelDim=False):
+        """ Return a graph map for a given graph item (``'node'`` , ``'edge'`` or ``'arc'``).
+
+            Parameters:
+
+                - graph    : graph to get a graph map for
+                - item     : ``'node'`` , ``'edge'`` or ``'arc'``
+                - dtype    : desired dtype
+                - channels : number of channels (default: 1)
+                - addChannelDim -- add an explicit channelDim :(default: False)
+                    only useful if channels == 1
+
+            Returns:
+
+                - graphmap as numpy.ndarray / VigraArray
+        """
+        s = intrinsicGraphMapShape(graph,item)
+        intrDim = len(s)
+        if(channels==1) and addChannelDim==False:
+            a=numpy.zeros(shape=s,dtype=dtype)
+            if intrDim == 1:
+                return taggedView(a,'x')
+            elif intrDim == 2:
+                return taggedView(a,'xy')
+            elif intrDim == 3:
+                return taggedView(a,'xyz')
+            elif intrDim == 4:
+                return taggedView(a,'xyzt')
+            else :
+                raise RuntimeError("graphs with intrisic dimension >4 are not supported")
+        else:
+            s = s+(channels,)
+            a=numpy.zeros(shape=s,dtype=dtype)
+            if intrDim == 1:
+                return taggedView(a,'xc')
+            elif intrDim == 2:
+                return taggedView(a,'xyc')
+            elif intrDim == 3:
+                return taggedView(a,'xyzc')
+            elif intrDim == 4:
+                return taggedView(a,'xyztc')
+            else :
+                raise RuntimeError("graphs with intrisic dimension >4 are not supported")
+
+    graphMap.__module__ = 'vigra.graphs'
+    graphs.graphMap = graphMap
+
+
+    def mergeGraph(graph):
+        """ get a merge graph from input graph.
+
+            A merge graph might be usefull for hierarchical clustering
+        """
+        #mg = graph.mergeGraph()
+        mg = graphs.__mergeGraph(graph)
+        #mg.__base_graph__=graph
+        return mg
+
+    mergeGraph.__module__ = 'vigra.graphs'
+    graphs.mergeGraph = mergeGraph
+
+
+    INVALID = graphs.Invalid()
+    graphs.INVALID = INVALID
+
+
+
+    class ShortestPathPathDijkstra(object):
+        def __init__(self,graph):
+            """ shortest path computer
+
+                Keyword Arguments:
+
+                    - graph : input graph
+
+            """
+            self.pathFinder =  graphs._shortestPathDijkstra(graph)
+            self.graph=graph
+            self.source = None
+            self.target = None
+        def run(self,weights,source,target=None):
+            """ run shortest path search
+
+                Keyword Arguments:
+
+                   - weights : edge weights encoding distance from two adjacent nodes
+
+                   - source : source node
+
+                   - target : target node (default: None)
+                        If target node is None, the shortest path
+                        to all nodes!=source is computed
+
+            """
+            self.source = source
+            self.target = target
+            if target is None:
+                self.pathFinder.run(weights,source)
+            else:
+                self.pathFinder.run(weights,source,target)
+            return self
+
+        def runIgnoreLargeWeights(self,weights,source,val):
+            """ run shortest path search, nodes with all edge weights larger than val will be ignored
+
+                Keyword Arguments:
+
+                   - weights : edge weights encoding distance from two adjacent nodes
+
+                   - source : source node
+
+                   - val : upper bound
+
+            """
+            self.source = source
+            self.target = None
+            self.pathFinder.runIgnoreLargeWeights(weights,source,val)
+            return self
+
+        def path(self,target=None,pathType='coordinates'):
+            """ get the shortest path from source to target
+
+                Keyword Arguments:
+
+                    - weights : edge weights encoding distance from two adjacent nodes
+
+                    - source : source node
+
+                    - target : target node (default: None)
+                        If target node is None, the target specified
+                        by 'run' is used.
+
+                    pathType : 'coordinates' or 'ids' path (default: 'coordinates')
+
+
+
+            """
+            if target is None:
+                assert self.target is not None
+                target=self.target
+
+            if pathType=='coordinates':
+                return self.pathFinder.nodeCoordinatePath(target)
+            elif pathType == 'ids':
+                return self.pathFinder.nodeIdPath(target)
+        def distance(self,target=None):
+            """ get distance from source to target
+
+                Keyword Arguments:
+                    - target : target node (default: None)
+                        If target node is None, the target specified
+                        by 'run' is used.
+            """
+            if target is None:
+                assert self.target is not None
+                target=self.target
+            return self.pathFinder.distance(target)
+
+        def distances(self,out=None):
+            """ return the full distance map"""
+            return self.pathFinder.distances(out)
+        def predecessors(self,out=None):
+            """ return the full predecessors map"""
+            return self.pathFinder.predecessors(out)
+
+
+    ShortestPathPathDijkstra.__module__ = 'vigra.graphs'
+    graphs.ShortestPathPathDijkstra = ShortestPathPathDijkstra
+
+_genGraphConvenienceFunctions()
+del _genGraphConvenienceFunctions
+
+
+def _genRegionAdjacencyGraphConvenienceFunctions():
+
+
+
+    class RegionAdjacencyGraph(graphs.AdjacencyListGraph):
+        def __init__(self,graph=None ,labels=None ,ignoreLabel=None,reserveEdges=0, maxLabel=None, isDense=None):
+            """ Region adjacency graph
+
+                Keyword Arguments :
+                    - graph : the base graph, the region adjacency graph should be based on
+
+                    - labels : label map for the graph
+
+                    - ignoreLabel : ignore a label in the labels map (default: None)
+
+                    - reserveEdges : reserve a certain number of Edges
+
+                Attributes:
+
+                    - labels : labels passed in constructor
+
+                    - ignoreLabel  : ignoreLabel passed in constructor
+
+                    - baseGraphLabels : labels passed in constructor
+                        (fixme,dublicated attribute (see labels) )
+
+                    - baseGraph : baseGraph is the graph passed in constructor
+
+                    - affiliatedEdges : for each edge in the region adjacency graph,
+                        a vector of edges of the baseGraph is stored in affiliatedEdges
+
+
+            """
+            if(graph is not None and labels is not None):
+                super(RegionAdjacencyGraph,self).__init__(long(labels.max()+1),long(reserveEdges))
+
+                if ignoreLabel is None and isDense is not None and isDense == True:
+                    if ignoreLabel is None:
+                        ignoreLabel=-1
+
+                    self.labels          = labels
+                    self.ignoreLabel     = ignoreLabel
+                    self.baseGraphLabels = labels
+                    self.baseGraph       = graph
+                    if maxLabel is None:
+                        maxLabel = int(numpy.max(labels))
+                    # set up rag
+                    self.affiliatedEdges = graphs._regionAdjacencyGraphFast(graph,labels,self,maxLabel,int(reserveEdges))
+
+                else:
+
+                    if ignoreLabel is None:
+                        ignoreLabel=-1
+
+                    self.labels          = labels
+                    self.ignoreLabel     = ignoreLabel
+                    self.baseGraphLabels = labels
+                    self.baseGraph       = graph
+                    # set up rag
+                    self.affiliatedEdges = graphs._regionAdjacencyGraph(graph,labels,self,self.ignoreLabel)
+            else :
+                super(RegionAdjacencyGraph,self).__init__(0,0)
+
+        def mergeGraph(self):
+            return graphs.AdjacencyListGraphMergeGraph(self)
+
+        def accumulateSeeds(self, seeds, out=None):
+            graph = self.baseGraph
+            labels = self.labels
+            return graphs._pyAccNodeSeeds(self, graph, labels, seeds, out)
+
+        def accumulateEdgeFeatures(self,edgeFeatures,acc='mean',out=None):
+            """ accumulate edge features from base graphs edges features
+
+                Keyword Argument:
+
+                    - edgeFeatures : edge features of baseGraph
+                    - acc : used accumulator (default: 'mean')
+                        Currently only 'mean' and 'sum' are implemented
+                    - out :  preallocated edge map
+
+                Returns :
+                    accumulated edge features
+            """
+            graph = self.baseGraph
+            affiliatedEdges = self.affiliatedEdges
+
+            if isinstance(edgeFeatures, (graphs.ImplicitMEanEdgeMap_2d_float_float, graphs.ImplicitMEanEdgeMap_3d_float_float)):
+
+
+                if graphs.isGridGraph(graph)==False:
+                    raise RuntimeError("implicit edge maps are only implemented for grid graphs")
+
+                return graphs._ragEdgeFeatures(self, graph, affiliatedEdges, edgeFeatures,acc, out)
+
+            else:
+                if self.edgeNum == 0:
+                    raise RuntimeError("self.edgeNum == 0  => cannot accumulate edge features")
+                if acc == 'mean':
+                    weights = self.baseGraph.edgeLengths()
+                    #print "Weights",weights
+                else:
+                    weights = graphs.graphMap(self.baseGraph,'edge',dtype=numpy.float32)
+                    weights[:] = 1
+                if graphs.isGridGraph2d(graph) and edgeFeatures.ndim == 4 :
+                    return graphs._ragEdgeFeaturesMb(self,graph,affiliatedEdges,edgeFeatures,weights,acc,out)
+                else:
+                    return graphs._ragEdgeFeatures(self,graph,affiliatedEdges,edgeFeatures,weights,acc,out)
+
+
+        def accumulateNodeFeatures(self,nodeFeatures,acc='mean',out=None):
+            """ accumulate edge features from base graphs edges features
+
+                Keyword Argument:
+
+                    - nodeFeatures : node features of baseGraph
+                    - acc : used accumulator (default: 'mean')
+                        Currently only 'mean' and 'sum' are implemented
+                    - out :  preallocated node map (default: None)
+
+                Returns :
+                    accumulated node features
+            """
+            if self.edgeNum == 0 :
+              raise RuntimeError("self.edgeNum == 0  => cannot accumulate edge features")
+            graph = self.baseGraph
+            labels = self.baseGraphLabels
+            ignoreLabel = self.ignoreLabel
+            if acc == 'mean':
+              #print "get node size..."
+              weights = self.baseGraph.nodeSize()
+              #print "weights == ", weights
+            else :
+              weights = graphs.graphMap(self.baseGraph,'node',dtype=numpy.float32)
+              weights[:]=1
+
+            return graphs._ragNodeFeatures(self,graph,labels,nodeFeatures,weights,acc,ignoreLabel,out)
+
+        def projectNodeFeatureToBaseGraph(self,features,out=None):
+            """ project node features from this graph, to the base graph of this graph.
+
+                Keyword Arguments:
+
+                    - features : node feautres for this graph
+                    - out :  preallocated node map of baseGraph (default: None)
+
+                Returns :
+                    projected node features of base graph
+            """
+            out=graphs._ragProjectNodeFeaturesToBaseGraph(
+                rag=self,
+                baseGraph=self.baseGraph,
+                baseGraphLabels=numpy.squeeze(self.baseGraphLabels),
+                ragNodeFeatures=features,
+                ignoreLabel=self.ignoreLabel,
+                out=out
+            )
+            #print "out",out.shape,out.dtype
+            return out
+
+        def projectLabelsBack(self,steps,labels=None,_current=0):
+            """  project labels from current graph to baseGraph and repeat this recursively
+
+                Keyword  Arguments:
+
+                    - steps : how often should the labels be projected back
+                    - labels : labels for the current graph (default: None)
+                        If labels is None, each node gets its own label
+            """
+            if labels is None :
+                # identity segmentation on this level
+                labels = self.nodeIdMap()
+
+            if steps == _current :
+                return labels
+            else :
+                labels = self.projectLabelsToBaseGraph(labels)
+                return self.baseGraph.projectLabelsBack(steps,labels,_current+1)
+
+
+        def projectLabelsToBaseGraph(self,labels=None):
+            """ project node labels from this graph, to the base graph of this graph.
+
+                Keyword Arguments:
+
+                    - labels : node labels for this graph (default: None)
+                        If labels is None, each node gets its own label
+                    - out :  preallocated node map of baseGraph (default: None)
+
+                Returns :
+            """
+            if labels is None :
+                # identity segmentation on this level
+                labels = self.nodeIdMap()
+            return self.projectNodeFeatureToBaseGraph(features=labels)
+
+        def projectBaseGraphGt(self, baseGraphGt, gt=None, gtQuality=None):
+            bggt = numpy.require(baseGraphGt,dtype=numpy.uint32)
+            gt, gtQuality = graphs._ragProjectGroundTruth(rag=self, graph=self.baseGraph,
+                                                          labels=self.baseGraphLabels, gt=bggt,
+                                                          ragGt=gt, ragGtQuality=gtQuality)
+            return gt, gtQuality
+
+
+        def edgeUVCoordinates(self, edgeId):
+
+            try :
+                ei = int(edgeId)
+            except:
+                ei = edgeId.id
+
+            affEdges = self.affiliatedEdges
+            uvCoords = affEdges.getUVCoordinates(self.baseGraph, ei)
+            dim = uvCoords.shape[1]/2
+            uCoords = uvCoords[:,0:dim]
+            vCoords = uvCoords[:,dim:2*dim]
+            return (uCoords,vCoords)
+
+        def edgeTopologicalCoordinates(self, edgeId):
+            uc,vc = self.edgeUVCoordinates(edgeId)
+            return uc+vc
+
+        def edgeCoordinates(self, edgeId):
+            uc,vc = self.edgeUVCoordinates(edgeId)
+            return (uc+vc)/2.0
+
+    RegionAdjacencyGraph.__module__ = 'vigra.graphs'
+    graphs.RegionAdjacencyGraph = RegionAdjacencyGraph
+
+    class GridRegionAdjacencyGraph(graphs.RegionAdjacencyGraph):
+        def __init__(self,graph=None,labels=None,ignoreLabel=None,reserveEdges=0, maxLabel=None, isDense=None):
+            """ Grid Region adjacency graph
+
+                A region adjaceny graph,where the base graph should be
+                a grid graph or a GridRegionAdjacencyGraph.
+
+
+                Keyword Arguments :
+                    - graph : the base graph, the region adjacency graph should be based on
+
+                    - labels : label map for the graph
+
+                    - ignoreLabel : ignore a label in the labels map (default: None)
+
+                    - reserveEdges : reserve a certain number of Edges
+
+                Attributes :
+
+                    - labels : labels passed in constructor
+
+                    - ignoreLabel  : ignoreLabel passed in constructor
+
+                    - baseGraphLabels : labels passed in constructor
+                        (fixme,dublicated attribute (see labels) )
+
+                    - baseGraph : baseGraph is the graph passed in constructor
+
+                    - affiliatedEdges : for each edge in the region adjacency graph,
+                        a vector of edges of the baseGraph is stored in affiliatedEdges
+
+                    - shape : shape of the grid graph which is a base graph in the
+                        complete graph chain.
+
+
+            """
+            if graph is not None and labels is not None:
+                if not (graphs.isGridGraph(graph) or  isinstance(graph,GridRegionAdjacencyGraph)):
+                    raise RuntimeError("graph must be a GridGraph or a GridRegionAdjacencyGraph")
+                super(GridRegionAdjacencyGraph, self).__init__(graph, labels, ignoreLabel, reserveEdges, maxLabel, isDense)
+            else:
+                super(GridRegionAdjacencyGraph, self).__init__()
+
+        @property
+        def shape(self):
+            """ shape of the underlying grid graph"""
+            return self.baseGraph.shape
+
+        def projectLabelsToGridGraph(self,labels=None):
+            """project labels of this graph to the underlying grid graph.
+
+                Keyword Arguments :
+
+                    - labels : node labeling of this graph (default: None)
+                        If labels is None, each node gets its own label
+
+                Returns :
+                    grid graph labeling
+
+            """
+            if labels is None :
+                # identity segmentation on this level
+                labels = self.nodeIdMap()
+
+            if graphs.isGridGraph(self.baseGraph):
+                return self.projectLabelsToBaseGraph(labels)
+            else :
+                labels = self.projectLabelsToBaseGraph(labels)
+                return self.baseGraph.projectLabelsToGridGraph(labels)
+
+        def projectNodeFeaturesToGridGraph(self,features):
+            """ project features of this graph to the underlying grid graph.
+                Therefore project the features to an image.
+
+                Keyword Arguments :
+
+                    - features : nodeFeatures of the current graph
+
+                Returns :
+                    grid graph labeling
+
+            """
+            if graphs.isGridGraph(self.baseGraph):
+                return self.projectNodeFeatureToBaseGraph(features)
+            else :
+                features = self.projectNodeFeatureToBaseGraph(features)
+                return self.baseGraph.projectNodeFeaturesToGridGraph(features)
+
+        def showNested(self,img,labels=None,returnImg=False):
+            """ show the complet graph chain  / hierarchy given an RGB image
+
+                Keyword Arguments:
+                    - img : RGB image
+
+                    - labels : node labeling of this graph (default: None)
+                        If labels is None, each node gets its own label
+            """
+            ll=[]
+            if labels is not None:
+              ll.append( self.projectLabelsToGridGraph(labels) )
+            ll.append( self.projectLabelsToGridGraph() )
+
+            g=self.baseGraph
+            while graphs.isGridGraph(g)==False:
+              ll.append( g.projectLabelsToGridGraph() )
+              g=g.baseGraph
+
+
+            ll.reverse()
+            gridLabels = [l[...,numpy.newaxis] for l in ll ]
+            gridLabels = numpy.concatenate(gridLabels,axis=2)
+
+
+            return nestedSegShow(img,gridLabels,returnImg=returnImg)
+
+
+        def show(self,img,labels=None,edgeColor=(0,0,0),alpha=0.3,returnImg=False):
+            """ show the graph given an RGB image
+
+                Keyword Arguments:
+                    - img : RGB image
+
+                    - labels : node labeling of this graph (default: None)
+                        If labels is None, each node gets its own label
+
+                    - edgeColor : RGB tuple of edge color (default: (0,0,0) ).
+                        Do not use values bigger than 1 in edgeColor.
+
+                    - alpha : make edges semi transparent (default: 0.3).
+                        0 means no transparency,1 means full transparency.
+            """
+            pLabels = self.projectLabelsToGridGraph(labels)
+            return segShow(img,numpy.squeeze(pLabels),edgeColor=edgeColor,alpha=alpha,returnImg=returnImg)
+
+
+        def showEdgeFeature(self, img, edgeFeature, cmap='jet', returnImg=False, labelMode=False):
+            import matplotlib
+            assert graphs.isGridGraph(self.baseGraph)
+            imgOut = img.copy().squeeze()
+            if imgOut.ndim == 2:
+                imgOut = numpy.concatenate([imgOut[:,:,None]]*3,axis=2)
+            imgOut = taggedView(imgOut,'xyc')
+            imgOut-=imgOut.min()
+            imgOut/=imgOut.max()
+
+            if not labelMode:
+                edgeFeatureShow = edgeFeature.copy()
+                mi = edgeFeatureShow.min()
+                ma = edgeFeatureShow.max()
+                cm = matplotlib.cm.ScalarMappable(cmap=cmap)
+                rgb = cm.to_rgba(edgeFeatureShow)[:,0:3]
+                print rgb.shape
+
+                if(ma > mi):
+                    edgeFeatureShow -=mi
+                    edgeFeatureShow /= edgeFeatureShow.max()
+                else:
+                    edgeFeatureShow[:] = 1
+
+            for e in self.edgeIter():
+
+                u,v = self.edgeUVCoordinates(e.id)
+
+                if not labelMode:
+                    showVal = rgb[e.id,:]
+                else:
+                    if edgeFeature[e.id] == 0:
+                        showVal=[0,0,1]
+                    elif edgeFeature[e.id] == 1:
+                        showVal=[0,1,0]
+                    elif edgeFeature[e.id] == -1:
+                        showVal=[1,0,0]
+
+                imgOut[u[:,0],u[:,1],:] = showVal
+                imgOut[v[:,0],v[:,1],:] = showVal
+                #print u.shape
+            if returnImg:
+                return imgOut
+            imshow(imgOut)
+
+
+
+
+        def nodeSize(self):
+            """ get the geometric size of the nodes """
+            if graphs.isGridGraph(self.baseGraph):
+                return graphs._ragNodeSize(self, self.baseGraph, self.labels, self.ignoreLabel)
+            else:
+                baseNodeSizes = self.baseGraph.nodeSize()
+                return self.accumulateNodeFeatures(baseNodeSizes,acc='sum')
+        def edgeLengths(self):
+            """ get the geometric length of the edges"""
+            if graphs.isGridGraph(self.baseGraph):
+                return graphs._ragEdgeSize(self,self.affiliatedEdges)
+            else:
+                baseNodeSizes = self.baseGraph.edgeLengths()
+                return self.accumulateEdgeFeatures(baseNodeSizes,acc='sum')
+
+
+        def writeHDF5(self, filename, dset):
+            if(graphs.isGridGraph(self.baseGraph)):
+
+                sGraph    = self.serialize()
+                sAffEdges = graphs._serialzieGridGraphAffiliatedEdges(self.baseGraph, self, self.affiliatedEdges )
+                sLabels   = self.labels
+
+
+                writeHDF5(numpy.array([self.ignoreLabel]), filename, dset+'/ignore_label')
+                writeHDF5(sLabels, filename, dset+'/labels')
+                writeHDF5(sGraph, filename, dset+'/graph')
+                writeHDF5(sAffEdges, filename, dset+'/affiliated_edges')
+
+
+            else:
+                raise RuntimeError("only RAGs of Grid graph can be serialized")
+
+
+        #def readHdf5(self, filename, dset):
+        #    labels = readHdf5(filename,  dset+'/labels')
+        #    shape = labels.shape
+        #    self.baseGraph  = graphs.gridGraph(shape)
+
+
+
+    GridRegionAdjacencyGraph.__module__ = 'vigra.graphs'
+    graphs.GridRegionAdjacencyGraph = GridRegionAdjacencyGraph
+
+
+    class TinyEdgeLabelGui(object):
+        def __init__(self, rag, img, edgeLabels = None, labelMode=True):
+
+            if labelMode and isinstance(edgeLabels, numpy.ndarray):
+                assert set(numpy.unique(edgeLabels)).issubset({-1, 0, 1}), 'if labelMode is true only label values of [-1, 0, 1] are permitted'
+
+            self.press = None
+            self.rag = rag
+            self.img = img
+            self.edgeLabels = edgeLabels
+            self.dim = len(img.shape)
+            self.zOffset = 0
+            self.edgeRag2dToRag = None
+            self.edgeRagToRag2d = None
+            if self.dim == 3:
+                self.zOffset = self.img.shape[2]/2
+
+            self.visuImg = numpy.array(img, dtype=numpy.float32)
+            self.visuImg -= self.visuImg.min()
+            self.visuImg /= self.visuImg.max()
+
+            self.rag2d = None
+            self.visuImg2d = None
+
+            self.labelMode = labelMode
+
+            if self.edgeLabels is None :
+                self.edgeLabels = numpy.zeros(self.rag.edgeNum, dtype=numpy.float32)
+            self.edgeLabels2d = None
+
+            self.slice2d()
+
+            self.implot = None
+            self.currentLabel  = 1
+
+            self.brushSize = 1
+
+
+        def startGui(self):
+            from functools import partial
+            import pylab as plt
+            from matplotlib.widgets import Slider, Button, RadioButtons
+
+
+            ax = plt.gca()
+            fig = plt.gcf()
+
+            imgWithEdges =self.rag2d.showEdgeFeature(self.visuImg2d, self.edgeLabels2d, returnImg=True, labelMode=self.labelMode)
+            self.implot = ax.imshow(numpy.swapaxes(imgWithEdges,0,1))
+
+            ff = partial(self.onclick, self)
+
+            cid = fig.canvas.mpl_connect('button_press_event', self.onclick)
+
+            fig.canvas.mpl_connect('key_press_event', self.press_event)
+
+            fig.canvas.mpl_connect('scroll_event', self.scroll)
+
+            fig.canvas.mpl_connect('motion_notify_event', self.on_motion)
+            fig.canvas.mpl_connect('button_release_event', self.on_release)
+
+            if self.labelMode:
+                axcolor = 'lightgoldenrodyellow'
+                axamp  = plt.axes([0.25, 0.15, 0.65, 0.03], axisbg=axcolor)
+                self.slideBrush = Slider(axamp, 'brush-size', 1, 20.0, valinit=2)
+
+                self.slideBrush.on_changed(self.updateBrushSize)
+
+            plt.show()
+
+
+        def updateBrushSize(self, val):
+            self.brushSize = int(val+0.5)
+
+
+
+        def press_event(self, event):
+            sys.stdout.flush()
+            if event.key=='0' or event.key=='3':
+                self.currentLabel = 0
+            if event.key=='1':
+                self.currentLabel = 1
+            if event.key=='2':
+                self.currentLabel = -1
+
+
+        def slice2d(self):
+            if self.dim==3:
+                labels = self.rag.labels[:,:,self.zOffset].squeeze()
+                gg = graphs.gridGraph(labels.shape)
+                self.rag2d = graphs.regionAdjacencyGraph(gg, labels)
+                # update edges 2d:
+                self.edgeLabels2d = numpy.zeros(self.rag2d.edgeNum, dtype=numpy.float32)
+
+                # update edge correlation
+                self.edgeIdRag2dToRag = dict()
+                self.edgeIdRagToRag2d = dict()
+                for edge in self.rag2d.edgeIter():
+                    edge3d = self.rag.findEdge(edge.u, edge.v)
+                    self.edgeIdRag2dToRag[edge.id] = edge3d.id
+                    self.edgeIdRagToRag2d[edge3d.id] = edge.id
+                self.visuImg2d = self.visuImg[:,:,self.zOffset]
+
+                # update edge 2d status:
+                for i in numpy.arange(self.edgeLabels2d.shape[0]):
+                    self.edgeLabels2d[i] = self.edgeLabels[self.edgeIdRag2dToRag[i]]
+
+            elif self.dim==2:
+                self.rag2d = self.rag
+                self.visuImg2d = self.visuImg
+                self.edgeIdRag2dToRag = dict()
+                for edge in self.rag.edgeIter():
+                    self.edgeIdRag2dToRag[edge.id] = edge.id
+
+                self.edgeIdRagToRag2d = self.edgeIdRag2dToRag
+                self.edgeLabels2d = self.edgeLabels
+
+            else:
+                print 'warning: bad dimension!'
+
+
+        def scroll(self, event):
+            import pylab as plt
+            if self.dim==3:
+                if event.button == 'up':
+                    self.zOffset += 1
+                else:
+                    self.zOffset -= 1
+
+                self.zOffset = self.zOffset % self.visuImg.shape[2]
+                self.slice2d()
+                imgWithEdges = self.rag2d.showEdgeFeature(self.visuImg2d, self.edgeLabels2d,returnImg=True, labelMode=self.labelMode)
+                self.implot.set_data(numpy.swapaxes(imgWithEdges,0,1))
+                plt.draw()
+        def on_motion(self, event):
+
+            if self.press is None:
+                return
+
+            print event.xdata, event.ydata
+            self.handle_click(event)
+
+        def on_release(self, event):
+            self.press = None
+
+        def onclick(self, event):
+            self.press = event.xdata, event.ydata
+            print event.xdata, event.ydata
+            try:
+                self.handle_click(event)
+            except:
+                pass
+        def handle_click(self, event):
+
+            import pylab as plt
+            if event.button==1:
+                self.currentLabel = 1
+            if event.button==2:
+                self.currentLabel = 0
+            if event.button==3:
+                self.currentLabel = -1
+
+
+            img = self.img
+            rag  = self.rag2d
+            labels = rag.baseGraphLabels
+            shape = img.shape
+            if event.xdata != None and event.ydata != None:
+                xRaw,yRaw = event.xdata,event.ydata
+                if xRaw >=0.0 and yRaw>=0.0 and xRaw<img.shape[0] and yRaw<img.shape[1]:
+                    x,y = long(math.floor(event.xdata)),long(math.floor(event.ydata))
+
+                    #print "X,Y",x,y
+                    l = labels[x,y]
+                    others  = []
+
+                    bs = self.brushSize
+                    for xo in range(-1*bs, bs+1):
+                        for yo in range(-1*bs, bs+1):
+                            xx = x+xo
+                            yy = y+yo
+                            if xo is not 0 or yo is not 0:
+                                if  xx >=0 and xx<shape[0] and \
+                                    yy >=0 and yy<shape[0]:
+                                    otherLabel = labels[xx, yy]
+                                    if l != otherLabel:
+                                        edge = rag.findEdge(long(l), long(otherLabel))
+                                    #print edge
+                                        others.append((xx,yy,edge))
+                                        #break
+                        #if other is not None:
+                        #    pass
+
+                    if self.labelMode:
+                        for other in others:
+                            eid = other[2].id
+                            oldLabel  = self.edgeLabels[self.edgeIdRag2dToRag[eid]]
+
+                            if self.currentLabel == oldLabel:
+                                newLabel = oldLabel
+                            else:
+                                newLabel = self.currentLabel
+
+
+
+                            self.edgeLabels[self.edgeIdRag2dToRag[eid]] = newLabel
+                            self.edgeLabels2d[eid] = newLabel
+                        imgWithEdges = rag.showEdgeFeature(self.visuImg2d, self.edgeLabels2d,returnImg=True, labelMode=self.labelMode)
+                        self.implot.set_data(numpy.swapaxes(imgWithEdges,0,1))
+                        plt.draw()
+
+
+    TinyEdgeLabelGui.__module__ = 'vigra.graphs'
+    graphs.TinyEdgeLabelGui = TinyEdgeLabelGui
+
+
+    def loadGridRagHDF5(filename , dset):
+
+        #print "load labels and make grid graph"
+        labels = readHDF5(filename,  dset+'/labels')
+        shape = labels.shape
+        gridGraph = graphs.gridGraph(shape)
+        #print gridGraph
+
+
+        #print "load graph serialization"
+        graphSerialization = readHDF5(filename, dset+'/graph')
+
+        #print "make empty grid rag"
+        gridRag = GridRegionAdjacencyGraph()
+
+        #print "deserialize"
+        gridRag.deserialize(graphSerialization)
+
+
+        #print "load affiliatedEdges"
+        affEdgeSerialization = readHDF5(filename, dset+'/affiliated_edges')
+
+        #print "deserialize"
+        affiliatedEdges = graphs._deserialzieGridGraphAffiliatedEdges(gridGraph, gridRag, affEdgeSerialization)
+
+
+        ignoreLabel =  readHDF5(filename, dset+'/ignore_label')
+
+        gridRag.affiliatedEdges = affiliatedEdges
+        gridRag.labels          = taggedView(labels,"xyz")
+        gridRag.ignoreLabel     = int(ignoreLabel[0])
+        gridRag.baseGraphLabels = taggedView(labels,"xyz")
+        gridRag.baseGraph       = gridGraph
+
+        return gridRag
+
+
+
+
+    loadGridRagHDF5.__module__ = 'vigra.graphs'
+    graphs.loadGridRagHDF5 = loadGridRagHDF5
+
+    def regionAdjacencyGraph(graph,labels,ignoreLabel=None,reserveEdges=0, maxLabel=None, isDense=None):
+        """ Return a region adjacency graph for a labeld graph.
+
+            Parameters:
+
+                - graph  -- input graph
+                - lables -- node-map with labels for each nodeSumWeights
+                - ignoreLabel -- label to ingnore (default: None)
+                - reserveEdges -- reverse a certain number of edges (default: 0)
+
+            Returns:
+                - rag -- instance of RegionAdjacencyGraph or GridRegionAdjacencyGraph
+                    If graph is a GridGraph or a GridRegionAdjacencyGraph, a GridRegionAdjacencyGraph
+                    will be returned.
+                    Otherwise a RegionAdjacencyGraph will be returned
+        """
+        if isinstance(graph , graphs.GridRegionAdjacencyGraph) or graphs.isGridGraph(graph):
+            return GridRegionAdjacencyGraph(graph=graph, labels=labels, ignoreLabel=ignoreLabel,
+                                            reserveEdges=reserveEdges, maxLabel=maxLabel, isDense=isDense)
+        else:
+            return RegionAdjacencyGraph(graph=graph, labels=labels, ignoreLabel=ignoreLabel,
+                                        reserveEdges=reserveEdges, maxLabel=maxLabel, isDense=isDense)
+
+
+    regionAdjacencyGraph.__module__ = 'vigra.graphs'
+    graphs.regionAdjacencyGraph = regionAdjacencyGraph
+
+
+
+
+
+
+    def gridRegionAdjacencyGraph(labels,ignoreLabel=None,reserveEdges=0, maxLabel=None, isDense=None):
+        """ get a region adjacency graph and a grid graph from a labeling.
+
+            This function will call 'graphs.gridGraph' and 'graphs.regionAdjacencyGraph'
+
+            Keyword Arguments:
+                - labels : label image
+                - ignoreLabel : label to ingnore (default: None)
+                - reserveEdges : reserve a number of edges (default: 0)
+        """
+        _gridGraph=graphs.gridGraph(numpy.squeeze(labels).shape)
+        rag=graphs.regionAdjacencyGraph(graph=_gridGraph, labels=labels, ignoreLabel=ignoreLabel,
+                                        reserveEdges=reserveEdges, maxLabel=maxLabel, isDense=isDense)
+        return _gridGraph, rag
+
+    gridRegionAdjacencyGraph.__module__ = 'vigra.graphs'
+    graphs.gridRegionAdjacencyGraph = gridRegionAdjacencyGraph
+
+_genRegionAdjacencyGraphConvenienceFunctions()
+del _genRegionAdjacencyGraphConvenienceFunctions
+
+
+def _genGraphSegmentationFunctions():
+
+    def getNodeSizes(graph):
+        """ get size of nodes:
+
+            This functions will try to call 'graph.nodeSize()' .
+            If this fails, a node map filled with 1.0 will be
+            returned
+
+            Keyword Arguments:
+
+                - graph : input graph
+        """
+        try:
+            return graph.nodeSize()
+        except:
+            size = graphs.graphMap(graph,'node',dtype=numpy.float32)
+            size[:]=1
+            return size
+    getNodeSizes.__module__ = 'vigra.graphs'
+    graphs.getNodeSizes = getNodeSizes
+
+    def getEdgeLengths(graph):
+        """ get lengths/sizes of edges:
+
+            This functions will try to call 'graph.edgeLength()' .
+            If this fails, an edge map filled with 1.0 will be
+            returned
+
+            Keyword Arguments:
+
+                - graph : input graph
+        """
+        try:
+            return graph.edgeLengths()
+        except:
+            size = graphs.graphMap(graph,'edge',dtype=numpy.float32)
+            size[:]=1
+            return size
+    getEdgeLengths.__module__ = 'vigra.graphs'
+    graphs.getEdgeLengths = getEdgeLengths
+
+
+    def felzenszwalbSegmentation(graph,edgeWeights,nodeSizes=None,k=1.0,nodeNumStop=None,out=None):
+        """ felzenszwalbs segmentation method
+
+        Keyword Arguments :
+
+            - graph : input graph
+
+            - edgeWeights : edge weights / indicators
+
+            - nodeSizes : size of each node (default: None)
+                If nodeSizes is None, 'getNodeSizes' will be called
+
+            - k : free parameter in felzenszwalbs algorithms (default : 1.0)
+                (todo: write better docu)
+
+            - nodeNumStop : stop the agglomeration at a given nodeNum (default :None)
+                If nodeNumStop is None, the resulting number of nodes does depends on k.
+
+
+            - backgroundBias : backgroundBias (default  : None)
+
+        """
+        if nodeNumStop is None :
+            nodeNumStop=-1
+        if nodeSizes is None :
+            nodeSizes=graphs.getNodeSizes(graph)
+        return graphs._felzenszwalbSegmentation(graph=graph,edgeWeights=edgeWeights,nodeSizes=nodeSizes,
+                                                k=k,nodeNumStop=nodeNumStop,out=out)
+
+
+    felzenszwalbSegmentation.__module__ = 'vigra.graphs'
+    graphs.felzenszwalbSegmentation = felzenszwalbSegmentation
+
+
+    def edgeWeightedWatersheds(graph,edgeWeights,seeds,backgroundLabel=None,backgroundBias=None,out=None):
+        """ edge weighted seeded watersheds
+
+        Keyword Arguments :
+
+            - graph : input graph
+
+            - edgeWeights : evaluation weights
+
+            - seeds : node map with seeds .
+                For at least one node, seeds must be nonzero
+
+            - backgroundLabel : a specific backgroundLabel (default : None)
+
+            - backgroundBias : backgroundBias (default  : None)
+
+        """
+        if backgroundLabel is None and backgroundBias is None:
+            return graphs._edgeWeightedWatershedsSegmentation(graph=graph,edgeWeights=edgeWeights,seeds=seeds,
+                                                                out=out)
+        else :
+            if backgroundLabel is None or backgroundBias is None:
+                raise RuntimeError("if backgroundLabel or backgroundBias is not None, the other must also be not None")
+            return graphs._carvingSegmentation(graph=graph,edgeWeights=edgeWeights,seeds=seeds,
+                                                backgroundLabel=backgroundLabel,backgroundBias=backgroundBias,out=out)
+
+    edgeWeightedWatersheds.__module__ = 'vigra.graphs'
+    graphs.edgeWeightedWatersheds = edgeWeightedWatersheds
+
+    def nodeWeightedWatershedsSeeds(graph,nodeWeights,out=None):
+        """ generate watersheds seeds
+
+        Keyword Arguments :
+
+            - graph : input graph
+
+            - nodeWeights : node height map
+
+            - out : seed map
+
+        """
+        return graphs._nodeWeightedWatershedsSeeds(graph=graph,nodeWeights=nodeWeights,out=out)
+
+    nodeWeightedWatershedsSeeds.__module__ = 'vigra.graphs'
+    graphs.nodeWeightedWatershedsSeeds = nodeWeightedWatershedsSeeds
+
+
+    def shortestPathSegmentation(graph, edgeWeights, nodeWeights, seeds=None, out=None):
+        """ node weighted seeded watersheds
+
+        Keyword Arguments :
+
+            - graph : input graph
+
+            - edgeWeights : edge weight map
+
+            - nodeWeights : node weight map
+
+            - seeds : node map with seeds (default: None)
+                If seeds are None, 'nodeWeightedWatershedsSeeds' will be called
+
+        """
+
+        if seeds  is None:
+            seeds = graphs.nodeWeightedWatershedsSeeds(graph=graph,nodeWeights=nodeWeights)
+        return graphs._shortestPathSegmentation(graph=graph, edgeWeights=edgeWeights, nodeWeights=nodeWeights,
+                                                seeds=seeds, out=out)
+
+    shortestPathSegmentation.__module__ = 'vigra.graphs'
+    graphs.shortestPathSegmentation = shortestPathSegmentation
+
+    def nodeWeightedWatersheds(graph,nodeWeights,seeds=None,method='regionGrowing',out=None):
+        """ node weighted seeded watersheds
+
+        Keyword Arguments :
+
+            - graph : input graph
+
+            - nodeWeights : node height map / evaluation weights
+
+            - seeds : node map with seeds (default: None)
+                If seeds are None, 'nodeWeightedWatershedsSeeds' will be called
+
+        """
+
+        if seeds  is None:
+            seeds = graphs.nodeWeightedWatershedsSeeds(graph=graph,nodeWeights=nodeWeights)
+        if method!='regionGrowing':
+            raise RuntimeError("currently only 'regionGrowing' is supported")
+        return graphs._nodeWeightedWatershedsSegmentation(graph=graph,nodeWeights=nodeWeights,seeds=seeds,method=method,out=out)
+
+    nodeWeightedWatersheds.__module__ = 'vigra.graphs'
+    graphs.nodeWeightedWatersheds = nodeWeightedWatersheds
+
+
+
+
+
+
+
+
+    def seededSegmentation(graph, nodeMap=None, edgeMap=None, seeds=None, alg='ws',out=None,**kwargs):
+        """
+            alg:
+                - 'ws' watershed
+                - 'sp' shortest path
+                - 'crf' crf/mrf method
+                - 'hc' hierarchical-clustering method
+        """
+
+        if alg == 'ws':
+            # "default" node weighted watershed
+            if nodeMap is not None and edgeMap is None:
+                seg = graphs.nodeWeightedWatersheds(graph=graph,
+                                                         nodeWeights=nodeMap,
+                                                         seeds=seeds,out=out)
+            # edge weighted watershed
+            elif nodeMap is None and edgeMap is not None:
+                seg = graphs.edgeWeightedWatersheds(graph=graph,
+                                                         edgeWeights=edgeMap,
+                                                         seeds=seeds,out=out)
+            # hybrid (not yet implemented)
+            elif nodeMap is not None and edgeMap is not None:
+                raise RuntimeError("Not Yet Implemented")
+            else :
+                # error
+                raise RuntimeError("error")
+
+        elif alg == 'sp':
+            # "default" shortest path
+            if nodeMap is None and edgeMap is  None:
+                raise RuntimeError("Not Yet Implemented")
+            elif nodeMap is not None or edgeMap is not None:
+                if nodeMap is None:
+                    nodeMap = graphs.graphMap(graph,'node',dtype='float32')
+                    nodeMap[:] = 0
+                if edgeMap is None:
+                    edgeMap = graphs.graphMap(graph,'edge',dtype='float32')
+                    edgeMap[:] = 0
+                seg = graphs.shortestPathSegmentation(graph=graph,
+                                                           edgeWeights=edgeMap,
+                                                           nodeWeights=nodeMap,
+                                                           seeds=seeds,out=out)
+
+            else :
+                # error
+                raise RuntimeError("error")
+
+        elif alg == 'crf':
+            raise RuntimeError("Not Yet Implemented")
+
+
+        return seg
+
+    seededSegmentation.__module__ = 'vigra.graphs'
+    graphs.seededSegmentation = seededSegmentation
+
+
+    def wsDtSegmentation(pmap, pmin, minMembraneSize, minSegmentSize, sigmaMinima, sigmaWeights, cleanCloseSeeds=True):
+        """A probability map 'pmap' is provided and thresholded using pmin.
+        This results in a mask. Every connected component which has fewer pixel
+        than 'minMembraneSize' is deleted from the mask. The mask is used to
+        calculate the signed distance transformation.
+
+        From this distance transformation the segmentation is computed using
+        a seeded watershed algorithm. The seeds are placed on the local maxima
+        of the distanceTrafo after smoothing with 'sigmaMinima'.
+
+        The weights of the watershed are defined by the inverse of the signed
+        distance transform smoothed with 'sigmaWeights'.
+
+        'minSegmentSize' determines how small the smallest segment in the final
+        segmentation is allowed to be. If there are smaller ones the corresponding
+        seeds are deleted and the watershed is done again.
+
+        If 'cleanCloseSeeds' is True, multiple seed points that are clearly in the
+        same neuron will be merged with a heuristik that ensures that no seeds of
+        two different neurons are merged.
+        """
+
+        def cdist(xy1, xy2):
+            # influenced by: http://stackoverflow.com/a/1871630
+            d = numpy.zeros((xy1.shape[1], xy1.shape[0], xy1.shape[0]))
+            for i in numpy.arange(xy1.shape[1]):
+                d[i,:,:] = numpy.square(numpy.subtract.outer(xy1[:,i], xy2[:,i]))
+            d = numpy.sum(d, axis=0)
+            return numpy.sqrt(d)
+
+        def findBestSeedCloserThanMembrane(seeds, distances, distanceTrafo, membraneDistance):
+            """ finds the best seed of the given seeds, that is the seed with the highest value distance transformation."""
+            closeSeeds = distances <= membraneDistance
+            numpy.zeros_like(closeSeeds)
+            # iterate over all close seeds
+            maximumDistance = -numpy.inf
+            mostCentralSeed = None
+            for seed in seeds[closeSeeds]:
+                if distanceTrafo[seed[0], seed[1], seed[2]] > maximumDistance:
+                    maximumDistance = distanceTrafo[seed[0], seed[1], seed[2]]
+                    mostCentralSeed = seed
+            return mostCentralSeed
+
+
+        def nonMaximumSuppressionSeeds(seeds, distanceTrafo):
+            """ removes all seeds that have a neigbour that is closer than the the next membrane
+
+            seeds is a list of all seeds, distanceTrafo is array-like
+            return is a list of all seeds that are relevant.
+
+            works only for 3d
+            """
+            seedsCleaned = set()
+
+            # calculate the distances from each seed to the next seeds.
+            distances = cdist(seeds, seeds)
+            for i in numpy.arange(len(seeds)):
+                membraneDistance = distanceTrafo[seeds[i,0], seeds[i,1], seeds[i,2]]
+                bestAlternative = findBestSeedCloserThanMembrane(seeds, distances[i,:], distanceTrafo, membraneDistance)
+                seedsCleaned.add(tuple(bestAlternative))
+            return numpy.array(list(seedsCleaned))
+
+
+        def volumeToListOfPoints(seedsVolume, threshold=0.):
+            return numpy.array(numpy.where(seedsVolume > threshold)).transpose()
+
+
+        def placePointsInVolumen(points, shape):
+            volumen = numpy.zeros(shape)
+            points = numpy.maximum(points, numpy.array((0, 0, 0)))
+            points = numpy.minimum(points, numpy.array(shape) - 1)
+            for point in (numpy.floor(points)).astype(int):
+                volumen[point[0], point[1], point[2]] = 1
+            return volumen
+
+        # get the thresholded pmap
+        binary = numpy.zeros_like(pmap, dtype=numpy.uint32)
+        binary[pmap >= pmin] = 1
+
+        # delete small CCs
+        labeled = analysis.labelVolumeWithBackground(binary)
+        analysis.sizeFilterSegInplace(labeled, int(numpy.max(labeled)), int(minMembraneSize), checkAtBorder=True)
+
+        # use cleaned binary image as mask
+        mask = numpy.zeros_like(binary, dtype = numpy.float32)
+        mask[labeled > 0] = 1.
+
+        # perform signed dt on mask
+        dt = filters.distanceTransform3D(mask)
+        dtInv = filters.distanceTransform3D(mask, background=False)
+        dtInv[dtInv>0] -= 1
+        dtSigned = dt.max() - dt + dtInv
+
+        dtSignedSmoothMinima = filters.gaussianSmoothing(dtSigned, sigmaMinima)
+        dtSignedSmoothWeights = filters.gaussianSmoothing(dtSigned, sigmaWeights)
+
+        seeds = analysis.localMinima3D(dtSignedSmoothMinima, neighborhood=26, allowAtBorder=True)
+
+        if cleanCloseSeeds:
+            seeds = nonMaximumSuppressionSeeds(volumeToListOfPoints(seeds), dt)
+            seeds = placePointsInVolumen(seeds, mask.shape).astype(numpy.uint32)
+
+        seedsLabeled = analysis.labelVolumeWithBackground(seeds)
+        segmentation = analysis.watershedsNew(dtSignedSmoothWeights, seeds = seedsLabeled, neighborhood=26)[0]
+
+        analysis.sizeFilterSegInplace(segmentation, int(numpy.max(segmentation)), int(minSegmentSize), checkAtBorder=True)
+
+        segmentation = analysis.watershedsNew(dtSignedSmoothWeights, seeds = segmentation, neighborhood=26)[0]
+
+        return segmentation
+
+
+    wsDtSegmentation.__module__ = 'vigra.analysis'
+    analysis.wsDtSegmentation = wsDtSegmentation
+
+
+
+    def agglomerativeClustering(graph,edgeWeights=None,edgeLengths=None,nodeFeatures=None,nodeSizes=None,
+            nodeLabels=None,nodeNumStop=None,beta=0.5,metric='l1',wardness=1.0,out=None):
+        """ agglomerative hierarchicalClustering
+        Keyword Arguments :
+
+            - graph : input graph
+
+            - edgeWeights : edge weights / indicators (default : None)
+
+            - edgeLengths : length  / weight of each edge (default : None)
+                Since we do weighted mean agglomeration, a length/weight
+                is needed for each edge to merge 2 edges w.r.t. weighted mean.
+                If no edgeLengths is given, 'getEdgeLengths' is called.
+
+            - nodeFeatures : a feature vector for each node (default: None)
+                A feature vector as RGB values,or a histogram for each node.
+                Within the agglomeration, an additional edge weight will be
+                computed from the "difference" between the features of two adjacent nodes.
+                The metric specified in the keyword 'metric' is used to compute this
+                difference
+
+            - nodeSizes : size  / weight of each node (default : None)
+                Since we do weighted mean agglomeration, a size / weight
+                is needed for each node to merge 2 edges w.r.t. weighted mean.
+                If no nodeSizes is given, 'getNodeSizes' is called.
+
+            - nodeNumStop : stop the agglomeration at a given nodeNum (default : graph.nodeNum/2)
+
+            - beta : weight between edgeWeights and nodeFeatures based edgeWeights (default:0.5) :
+                    0.0 means only edgeWeights (from keyword edge weights) and 1.0 means only edgeWeights
+                    from nodeFeatures differences
+
+            - metric : metric used to compute node feature difference (default : 'l1')
+
+            - wardness : 0 means do not apply wards critrion, 1.0 means fully apply wards critrion (default : 1.0)
+
+            - out : preallocated nodeMap for the resulting labeling (default : None)
+
+        Returns:
+
+            A node labele map encoding the segmentation
+
+        """
+
+        assert edgeWeights is not None or nodeFeatures is not None
+
+        #print "prepare "
+
+        if nodeNumStop is None:
+            nodeNumStop = max(graph.nodeNum/2,min(graph.nodeNum,2))
+
+
+        if edgeLengths is None :
+            #print "get edge length"
+            edgeLengths = graphs.getEdgeLengths(graph)
+
+
+        if nodeSizes is None:
+            #print "get node size"
+            nodeSizes = graphs.getNodeSizes(graph)
+
+
+        if edgeWeights is None :
+            #print "get wegihts length"
+            edgeWeights = graphs.graphMap(graph,'edge')
+            edgeWeights[:]=0
+
+        if nodeFeatures is None :
+            #print "get node feat"
+            nodeFeatures = graphs.graphMap(graph,'node',addChannelDim=True)
+            nodeFeatures[:]=0
+
+        if nodeLabels is None:
+            nodeLabels = graphs.graphMap(graph,'node',dtype='uint32')
+
+
+
+        #import sys
+        #print "graph refcout", sys.getrefcount(graph)
+        mg = graphs.mergeGraph(graph)
+        #print "graph refcout", sys.getrefcount(graph)
+        #mg = []
+        #del mg
+        #import gc
+        #gc.collect()
+
+        #print "graph refcout", sys.getrefcount(graph)
+        #sys.exit(0)
+
+
+
+        clusterOp = graphs.minEdgeWeightNodeDist(mg,edgeWeights=edgeWeights,edgeLengths=edgeLengths,
+                                                    nodeFeatures=nodeFeatures,nodeSizes=nodeSizes,
+                                                    nodeLabels=nodeLabels,
+                                                    beta=float(beta),metric=metric,wardness=wardness)
+
+
+
+        hc = graphs.hierarchicalClustering(clusterOp, nodeNumStopCond=nodeNumStop,
+                                           buildMergeTreeEncoding=False)
+
+        hc.cluster()
+        labels = hc.resultLabels(out=out)
+        #del hc
+        #del clusterOp
+        #del mg
+        return labels
+
+
+    agglomerativeClustering.__module__ = 'vigra.graphs'
+    graphs.agglomerativeClustering = agglomerativeClustering
+
+
+
+    def minEdgeWeightNodeDist(mergeGraph,edgeWeights=None,edgeLengths=None,nodeFeatures=None,nodeSizes=None,
+        nodeLabels=None,outWeight=None,
+        beta=0.5,metric='squaredNorm',wardness=1.0, gamma=10000000.0):
+            graph=mergeGraph.graph()
+            assert edgeWeights is not None or nodeFeatures is not None
+
+            if edgeLengths is None :
+                edgeLengths = graphs.getEdgeLengths(graph,addChannelDim=True)
+            if nodeSizes is None:
+                nodeSizes = graphs.getNodeSizes(graph,addChannelDim=True)
+
+            if edgeWeights is None :
+                edgeWeights = graphs.graphMap(graph,'edge',addChannelDim=True)
+                edgeWeights[:]=0
+
+            if nodeFeatures is None :
+                nodeFeatures = graphs.graphMap(graph,'node',addChannelDim=True)
+                nodeFeatures[:]=0
+
+            if outWeight is None:
+                outWeight=graphs.graphMap(graph,item='edge',dtype=numpy.float32)
+
+            if nodeLabels is None :
+                nodeLabels = graphs.graphMap(graph,'node',dtype='uint32')
+                nodeLabels[:]=0
+
+
+            if  metric=='squaredNorm':
+                nd=graphs.MetricType.squaredNorm
+            elif  metric=='norm':
+                nd=graphs.MetricType.norm
+            elif  metric=='chiSquared':
+                nd=graphs.MetricType.chiSquared
+            elif metric in ('l1','manhattan'):
+                nd=graphs.MetricType.manhattan
+            elif isinstance(metric,graphs.MetricType):
+                nd=metric
+            else :
+                raise RuntimeError("'%s' is not a supported distance type"%str(metric))
+
+            # call unsave c++ function and make it sav
+            print "nodeLabels ",nodeLabels.shape, nodeLabels.dtype
+            op = graphs.__minEdgeWeightNodeDistOperator(mergeGraph,edgeWeights,edgeLengths,nodeFeatures,nodeSizes,outWeight,nodeLabels,
+                float(beta),nd,float(wardness),float(gamma))
+
+
+            op.__base_object__=mergeGraph
+            op.__outWeightArray__=outWeight
+            op.edgeLengths=edgeLengths
+            op.nodeSizes=nodeSizes
+            op.edgeWeights=edgeWeights
+            op.nodeFeatures=nodeFeatures
+            return op
+
+
+    minEdgeWeightNodeDist.__module__ = 'vigra.graphs'
+    graphs.minEdgeWeightNodeDist = minEdgeWeightNodeDist
+
+
+
+    def pythonClusterOperator(mergeGraph,operator,useMergeNodeCallback=True,useMergeEdgesCallback=True,useEraseEdgeCallback=True):
+      #call unsave function and make it save
+      op = graphs.__pythonClusterOperator(mergeGraph,operator,useMergeNodeCallback,useMergeEdgesCallback,useEraseEdgeCallback)
+      #op.__dict__['__base_object__']=mergeGraph
+      #op.__base_object__=mergeGraph
+      return op
+
+    pythonClusterOperator.__module__ = 'vigra.graphs'
+    graphs.pythonClusterOperator = pythonClusterOperator
+
+    def hierarchicalClustering(clusterOperator,nodeNumStopCond,buildMergeTreeEncoding=True):
+        # call unsave c++ function and make it save
+        hc = graphs.__hierarchicalClustering(clusterOperator,long(nodeNumStopCond),bool(buildMergeTreeEncoding))
+        #hc.__dict__['__base_object__']=clusterOperator
+        hc.__base_object__ = clusterOperator
+        return hc
+
+    hierarchicalClustering.__module__ = 'vigra.graphs'
+    graphs.hierarchicalClustering = hierarchicalClustering
+
+_genGraphSegmentationFunctions()
+del _genGraphSegmentationFunctions
+
+
+
+def _genHistogram():
+    def gaussianHistogram(image,minVals,maxVals,bins=30,
+                     sigma=3.0,sigmaBin=2.0,out=None):
+        """
+        """
+        spatialDim  = image.ndim - 1
+        out = histogram.gaussianHistogram_(image=image, minVals=minVals, maxVals=maxVals,
+                                           bins=bins, sigma=sigma, sigmaBin=sigmaBin,
+                                           out=out)
+
+        out = out.reshape(image.shape[0:spatialDim]+(-1,))
+        if spatialDim == 2:
+            out /= numpy.sum(out,axis=spatialDim)[:,:, numpy.newaxis]
+        elif spatialDim == 3:
+            out /= numpy.sum(out,axis=spatialDim)[:,:,:, numpy.newaxis]
+        elif spatialDim == 4:
+            out /= numpy.sum(out,axis=spatialDim)[:,:,:, :,numpy.newaxis]
+        return out
+
+    gaussianHistogram.__module__ = 'vigra.histogram'
+    histogram.gaussianHistogram = gaussianHistogram
+
+
+    def gaussianRankOrder(image, minVal=None, maxVal=None,
+                     bins=20, sigmas=None, ranks=[0.1,0.25,0.5,0.75,0.9],
+                     out=None):
+        image = numpy.require(image.squeeze(),dtype='float32')
+        nDim = image.ndim
+        if sigmas is None:
+            sigmas =  (2.0,)*nDim + (float(bins)/10.0,)
+
+        ranks = numpy.require(ranks,dtype='float32')
+        sigmas = numpy.require(sigmas,dtype='float32')
+        assert len(sigmas) == image.ndim + 1
+
+
+
+
+        if minVal is None :
+            minVal = image.min()
+        if maxVal is None :
+            maxVal = image.max()
+
+        #print "image",image.shape,image.dtype
+        #print "ranks",ranks.shape,ranks.dtype
+        #print "sigmas",sigmas
+        return histogram._gaussianRankOrder(image=image,
+                                            minVal=float(minVal),
+                                            maxVal=float(maxVal),
+                                            bins=int(bins),
+                                            sigmas=sigmas,ranks=ranks,
+                                            out=out)
+
+    gaussianRankOrder.__module__ = 'vigra.histogram'
+    histogram.gaussianRankOrder = gaussianRankOrder
+
+
+_genHistogram()
+del _genHistogram
+
+
+def _genGraphSmoothingFunctions():
+    def recursiveGraphSmoothing( graph,nodeFeatures,edgeIndicator,gamma,
+                               edgeThreshold,scale=1.0,iterations=1,out=None):
+        """ recursive graph smoothing to smooth node features.
+            Each node feature is smoothed with the features of neighbor nodes.
+            The strength of the smoothing is computed from:
+
+                "edgeIndicator > edgeThreshold ? 0 : exp(-1.0*gamma*edgeIndicator)*scale"
+
+            Therefore this filter is edge preserving.
+
+            Keyword Arguments :
+
+                - graph : input graph
+
+                - nodeFeatures : node features which should be smoothed
+
+                - edgeIndicator  : edge indicator
+
+                - gamma  : scale edgeIndicator by gamma bevore taking the negative exponent
+
+                - scale  : how much should a node be mixed with its neighbours per iteration
+
+                - iteration : how often should recursiveGraphSmoothing be called recursively
+
+            Returns :
+                smoothed nodeFeatures
+
+        """
+        return graphs._recursiveGraphSmoothing(graph=graph,nodeFeatures=nodeFeatures,edgeIndicator=edgeIndicator,
+                              gamma=gamma,edgeThreshold=edgeThreshold,scale=scale,iterations=iterations,out=out)
+
+    recursiveGraphSmoothing.__module__ = 'vigra.graphs'
+    graphs.recursiveGraphSmoothing = recursiveGraphSmoothing
+
+_genGraphSmoothingFunctions()
+del _genGraphSmoothingFunctions
+
+
+
+
+def _genGraphMiscFunctions():
+
+    def nodeFeaturesToEdgeWeights(graph,nodeFeatures,metric='l1',out=None):
+        """ compute an edge indicator from node features .
+
+            Keyword Arguments :
+                - graph : input graph
+                - nodeFeatures : node map with feature vector for each node
+                - metric : metric / distance used to convert 2 node features to
+                    an edge weight
+
+            Returns :
+                edge indicator
+        """
+        return graphs._nodeFeatureDistToEdgeWeight(graph=graph,nodeFeatures=nodeFeatures,metric=metric,out=out)
+
+    nodeFeaturesToEdgeWeights.__module__ = 'vigra.graphs'
+    graphs.nodeFeaturesToEdgeWeights = nodeFeaturesToEdgeWeights
+
+_genGraphMiscFunctions()
+del _genGraphMiscFunctions
+
+
+
+
+
+
+def _genBlockwiseFunctions():
+
+    def makeTuple(val, ndim):
+        tvals = None
+        if isinstance(val, Number):
+            tvals = (float(val),)*ndim
+        else :
+            tvals = tuple(val)
+            if len(tvals) != ndim:
+                raise RuntimeError("sigma/innerScale/outerScale must be as long as ndim, or must be a scalar")
+        return tvals
+
+    def getConvolutionOptionsClass(ndim):
+        assert ndim >=2 and ndim <= 5
+        if ndim == 2 :
+            return blockwise.BlockwiseConvolutionOptions2D
+        elif ndim == 3 :
+            return blockwise.BlockwiseConvolutionOptions3D
+        elif ndim == 4 :
+            return blockwise.BlockwiseConvolutionOptions4D
+        elif ndim == 5 :
+            return blockwise.BlockwiseConvolutionOptions5D
+
+    def convolutionOptions(blockShape, sigma=None,innerScale=None, outerScale=None, numThreads = cpu_count()):
+        ndim = len(blockShape)
+        options = getConvolutionOptionsClass(ndim)()
+        options.blockShape = blockShape
+        options.numThreads = numThreads
+
+        if sigma is not None:
+            sigma = makeTuple(sigma,ndim)
+            options.stdDev = sigma
+
+        if innerScale is not None:
+            options.innerScale = makeTuple(innerScale,ndim)
+
+        if outerScale is not None:
+            options.outerScale = makeTuple(outerScale,ndim)
+
+        return options
+
+    convolutionOptions.__module__ = 'vigra.blockwise'
+    blockwise.convolutionOptions = convolutionOptions
+    blockwise.convOpts = convolutionOptions
+
+    def gaussianSmooth(image,options,out=None):
+        out = blockwise._gaussianSmooth(image,options,out)
+        return out
+    gaussianSmooth.__module__ = 'vigra.blockwise'
+    blockwise.gaussianSmooth = gaussianSmooth
+
+    def gaussianGradient(image,options,out=None):
+        out = blockwise._gaussianGradient(image,options,out)
+        return out
+    gaussianGradient.__module__ = 'vigra.blockwise'
+    blockwise.gaussianGradient = gaussianGradient
+
+    def gaussianGradientMagnitude(image,options,out=None):
+        out = blockwise._gaussianGradientMagnitude(image,options,out)
+        return out
+    gaussianGradientMagnitude.__module__ = 'vigra.blockwise'
+    blockwise.gaussianGradientMagnitude = gaussianGradientMagnitude
+
+
+    def hessianOfGaussianEigenvalues(image,options,out=None):
+        out = blockwise._hessianOfGaussianEigenvalues(image,options,out)
+        return out
+    hessianOfGaussianEigenvalues.__module__ = 'vigra.blockwise'
+    blockwise.hessianOfGaussianEigenvalues = hessianOfGaussianEigenvalues
+
+    def hessianOfGaussianFirstEigenvalue(image,options,out=None):
+        out = blockwise._hessianOfGaussianFirstEigenvalue(image,options,out)
+        return out
+    hessianOfGaussianFirstEigenvalue.__module__ = 'vigra.blockwise'
+    blockwise.hessianOfGaussianFirstEigenvalue = hessianOfGaussianFirstEigenvalue
+
+    def hessianOfGaussianLastEigenvalue(image,options,out=None):
+        out = blockwise._hessianOfGaussianLastEigenvalue(image,options,out)
+        return out
+    hessianOfGaussianLastEigenvalue.__module__ = 'vigra.blockwise'
+    blockwise.hessianOfGaussianLastEigenvalue = hessianOfGaussianLastEigenvalue
+
+
+_genBlockwiseFunctions()
+del _genBlockwiseFunctions
+
+
+def loadBSDGt(filename):
+    import scipy.io as sio
+    matContents = sio.loadmat(filename)
+    ngt = len(matContents['groundTruth'][0])
+    gts = []
+    for gti in range(ngt):
+        gt =  matContents['groundTruth'][0][gti][0]['Segmentation'][0]
+        gt = numpy.swapaxes(gt,0,1)
+        gt = gt.astype(numpy.uint32)
+        print gt.min(),gt.max()
+        gts.append(gt[:,:,None])
+    gtArray = numpy.concatenate(gts,axis=2)
+    print gtArray.shape
+    return gtArray
+
+
+
+
+
+def pmapSeeds(pmap):
+    pass
diff --git a/vigranumpy/lib/arraytypes.py b/vigranumpy/lib/arraytypes.py
index 168e84b..3e1e0ec 100644
--- a/vigranumpy/lib/arraytypes.py
+++ b/vigranumpy/lib/arraytypes.py
@@ -37,6 +37,7 @@ import sys
 import copy
 import numpy
 import ufunc
+import collections
 import vigranumpycore
 
 from vigranumpycore import AxisType, AxisInfo, AxisTags
@@ -47,7 +48,7 @@ def _preserve_doc(f):
                  ("" if f.__doc__ is None else "\n" + f.__doc__)
     return f
 
-# a decorator to finalize the return value of a 
+# a decorator to finalize the return value of a
 # dimension-reducing function (e.g. array.max())
 def _finalize_reduce_result(f):
     def new_f(self, axis=None, out=None):
@@ -59,12 +60,12 @@ def _finalize_reduce_result(f):
                 res.axistags = self._copy_axistags()
                 del res.axistags[axis]
             else:
-                # this 'else' is necessary because numpy 1.6.0 gives 
+                # this 'else' is necessary because numpy 1.6.0 gives
                 #     type(res) == type(self)
                 # instead of the desired
                 #     type(res) == self.dtype
-                # when res is scalar and self is a subclass of ndarray 
-                # (this is probably a bug in numpy, since it works correctly 
+                # when res is scalar and self is a subclass of ndarray
+                # (this is probably a bug in numpy, since it works correctly
                 #  when self is a plain ndarray)
                 res = res.dtype.type(res)
         return res
@@ -96,10 +97,10 @@ class classproperty(object):
 
 def newaxis(axisinfo=AxisInfo()):
     '''
-    Create a new singleton axis via the indexing operator. This works similar to 
-    `numpy.newaxis`, but allows to provide an AxisInfo object for the new axis. 
+    Create a new singleton axis via the indexing operator. This works similar to
+    `numpy.newaxis`, but allows to provide an AxisInfo object for the new axis.
     For example::
-    
+
         >>> s = vigra.ScalarImage((width, height))
         >>> s.axistags  # no channel axis
         x y
@@ -107,35 +108,113 @@ def newaxis(axisinfo=AxisInfo()):
         >>> t.axistags  # with unknown axis type
         x y ?
         >>> t = s[..., vigra.newaxis(vigra.AxisInfo.c)]
-        >>> t.axistags  # with channel axis 
+        >>> t.axistags  # with channel axis
         x y c
     '''
-    return axisinfo
+    if isinstance(axisinfo, str):
+        return eval('AxisInfo.'+axisinfo)
+    else:
+        return axisinfo
 
-def taggedView(array, axistags):
+def makeAxistags(spec, order=None, noChannels=None):
     '''
-    Create a view to the given array with type :class:`~vigra.VigraArray` and the 
-    given axistags. This is essentially a shorthand for::
-    
-        >>> view = array.view(vigra.VigraArray)
-        >>> view.axistags = copy.copy(axistags)
-        
-    if axistags is an instance of AxisTags. Otherwise, the function first attempts
-    to convert the input to that type by calling VigraArray.defaultAxistags()
+    Create a new :class:`~vigra.AxisTags` object from the specification ``spec``.
+    ``spec`` can be one of the following:
+
+    * an instance of the ``AxisTags`` class. In this case, the function creates
+      a copy of ``spec``. If ``order`` is given, the resulting axistags are
+      transposed to the desired order ('C', 'F', or 'V'). If ``noChannels=True``,
+      the channel axis (if any) is dropped from the specification.
+
+    * a string or tuple of axis keys (e.g. ``'xyc'`` or ``('x', 'y', 'c')`` respectively)
+      or a tuple of :class:`~vigra.AxisInfo` objects (e.g.
+      ``(AxisInfo.x, AxisInfo.y, AxisInfo.c)``). The function then constructs a
+      new ``AxisTags`` object from this specification. If ``order`` is given,
+      the resulting axistags are transposed to the desired order ('C', 'F', or 'V').
+      If ``noChannels=True``, the channel axis (if any) is dropped from the specification.
+
+    * an integer signifying the desired number of axes. In this case, the call (including
+      optional arguments ``order`` and ``noChannels``) is forwarded to the function
+      :meth:`~vigra.VigraArray.defaultAxistags`, whose output is returned.
     '''
-    if not isinstance(axistags, AxisTags):
-        axistags = VigraArray.defaultAxistags(axistags)
+    if isinstance(spec, int):
+        return VigraArray.defaultAxistags(spec, order=order, noChannels=noChannels)
+
+    if isinstance(spec, AxisTags):
+        res = copy.copy(spec)
     else:
-        axistags = copy.copy(axistags)
-    if array.ndim != len(axistags):
-        raise RuntimeError('vigra.taggedView(): array.ndim must match len(axistags).')
-    res = array.view(VigraArray)
-    res.axistags = axistags
+        tags = [k if isinstance(k, AxisInfo) else eval('AxisInfo.'+k) for k in spec]
+        res = AxisTags(*tuple(tags))
+    if order:
+        res.transpose(res.permutationToOrder(order))
+    if noChannels:
+        res.dropChannelAxis()
     return res
 
+def taggedView(array, axistags='', force=False, order=None, noChannels=False):
+    '''
+    Create a view to the given array with type :class:`~vigra.VigraArray` and
+    desired axistags.
+
+    You can either explicitly provide axistags to be imposed on the array
+    (parameter ``axistags``), or a general description for the desired axis
+    ordering (parameters ``order`` and ``noChannels``). It is an error to
+    specify axistags and order simultaneously. In addition, the effect of
+    ``taggedView()`` depends on whether ``array`` already has axistags or not.
+
+    1. If ``array`` has no axistags or ``force=True`` (i.e. existing axistags
+       shall be ignored) and the ``order`` parameter is given, the function
+       constructs appropriate axistags via :meth:`~vigra.VigraArray.defaultAxistags`::
+
+       >>> view = array.view(VigraArray)
+       >>> view.axistags = VigraArray.defaultAxistags(view.ndim, order, noChannels)
+
+    2. If ``array`` has no axistags (or ``force=True``) and the ``axistags`` parameter
+       is given, the function transforms this specification into an object of type
+       :class:`~vigra.AxisTags` and attaches the result to the view::
+
+       >>> view = array.view(VigraArray)
+       >>> view.axistags = makeAxistags(axistags)
+
+    3. If ``array`` has axistags (and ``force=False``) and the ``order`` parameter is
+       given, the function transposes the array into the desired order::
+
+       >>> view = array.transposeToOrder(order)
+       >>> if noChannels:
+       ...     view = view.dropChannelAxis()
+
+    4. If ``array`` has axistags (and ``force=False``) and the ``axistags`` parameter
+       is given, the function calls :meth:`~vigra.VigraArray.withAxes` to transforms
+       the present axistags into the desired ones::
+
+       >>> view = array.withAxes(axistags)
+
+    The function raises a RuntimeError when the axistag specification is incompatible
+    with the array.
+    '''
+    if axistags and order:
+        raise RuntimeError("vigra.taggedView(): you cannot specify 'axistags' and 'order' at the same time.")
+    if hasattr(array, 'axistags') and not force:
+        if not axistags:
+            array = array.transposeToOrder(order)
+            if noChannels:
+                array = array.dropChannelAxis()
+        else:
+            array = array.withAxes(axistags)
+    else:
+        if not axistags:
+            axistags = VigraArray.defaultAxistags(array.ndim, order, noChannels)
+        else:
+            axistags = makeAxistags(axistags)
+        if array.ndim != len(axistags):
+            raise RuntimeError('vigra.taggedView(): array.ndim must match len(axistags).')
+        array = array.view(VigraArray)
+        array.axistags = axistags
+    return array
+
 def dropChannelAxis(array):
     '''
-    Return the view created by ``array.``:meth:`~vigra.VigraArray.dropChannelAxis` if 
+    Return the view created by ``array.``:meth:`~vigra.VigraArray.dropChannelAxis` if
     the given array supports that function, or return ``array`` unchanged otherwise.
     '''
     try:
@@ -167,7 +246,7 @@ def _AxisTags__reduce__(self):
 AxisTags.__reduce__ = _AxisTags__reduce__
 AxisTags.fromJSON = staticmethod(_AxisTags_fromJSON)
 AxisTags.fromJSON.__doc__ = _AxisTags_fromJSON.__doc__
-    
+
 # How to construct a VigraArray
 #
 # case 1: from shape and order or axistags
@@ -189,19 +268,19 @@ AxisTags.fromJSON.__doc__ = _AxisTags_fromJSON.__doc__
 # * permute the array by the inverse normalization
 # * copy original data and axistags
 
-_constructArrayFromAxistags = vigranumpycore.constructArrayFromAxistags 
-    
+_constructArrayFromAxistags = vigranumpycore.constructArrayFromAxistags
+
 def _constructArrayFromOrder(cls, shape, dtype, order, init):
     axistags = VigraArray.defaultAxistags(len(shape), order)
     return _constructArrayFromAxistags(cls, shape, dtype, axistags, init)
-    
+
 def _constructArrayFromArray(cls, obj, dtype, order, init, axistags):
     if order is None:
         order = 'A'
     if order == 'A':
         # we cannot use ndarray.copy('A') here, because this only preserves 'C' and 'F'
         # order, whereas any other order is silently transformed into 'C'
-        
+
         # we must also make sure that a singleton channel index has the smallest stride
         # (otherwise, strides in the copy may not exactly match those in obj)
         strides = list(obj.strides)
@@ -218,7 +297,7 @@ def _constructArrayFromArray(cls, obj, dtype, order, init, axistags):
         array = array.transpose(inverse_permutation)
     else:
         array = _constructArrayFromOrder(cls, obj.shape, dtype, order, False)
-        
+
     if init:
         array[...] = obj
     if cls is not numpy.ndarray:
@@ -236,7 +315,7 @@ def _constructArrayFromPickle(_arraypickle, _permutation, _axistags):
     array = array.transpose(_permutation)
     array.axistags = AxisTags.fromJSON(_axistags)
     return array
-    
+
 def _constructArrayFromZMQSocket(socket, flags=0, copy=True, track=False):
     metadata = socket.recv_json(flags=flags)
     axistags = AxisTags.fromJSON(socket.recv(flags=flags))
@@ -244,61 +323,61 @@ def _constructArrayFromZMQSocket(socket, flags=0, copy=True, track=False):
     array = numpy.frombuffer(data, dtype=metadata['dtype']).reshape(metadata['shape'])
     array = taggedView(array.transpose(metadata['permutation']), axistags)
     return array
-    
+
 ##################################################################
 
 class VigraArray(numpy.ndarray):
     '''
-    This class extends numpy.ndarray with the concept of **axistags** 
+    This class extends numpy.ndarray with the concept of **axistags**
     which encode the semantics of the array's axes. VigraArray overrides all
     numpy.ndarray methods in order to handle axistags in a sensible way.
     In particular, operations acting on two arrays simultaneously (e.g.
-    addition) will first transpose the arguments such that their axis 
+    addition) will first transpose the arguments such that their axis
     ordering matches.
 
     Constructor:
-    
+
     .. method:: VigraArray(obj, dtype=numpy.float32, order=None, init=True, value=None, axistags=None)
 
         :param obj: an array or shape object (see below)
         :param dtype: desired element type
         :param order: desired memory layout (see below)
-        :param init: True: initialize the image with zeros; False: do not 
+        :param init: True: initialize the image with zeros; False: do not
                      initialize the image
         :type init: boolean
         :param value: initialize the image with this value (overrides init)
         :type value: convertible to dtype
-        :param axistags: the AxisTags object of the new array. The length of 
-                         axistags must match the array's shape. It axistags=None, 
-                         obj.axistags is used if it exists. Otherwise, a new 
-                         axistags object is created by a call to 
+        :param axistags: the AxisTags object of the new array. The length of
+                         axistags must match the array's shape. It axistags=None,
+                         obj.axistags is used if it exists. Otherwise, a new
+                         axistags object is created by a call to
                          :meth:`~vigra.VigraArray.defaultAxistags`.
- 
+
         **obj** may be one of the following
 
-        * If obj is a numpy.ndarray or a subtype, a copy of obj with the given 
+        * If obj is a numpy.ndarray or a subtype, a copy of obj with the given
           dtype, order and resulting class VigraArray is created. If obj.axistags
           exists, the new array will have these axistags as well, unless new
           axistags are explicitly passed to the constructor.
-        * If obj is a sequence, it is interpreted as a shape. 
+        * If obj is a sequence, it is interpreted as a shape.
         * Otherwise, or if shape and axistags are incompatible, an exception
           is raised.
-          
+
         **order** can be 'C' (C order), 'F' (Fortran order), 'V' (VIGRA
-        order), 'A' (any), or None. This parameter controls the order of strides 
-        and axistags (unless axistags are explicit passed into the constructor). 
-        See the :ref:`order definitions <array-order-parameter>` for details. If 
+        order), 'A' (any), or None. This parameter controls the order of strides
+        and axistags (unless axistags are explicit passed into the constructor).
+        See the :ref:`order definitions <array-order-parameter>` for details. If
         'order=None', the order is determined by :attr:`VigraArray.defaultOrder`.
     '''
-    
+
     ###############################################################
     #                                                             #
     #       a number of helper functions related to axistags      #
     #                                                             #
-    ###############################################################    
-    
+    ###############################################################
+
     # a number of helper functions related to axistags
-    
+
     # IMPORTANT: do not remove or rename this function, it is called from C++
     @classproperty
     def defaultOrder(cls):
@@ -311,13 +390,13 @@ class VigraArray(numpy.ndarray):
     @staticmethod
     def defaultAxistags(tagSpec, order=None, noChannels=False):
         '''
-        Get default axistags for the given specification 'tagSpec'. TagSpec can be the 
-        number of dimensions of the array (``array.ndim``, must be <= 5) or a string 
-        containing a sequence of axis keys (only the default keys 'x', 'y', 'z', 't', 
-        and 'c' are currently supported). The 'order' parameter determines the axis 
+        Get default axistags for the given specification 'tagSpec'. TagSpec can be the
+        number of dimensions of the array (``array.ndim``, must be <= 5) or a string
+        containing a sequence of axis keys (only the default keys 'x', 'y', 'z', 't',
+        and 'c' are currently supported). The 'order' parameter determines the axis
         ordering, see the :ref:`order definitions <array-order-parameter>` for details.
         If 'noChannels' is True, there will be no channel axis. Examples::
-        
+
             >>> vigra.VigraArray.defaultAxistags(3)
             x y c
             >>> vigra.VigraArray.defaultAxistags(4)
@@ -364,7 +443,7 @@ class VigraArray(numpy.ndarray):
             source = source.transposeToNumpyOrder()
         except:
             pass
-        
+
         try:
             compatible = source.axistags.compatible(target.axistags)
         except:
@@ -374,21 +453,21 @@ class VigraArray(numpy.ndarray):
             raise RuntimeError("VigraArray._copyValuesImpl(): incompatible axistags")
 
         target[...] = source
-    
+
     # IMPORTANT: do not remove or rename this function, it is called from C++
     @staticmethod
     def _empty_axistags(ndim):
-        '''Create an axistags object with non-informative entries. 
+        '''Create an axistags object with non-informative entries.
            That is, all axisinfo objects are '?'.
         '''
         return AxisTags(ndim)
-    
+
     def _copy_axistags(self):
-        '''Create a copy of 'self.axistags'. If the array doesn't have axistags, _empty_axistags() 
+        '''Create a copy of 'self.axistags'. If the array doesn't have axistags, _empty_axistags()
            will be returned.
         '''
         return copy.copy(getattr(self, 'axistags', self._empty_axistags(self.ndim)))
-        
+
     def _transform_axistags(self, index):
         if hasattr(self, 'axistags'):
             return self.axistags.transform(index, self.ndim)
@@ -413,8 +492,8 @@ class VigraArray(numpy.ndarray):
     #                                                             #
     #                   standard array functions                  #
     #                                                             #
-    ###############################################################    
-    
+    ###############################################################
+
     def __new__(cls, obj, dtype=numpy.float32, order=None, init=True, value=None, axistags=None):
         if value is not None:
             init = False
@@ -458,7 +537,7 @@ class VigraArray(numpy.ndarray):
         result = numpy.ndarray.__copy__(self, order)
         result.axistags = result._copy_axistags()
         return result
-        
+
     @_preserve_doc
     def __deepcopy__(self, memo):
         # numpy.ndarray.__deepcopy__ always creates C-order arrays =>
@@ -468,18 +547,18 @@ class VigraArray(numpy.ndarray):
         memo[id(self)] = result
         result.__dict__ = copy.deepcopy(self.__dict__, memo)
         return result
-    
+
     def __repr__(self):
         return "%s(shape=%s, axistags=%s, dtype=%s, data=\n%s)" % \
           (self.__class__.__name__, str(self.shape), repr(self.axistags), str(self.dtype), str(self))
-          
+
     def __str__(self):
         try:
             self = self.transposeToVigraOrder().transpose()
         except:
             pass
         return str(self.view(numpy.ndarray))
-          
+
     def __reduce__(self):
         '''
             Enable pickling of a VigraArray, including axistags. The stride ordering
@@ -487,29 +566,29 @@ class VigraArray(numpy.ndarray):
             will not be saved and restored.
         '''
         # since the stride ordering is not necessarily preserved by ndarray's pickling
-        # functions, we need to normalize stride ordering, and permute to the original 
+        # functions, we need to normalize stride ordering, and permute to the original
         # ordering upon reconstruction
         pickled = numpy.ndarray.__reduce__(self.transposeToNumpyOrder())
         return _constructArrayFromPickle, (pickled, self.permutationFromNumpyOrder(), self.axistags.toJSON())
-        
+
     @staticmethod
     def receiveSocket(socket, flags=0, copy=True, track=False):
         '''
-        Reconstruct an array that has been transferred via a ZMQ socket by a call to 
+        Reconstruct an array that has been transferred via a ZMQ socket by a call to
         VigraArray.sendSocket(). This only works when the 'zmq' module is available.
         The meaning of the arguments is described in zmq.Socket.recv().
         '''
         return _constructArrayFromZMQSocket(socket, flags, copy, track)
 
-            
+
     ###############################################################
     #                                                             #
     #                     array I/O and display                   #
     #                                                             #
-    ###############################################################    
-    
-    def writeImage(self, filename, dtype = '', compression = ''):
-        '''Write an image to a file. 
+    ###############################################################
+
+    def writeImage(self, filename, dtype = '', compression = '', mode='w'):
+        '''Write an image to a file.
         Consult :func:`vigra.impex.writeImage` for detailed documentation'''
         import vigra.impex
 
@@ -519,10 +598,10 @@ class VigraArray(numpy.ndarray):
         if ndim != 2:
             raise RuntimeError("VigraArray.writeImage(): array must have 2 non-channel axes.")
 
-        vigra.impex.writeImage(self, filename, dtype, compression)
-            
+        vigra.impex.writeImage(self, filename, dtype, compression, mode)
+
     def writeSlices(self, filename_base, filename_ext, dtype = '', compression = ''):
-        '''Write a volume to a sequence of files.         
+        '''Write a volume to a sequence of files.
         Consult :func:`vigra.impex.writeVolume` for detailed documentation.
         '''
         import vigra.impex
@@ -534,9 +613,9 @@ class VigraArray(numpy.ndarray):
             raise RuntimeError("VigraArray.writeSlices(): array must have 3 non-channel axes.")
 
         vigra.impex.writeVolume(self, filename_base, filename_ext, dtype, compression)
-            
+
     def writeHDF5(self, filenameOurGroup, pathInFile):
-        '''Write the array to a HDF5 file. 
+        '''Write the array to a HDF5 file.
            This is just a shortcut for :func:`vigra.impex.writeHDF5`
         '''
         import vigra.impex
@@ -549,7 +628,7 @@ class VigraArray(numpy.ndarray):
         The meaning of the arguments is described in zmq.Socket.send().
         '''
         import zmq
-        
+
         transposed = self.transposeToNumpyOrder().view(numpy.ndarray)
         metadata = dict(
             dtype = str(transposed.dtype),
@@ -570,10 +649,10 @@ class VigraArray(numpy.ndarray):
     def show(self, normalize=True):
         '''
         Display this image in a vigra.pyqt.ImageWindow.
-        
-        The channels are intepreted as follows: 1 channel = gray image, 
+
+        The channels are intepreted as follows: 1 channel = gray image,
         2 channels = gray + alpha, 3 channels = RGB, 4 channels = RGB + alpha.
-        
+
         The parameter `normalize` can be used to normalize an image's
         value range to 0..255:
 
@@ -589,7 +668,7 @@ class VigraArray(numpy.ndarray):
 
         `normalize` = False:
           don't scale the image's values
-           
+
         '''
         from pyqt.imagewindow import showImage
 
@@ -602,7 +681,7 @@ class VigraArray(numpy.ndarray):
         if ndim != 2:
             raise RuntimeError("VigraArray.show(): array must have 2 non-channel axes.")
 
-        return showImage(self, normalize)
+        return showImage(self.transposeToVigraOrder(), normalize)
 
     def qimage(self, normalize=True):
         '''
@@ -611,7 +690,7 @@ class VigraArray(numpy.ndarray):
         QImage will have QImage.Format_Indexed8 iff there was only one
         channel and QImage.Format_[A]RGB32 otherwise (with the last of
         2/4 channels being used as alpha channel).
-        
+
         The parameter `normalize` can be used to normalize an image's
         value range to 0..255:
 
@@ -627,7 +706,7 @@ class VigraArray(numpy.ndarray):
 
         `normalize` = False:
           don't scale the image's values
-           
+
         '''
         try:
             import qimage2ndarray
@@ -636,11 +715,11 @@ class VigraArray(numpy.ndarray):
             _fallbackModule('qimage2ndarray',
             '''
             %s
-            
+
             If qimage2ndarray is missing on your system, download it from
             http://pypi.python.org/pypi/qimage2ndarray/.''' % str(e))
             import qimage2ndarray
-        
+
         ndim = self.ndim
         if self.channelIndex < ndim:
             ndim -= 1
@@ -655,13 +734,13 @@ class VigraArray(numpy.ndarray):
             q = qimage2ndarray.array2qimage(yxImage, normalize)
 
         return q
-        
+
     def asRGB(self, normalize=True):
         '''
         Expand a scalar array (i.e. an array with a single channel) into an RGB array with
         three identical color channels. This is useful when you want to paste color
         annotations (e.g. user labels) into the array.
-        
+
         The parameter `normalize` can be used to normalize the array's
         value range to 0..255:
 
@@ -673,7 +752,7 @@ class VigraArray(numpy.ndarray):
 
         `normalize` = False:
           don't scale the array's values
-           
+
         '''
         if self.channels != 1:
             raise RuntimeError("VigraArray.asRGB(): array must have a single channel.")
@@ -704,40 +783,40 @@ class VigraArray(numpy.ndarray):
     #                                                             #
     #           new functionality enabled by axistags             #
     #                                                             #
-    ###############################################################    
-    
+    ###############################################################
+
     def copyValues(self, other):
         '''
         Copy the values of an array to another one. This is similar to::
-        
+
             self[...] = other
-            
+
         but will first transpose both arrays so that axistags are aligned. If
         there is no valid alignment, RuntimeError will be raised.
         '''
         self._copyValuesImpl(self, other)
-    
+
     # IMPORTANT: do not remove or rename this property, it is called from C++
     @property
     def channelIndex(self):
         '''
-        The index of the channel axis according to the axistags.        
-        For example, when axistags are 'x y c', the channel index is 2. 
+        The index of the channel axis according to the axistags.
+        For example, when axistags are 'x y c', the channel index is 2.
         If the axistags contain no channel axis, self.ndim is returned.
         '''
         return self.axistags.channelIndex
-    
+
     # IMPORTANT: do not remove or rename this property, it is called from C++
     @property
     def innerNonchannelIndex(self):
         '''
         The index of the innermost non-channel axis according to the axistags.
-        The innermost axis is determined by the AxisInfo sorting rules (see 
+        The innermost axis is determined by the AxisInfo sorting rules (see
         the :ref:`order definitions <array-order-parameter>` for details).
         For example, when axistags are 'x y c', the innerNonchannelIndex is 0.
         '''
         return self.axistags.innerNonchannelIndex
-    
+
     @property
     def channels(self):
         '''
@@ -749,7 +828,7 @@ class VigraArray(numpy.ndarray):
             return self.shape[i]
         else:
             return 1
-            
+
     @property
     def width(self):
         '''
@@ -761,7 +840,7 @@ class VigraArray(numpy.ndarray):
             return self.shape[i]
         else:
             raise RuntimeError("VigraArray.width(): axistag 'x' does not exist.")
-    
+
     @property
     def height(self):
         '''
@@ -773,7 +852,7 @@ class VigraArray(numpy.ndarray):
             return self.shape[i]
         else:
             raise RuntimeError("VigraArray.height(): axistag 'y' does not exist.")
-    
+
     @property
     def depth(self):
         '''
@@ -785,7 +864,7 @@ class VigraArray(numpy.ndarray):
             return self.shape[i]
         else:
             raise RuntimeError("VigraArray.depth(): axistag 'z' does not exist.")
-    
+
     @property
     def duration(self):
         '''
@@ -797,7 +876,7 @@ class VigraArray(numpy.ndarray):
             return self.shape[i]
         else:
             raise RuntimeError("VigraArray.duration(): axistag 't' does not exist.")
-            
+
     @property
     def spatialDimensions(self):
         '''
@@ -806,7 +885,7 @@ class VigraArray(numpy.ndarray):
         is set.
         '''
         return self.axistags.axisTypeCount(AxisType.Space)
-            
+
     def iterImpl(self, type):
         axes = [k for k in xrange(self.ndim) if self.axistags[k].isType(type)]
         if axes:
@@ -818,14 +897,14 @@ class VigraArray(numpy.ndarray):
                 yield self[tuple(slices)]
         else:
             yield self
-            
+
     def channelIter(self):
         '''
         Create an iterator over the channels of the array.
         In each iteration, you get the array corresponding to a single channel.
         If the axistags contain no channel axis, there is only one iteration
         which yields the entire array. Example::
-        
+
             >>> rgb = vigra.RGBImage((200, 100))
             >>> rgb.axistags
             x y c
@@ -836,14 +915,14 @@ class VigraArray(numpy.ndarray):
             (200, 100)
         '''
         return self.iterImpl(AxisType.Channels)
-            
+
     def spaceIter(self):
         '''
         Create an iterator over all the spatial coordinates in the array.
-        In each iteration, you get the value corresponding to a single 
-        coordinate location. If the axistags contain no spatial axes, 
+        In each iteration, you get the value corresponding to a single
+        coordinate location. If the axistags contain no spatial axes,
         there is only one iteration which yields the entire array. Example::
-        
+
             >>> s = vigra.ScalarImage((2,2))
             >>> s.ravel()[...] = range(4)
             >>> for p in s.spaceIter():
@@ -854,14 +933,14 @@ class VigraArray(numpy.ndarray):
             3.0
         '''
         return self.iterImpl(AxisType.Space)
-        
+
     def timeIter(self):
         '''
         Create an iterator over the time points of the array.
         In each iteration, you get the array corresponding to a single time point.
         If the axistags contain no time axis, there is only one iteration
         which yields the entire array. Example::
-        
+
             >>> from vigra import *
             >>> axistags = AxisTags(AxisInfo.t, AxisInfo.x, AxisInfo.y)
             >>> timesteps, width, height = 2, 200, 100
@@ -869,14 +948,14 @@ class VigraArray(numpy.ndarray):
             >>> step1, step2 = image_sequence.timeIter()
         '''
         return self.iterImpl(AxisType.Time)
-        
+
     def sliceIter(self, key='z'):
         '''
         Create an iterator over a single spatial axis of the array.
         In each iteration, you get the array corresponding to one coordinate
         along the axis given by 'key'. For example, to iterate along the z-axis
         to get all x-y-slices in turn, you write::
-        
+
             >>> volume = vigra.Volume((width, height, depth))
             >>> for slice in volume.sliceIter('z'):
             ...     processSlice(slice)
@@ -889,31 +968,31 @@ class VigraArray(numpy.ndarray):
                 yield self.bindAxis(i, k)
         else:
             yield self
-    
+
     def bindAxis(self, which, index=0):
         '''
         Bind the axis identified by 'which' to the given 'index'.
         This is similar to::
-        
+
             array[:, index, ...]
-            
-        but you do not need to know the position of the axis when you use the 
+
+        but you do not need to know the position of the axis when you use the
         axis key (according to axistags). For example, to get the green channel
         of an RGBImage, you write::
-        
+
             >>> rgb = vigra.RGBImage((200, 100))
             >>> green = rgb.bindAxis('c', 1)
-            
+
         This gives the correct result irrespective of the axis ordering.
         '''
         if type(which) == str:
             which = self.axistags.index(which)
         return self[(slice(None),)*which + (index,) + (slice(None),)*(self.ndim-which-1)]
-    
+
     def dropChannelAxis(self, ignoreMultiChannel=False):
         '''
         Drop the channel axis when it is a singleton.
-        This function is for easy transformation of an array shaped 
+        This function is for easy transformation of an array shaped
         (width, height, 1) into (width, height). A RuntimeError
         is raised when there is more than one channel, unless ignoreMultiChannel=True,
         in which case 'self' is returned.
@@ -921,17 +1000,17 @@ class VigraArray(numpy.ndarray):
         ci = self.channelIndex
         if ci == self.ndim:
             return self
-        
+
         if self.shape[ci] != 1:
             if ignoreMultiChannel:
                 return self
             raise RuntimeError("dropChannelAxis(): only allowed when there is a single channel.")
         return self.bindAxis(ci, 0)
-    
+
     def insertChannelAxis(self, order=None):
         '''
         Insert a singleton channel axis.
-        This function is for easy transformation of an array shaped 
+        This function is for easy transformation of an array shaped
         (width, height) into (width, height, 1). The 'order' parameter
         determines the position of the new axis: when order is 'F', it
         will become the first axis, otherwise it will become the last
@@ -941,7 +1020,7 @@ class VigraArray(numpy.ndarray):
         ci = self.channelIndex
         if ci != self.ndim:
             return self
-        
+
         if order == 'F':
             res = self[numpy.newaxis,...]
             res.axistags[0] = AxisInfo.c
@@ -949,61 +1028,100 @@ class VigraArray(numpy.ndarray):
             res = self[..., numpy.newaxis]
             res.axistags[-1] = AxisInfo.c
         return res
-    
-    def withAxes(self, *axiskeys):
-        '''
-        Create a view containing the desired axis keys in the given  
-        order. When the array contains an axis not listed, the axis
-        will be dropped if it is a singfleton (otherwise, an exception
-        is raised). If a requested key is not present in this array,
-        a singleton axis will be inserted at that position, if the 
-        missing key is among the known standard keys (otherwise, an 
-        exception is raised). The function fails if this array contains
-        axes of unknown type (key '?'). If 'self' is already suitable, 
-        it is simply retured without generating a new view.
-        
-        Usage::
-        
-            >>> a = vigra.ScalarVolume((200, 100))
-            >>> a.axistags
-            x y
-            >>> a.shape
-            (200, 100)
-            >>> b = a.withAxes('y', 'x', 'c')
-            >>> b.axistags
-            y x c
-            >>> b.shape
-            (100, 200, 1)
-        
-        '''
-        if repr(self.axistags) == ' '.join(axiskeys):
-            return self
-        axisinfo = []
-        slicing = [0]*self.ndim
-        for key in axiskeys:
-            index = self.axistags.index(key)
-            if index < self.ndim:
-                axisinfo.append(self.axistags[index])
-                slicing[index] = slice(None)
-            else:
-                axisinfo.append(eval('AxisInfo.%s' % key))
-                slicing.append(axisinfo[-1])
-        for k in xrange(self.ndim):
-            if self.axistags[k].isType(AxisType.UnknownAxisType):
-                raise RuntimeError("VigraArray.ensureAxes(): array must not contain axes of unknown type (key '?').")
-            if slicing[k] == 0 and self.shape[k] != 1:
-                raise RuntimeError("VigraArray.ensureAxes(): cannot drop non-singleton axis '%s'." % self.axistags[k].key)
-        permutation = AxisTags(axisinfo).permutationFromNumpyOrder()
-        return self[slicing].transposeToNumpyOrder().transpose(permutation)
-    
+
+    def noTags(self):
+        '''
+        Drop the axistags. This is a shorthand for ``array.view(numpy.ndarray)``.
+        '''
+        return self.view(numpy.ndarray)
+
+    def withAxes(self, *axistags, **kw):
+        '''
+        This function creates a view whose axistags are standardized in a
+        desired way. The standardization can be specified in two forms:
+
+        1. Provide ``axistags`` explicitly in any format understood by
+           :func:`vigra.makeAxistags`. The original axistags are then
+           transposed into the given order. When the original array contains
+           axes not listed in the new specification, these axes are dropped
+           if they are singletons (otherwise, an exception is raised).
+           If requested axes is not present in the original array,
+           singleton axes are inserted at the appropriate positions, provided
+           the axis keys are among the predefined standard keys ('x', 'y', 'z',
+           't', 'c', 'n', 'e', 'fx', 'fy', 'fz', 'ft'). The function fails if
+           the original array contains axes of unknown type (key '?')::
+
+                >>> array.axistags
+                x y c
+                >>> array.shape
+                (100, 50, 1)
+                >>> view = array.withAxes('tzyx')
+                >>> view.axistags
+                t z y x
+                >>> view.shape
+                (1, 1, 50, 100)
+
+        2. Provide keyword arguments ``order`` and (optionally) ``noChannels``.
+           The array is then transposed into the desired order ('C', 'F', or 'V').
+           If ``noChannels=True``, the channel axis is dropped if it is a
+           singleton, otherwise an exception is raised::
+
+                >>> array.axistags
+                x y c
+                >>> array.shape
+                (100, 50, 1)
+                >>> view = array.withAxes(order='F')
+                >>> view.axistags
+                c x y
+                >>> view.shape
+                (1, 100, 50)
+                >>> view = array.withAxes(order='C', noChannels=True)
+                >>> view.axistags
+                y x
+                >>> view.shape
+                (50, 100)
+
+        The parameters ``axistags`` and ``order`` cannot be specified simultaneously.
+        '''
+        if len(axistags) == 1:
+            axistags = axistags[0]
+        if axistags and kw.get('order'):
+            raise RuntimeError("vigra.withAxes(): you cannot specify 'axistags' and 'order' at the same time.")
+        if axistags:
+            axistags = makeAxistags(axistags)
+            if self.axistags.compatible(axistags):
+                return self
+            axisinfo = []
+            slicing = [0]*self.ndim
+            for tag in axistags:
+                index = self.axistags.index(tag.key)
+                if index < self.ndim:
+                    axisinfo.append(self.axistags[index])
+                    slicing[index] = slice(None)
+                else:
+                    axisinfo.append(tag)
+                    slicing.append(axisinfo[-1])
+            for k in xrange(self.ndim):
+                if self.axistags[k].isType(AxisType.UnknownAxisType):
+                    raise RuntimeError("VigraArray.withAxes(): array must not contain axes of unknown type (key '?').")
+                if slicing[k] == 0 and self.shape[k] != 1:
+                    raise RuntimeError("VigraArray.withAxes(): cannot drop non-singleton axis '%s'." % self.axistags[k].key)
+            permutation = AxisTags(axisinfo).permutationFromNumpyOrder()
+            res = self[slicing].transposeToNumpyOrder().transpose(permutation)
+        else:
+            res = self.transposeToOrder(kw.get('order'))
+            if kw.get('noChannels'):
+                res = res.dropChannelAxis()
+        return res
+
     def view5D(self, order='C'):
         '''
-            Create a 5-dimensional view containing the standard tags 
-            'x', 'y', 'z', 't', 'c' in the desired 'order' (which can be 
-            'C', 'F', and 'V' with the usual meaning). If 'self' has an 
-            axis key that is not among the five admissible keys, an 
-            exception is raised. Axes missing in 'self' are added as 
-            singleton axes with the appropriate tags. 
+            Create a 5-dimensional view containing the standard tags
+            'x', 'y', 'z', 't', 'c' in the desired 'order' (which can be
+            'C', 'F', and 'V' with the usual meaning). If 'self' has an
+            axis key that is not among the five admissible keys, an
+            exception is raised. Axes missing in 'self' are added as
+            singleton axes with the appropriate tags.
         '''
         stdTags = ['x', 'y', 'z', 't', 'c']
         for tag in self.axistags:
@@ -1013,66 +1131,66 @@ class VigraArray(numpy.ndarray):
                 raise RuntimeError("VigraArray.view5D(): array contains unsuitable axis key '%s'." % tag.key)
         index = [Ellipsis] + [newaxis(eval('AxisInfo.' + k)) for k in stdTags]
         return self[index].transposeToOrder(order)
-    
+
     def permutationToOrder(self, order):
         '''Create the permutation that would transpose this array into
            an array view with the given order (where order can be 'A',
-           'C', 'F', 'V' with the usual meaning). 
+           'C', 'F', 'V' with the usual meaning).
         '''
         return list(self.axistags.permutationToOrder(order))
-    
+
     def permutationToNormalOrder(self, types=AxisType.AllAxes):
-        '''Create the permutation that would transpose this array to 
-           normal order (that is, from the current axis order into 
-           ascending order, e.g. 'x y c' into 'c x y'). 
+        '''Create the permutation that would transpose this array to
+           normal order (that is, from the current axis order into
+           ascending order, e.g. 'x y c' into 'c x y').
            If 'types' is not 'AxisType.AllAxes', only the axes with the
            desired types are considered.
         '''
         return list(self.axistags.permutationToNormalOrder(types))
-    
+
     def permutationFromNormalOrder(self):
-        '''Create the permutation that would transpose an array that is 
+        '''Create the permutation that would transpose an array that is
            in normal (ascending) order into the axis order of this array.
-           (e.g. 'c x y' into 'x y c'). 
+           (e.g. 'c x y' into 'x y c').
         '''
         return list(self.axistags.permutationFromNormalOrder())
-    
+
     def permutationToNumpyOrder(self):
-        '''Create the permutation that would transpose this array to 
-           numpy order (that is, from the current axis order into 
-           descending order, e.g. 'x y c' into 'y x c'). 
+        '''Create the permutation that would transpose this array to
+           numpy order (that is, from the current axis order into
+           descending order, e.g. 'x y c' into 'y x c').
         '''
         return list(self.axistags.permutationToNumpyOrder())
-    
+
     def permutationFromNumpyOrder(self):
-        '''Create the permutation that would transpose an array that is 
+        '''Create the permutation that would transpose an array that is
            in numpy (descending) order into the axis order of this array.
-           (e.g.  'y x c' into 'x y c'). 
+           (e.g.  'y x c' into 'x y c').
         '''
         return list(self.axistags.permutationFromNumpyOrder())
-    
+
     def permutationToVigraOrder(self):
-        '''Create the permutation that would transpose this array to 
-           VIGRA order (that is, from the current axis order into 
-           ascending spatial order, but with the channel axis at the 
-           last position, e.g. 'c x y' into 'x y c'). 
+        '''Create the permutation that would transpose this array to
+           VIGRA order (that is, from the current axis order into
+           ascending spatial order, but with the channel axis at the
+           last position, e.g. 'c x y' into 'x y c').
         '''
         return list(self.axistags.permutationToVigraOrder())
-    
+
     def permutationFromVigraOrder(self):
-        '''Create the permutation that would transpose an array that is 
-           in VIGRA order (ascending spatial order, but with the channel 
+        '''Create the permutation that would transpose an array that is
+           in VIGRA order (ascending spatial order, but with the channel
            axis at the last position) into the axis order of this array.
-           (e.g.  'x y c' into 'c x y'). 
+           (e.g.  'x y c' into 'c x y').
         '''
         return list(self.axistags.permutationFromVigraOrder())
-    
+
     def transposeToOrder(self, order):
         '''
         Get a transposed view onto this array according to the given 'order'.
         Possible orders are:
-        
-        'A':
+
+        'A' or '' or None:
             return the array unchanged
         'C':
             transpose to descending axis order (e.g. 'z y x c')
@@ -1082,11 +1200,11 @@ class VigraArray(numpy.ndarray):
             transpose to VIGRA order, i.e. ascending spatial axes, but
             the channel axis is last (e.g. 'x y z c')
         '''
-        if order == 'A':
+        if not order or order == 'A':
             return self
         permutation = self.permutationToOrder(order)
         return self.transpose(permutation)
-    
+
     def transposeToDefaultOrder(self):
         '''Equivalent to self.transposeToOrder(VigraArray.defaultOrder).
         '''
@@ -1124,15 +1242,17 @@ class VigraArray(numpy.ndarray):
             * getitem creates an array view => axistags are transferred from the
               corresponding axes of the base array
             * getitem creates a copy of an array (fancy indexing) => all axistags are '?'
-         
-        If the index contains 'numpy.newaxis', a new singleton axis is inserted at the 
+
+        If the index contains 'numpy.newaxis', a new singleton axis is inserted at the
         appropriate position, whose axisinfo is set to '?' (unknown). If the index contains
         'vigra.newaxis(axisinfo)', the singleton axis will get the given axisinfo.
         '''
         try:
             res = numpy.ndarray.__getitem__(self, index)
         except:
-            res = numpy.ndarray.__getitem__(self, 
+            if not isinstance(index, collections.Iterable):
+                raise
+            res = numpy.ndarray.__getitem__(self,
                      map(lambda x: None if isinstance(x, AxisInfo) else x, index))
         if res is not self and hasattr(res, 'axistags'):
             if res.base is self or res.base is self.base:
@@ -1140,23 +1260,23 @@ class VigraArray(numpy.ndarray):
             else:
                 res.axistags = res._empty_axistags(res.ndim)
         return res
-        
+
     def subarray(self, p1, p2=None):
         '''
         Construct a subarray view from a pair of points. The first point denotes the start
         of the subarray (inclusive), the second its end (exclusive). For example,
-        
+
             a.subarray((1,2,3), (4,5,6))  # equivalent to a[1:4, 2:5, 3:6]
-        
-        The given points must have the same dimension, otherwise an IndexError is raised. 
-        If only one point is given, it refers to the subarray's end, and the start is set 
+
+        The given points must have the same dimension, otherwise an IndexError is raised.
+        If only one point is given, it refers to the subarray's end, and the start is set
         to the point (0, 0, ...) with appropriate dimension, for example
-        
+
             a.subarray((4,5,6))           # equivalent to a[:4, :5, :6]
-        
-        The function transforms the given point pair into a tuple of slices and calls 
-        self.__getitem__() in it. If the points have lower dimension than the array, an 
-        Ellipsis ('...') is implicitly appended to the slicing, so that missing axes 
+
+        The function transforms the given point pair into a tuple of slices and calls
+        self.__getitem__() in it. If the points have lower dimension than the array, an
+        Ellipsis ('...') is implicitly appended to the slicing, so that missing axes
         are left unaltered.
         '''
         if p2 is not None:
@@ -1165,13 +1285,13 @@ class VigraArray(numpy.ndarray):
             return self.__getitem__(tuple(map(lambda x,y: slice(x.__int__(), y.__int__()), p1, p2)))
         else:
             return self.__getitem__(tuple(map(lambda x: slice(x.__int__()), p1)))
-    
+
     ###############################################################
     #                                                             #
     #      re-implement ndarray methods to handle axistags        #
     #                                                             #
-    ###############################################################    
-    
+    ###############################################################
+
     @_finalize_reduce_result
     @_preserve_doc
     def all(self, axis=None, out=None):
@@ -1201,7 +1321,7 @@ class VigraArray(numpy.ndarray):
         if type(axis) == str:
             axis = self.axistags.index(axis)
         return numpy.ndarray.argmax(self, axis, out)
-        
+
     @_finalize_reduce_result
     @_preserve_doc
     def argmin(self, axis=None, out=None):
@@ -1211,11 +1331,11 @@ class VigraArray(numpy.ndarray):
         if type(axis) == str:
             axis = self.axistags.index(axis)
         return numpy.ndarray.argmin(self, axis, out)
-    
+
     @_preserve_doc
     def copy(self, order='A'):
         return self.__class__(self, dtype=self.dtype, order=order)
-    
+
     @_preserve_doc
     def cumprod(self, axis=None, dtype=None, out=None):
         '''
@@ -1246,7 +1366,7 @@ class VigraArray(numpy.ndarray):
         The array is always transposed to 'C' order before flattening.
         '''
         return self.transposeToNumpyOrder().view(numpy.ndarray).flat
-    
+
     @_preserve_doc
     def flatten(self, order='C'):
         '''
@@ -1269,7 +1389,7 @@ class VigraArray(numpy.ndarray):
         The 'axis' parameter can be an int (axis position) or string (axis key).
         '''
         return _numpyarray_overloaded_function(numpy.ndarray.mean, self, axis, dtype, out)
-    
+
     @_finalize_reduce_result
     @_preserve_doc
     def min(self, axis=None, out=None):
@@ -1277,10 +1397,10 @@ class VigraArray(numpy.ndarray):
         The 'axis' parameter can be an int (axis position) or string (axis key).
         '''
         return numpy.ndarray.min(self, axis, out)
-    
+
     @_preserve_doc
     def nonzero(self):
-        res = numpy.ndarray.nonzero(self)
+        res = tuple(k.view(type(self)) for k in numpy.ndarray.nonzero(self))
         for k in xrange(len(res)):
             res[k].axistags = AxisTags(AxisInfo(self.axistags[k]))
         return res
@@ -1295,7 +1415,7 @@ class VigraArray(numpy.ndarray):
              reduce(lambda x, y: y if y >= x and x >= 0 else -1, self.strides[:-1], 0) >= 0:
             return 'V'
         return 'A'
-    
+
     @_preserve_doc
     def prod(self, axis=None, dtype=None, out=None):
         '''
@@ -1344,7 +1464,7 @@ class VigraArray(numpy.ndarray):
     def reshape(self, shape, order='C', axistags=None):
         '''
         An additional keyword argument 'axistags' can be used to determine
-        the result's axistags. If not given, all axes of the result will 
+        the result's axistags. If not given, all axes of the result will
         have type 'unknown'.
         '''
         if axistags is not None and len(shape) != len(axistags):
@@ -1354,13 +1474,13 @@ class VigraArray(numpy.ndarray):
             res.axistags = copy.copy(axistags)
         else:
             res.axistags = res._empty_axistags(res.ndim)
-        return res        
+        return res
 
     @_preserve_doc
     def resize(self, new_shape, refcheck=True, order=False, axistags=None):
         '''
         An additional keyword argument 'axistags' can be used to determine
-        the self's axistags after the resize. If not given, all axes will have 
+        the self's axistags after the resize. If not given, all axes will have
         type 'unknown'.
         '''
         # ndarray.resize() internally checks for refcount <= 2
@@ -1375,7 +1495,7 @@ class VigraArray(numpy.ndarray):
             self.axistags = copy.copy(axistags)
         else:
             self.axistags = self._empty_axistags(self.ndim)
-            
+
     @_preserve_doc
     def squeeze(self):
         res = numpy.ndarray.squeeze(self)
@@ -1384,7 +1504,7 @@ class VigraArray(numpy.ndarray):
             for k in xrange(self.ndim-1, -1, -1):
                 if self.shape[k] == 1:
                     del res.axistags[k]
-        return res        
+        return res
 
     @_preserve_doc
     def std(self, axis=None, dtype=None, out=None, ddof=0):
@@ -1399,14 +1519,14 @@ class VigraArray(numpy.ndarray):
         The 'axis' parameter can be an int (axis position) or string (axis key).
         '''
         return _numpyarray_overloaded_function(numpy.ndarray.sum, self, axis, dtype, out)
-            
+
     @_preserve_doc
     def swapaxes(self, i, j, keepTags=False):
         '''
         Parameters 'i' and 'j' can also be ints (axis positions) or strings (axis keys).
-        
+
         If 'keepsTags' is False, axistags are swapped like the axes, otherwise they remain
-        unchanged such that the swapped axes aquire a new meaning. 
+        unchanged such that the swapped axes aquire a new meaning.
         '''
         if type(i) == str:
             i = self.axistags.index(i)
@@ -1419,8 +1539,8 @@ class VigraArray(numpy.ndarray):
                 res.axistags.swapaxes(i, j)
             except:
                 res.axistags[i], res.axistags[j] = res.axistags[j], res.axistags[i]
-        return res        
- 
+        return res
+
     @_preserve_doc
     def take(self, indices, axis=None, out=None, mode='raise'):
         '''
@@ -1433,13 +1553,13 @@ class VigraArray(numpy.ndarray):
             return numpy.ndarray.take(self.ravel(), indices, axis, out, mode)
         else:
             return numpy.ndarray.take(self, indices, axis, out, mode)
-           
+
     @_preserve_doc
     def transpose(self, *axes, **keepTags):
         '''
         An additional keyword parameter 'keepTags' can be provided (it has to be passed as an explicit
-        keyword parameter). If it is True, the axistags will remain unchanged such that the transposed 
-        axes aquire a new meaning. 
+        keyword parameter). If it is True, the axistags will remain unchanged such that the transposed
+        axes aquire a new meaning.
         '''
         keepTags = keepTags.get('keepTags', False)
         res = numpy.ndarray.transpose(self, *axes)
@@ -1459,122 +1579,122 @@ class VigraArray(numpy.ndarray):
     #        reimplement the numerical operators to make          #
     #             sure that array order is preserved              #
     #                                                             #
-    ###############################################################    
-    
+    ###############################################################
+
     def __abs__(self):
         return ufunc.absolute(self)
-    
+
     def __add__(self, other):
         return ufunc.add(self, other)
-        
+
     def __and__(self, other):
         return ufunc.bitwise_and(self, other)
-        
+
     def __div__(self, other):
         return ufunc.divide(self, other)
-    
+
     def __divmod__(self, other):
         return ufunc.floor_divide(self, other), ufunc.remainder(self, other)
-    
+
     def __eq__(self, other):
         return ufunc.equal(self, other)
-    
+
     def __floordiv__(self, other):
         return ufunc.floor_divide(self, other)
-    
+
     def __ge__(self, other):
         return ufunc.greater_equal(self, other)
-    
+
     def __gt__(self, other):
         return ufunc.greater(self, other)
-        
+
     def __invert__(self):
         return ufunc.invert(self)
-    
+
     def __le__(self, other):
         return ufunc.less_equal(self, other)
-    
+
     def __lshift__(self, other):
         return ufunc.left_shift(self, other)
-    
+
     def __lt__(self, other):
         return ufunc.less(self, other)
-    
+
     def __mod__(self, other):
         return ufunc.remainder(self, other)
-    
+
     def __mul__(self, other):
         return ufunc.multiply(self, other)
-    
+
     def __ne__(self, other):
         return ufunc.not_equal(self, other)
-    
+
     def __neg__(self):
         return ufunc.negative(self)
-    
+
     def __or__(self, other):
         return ufunc.bitwise_or(self, other)
-    
+
     def __pos__(self):
         return self
-    
+
     def __pow__(self, other):
         return ufunc.power(self, other)
-    
+
     def __radd__(self, other):
         return ufunc.add(other, self)
-    
+
     def __radd__(self, other):
         return ufunc.add(other, self)
-    
+
     def __rand__(self, other):
         return ufunc.bitwise_and(other, self)
-    
+
     def __rdiv__(self, other):
         return ufunc.divide(other, self)
-    
+
     def __rdivmod__(self, other):
         return ufunc.floor_divide(other, self), ufunc.remainder(other, self)
-    
+
     def __rfloordiv__(self, other):
         return ufunc.floor_divide(other, self)
-    
+
     def __rlshift__(self, other):
         return ufunc.left_shoft(other, self)
-    
+
     def __rmod__(self, other):
         return ufunc.remainder(other, self)
-    
+
     def __rmul__(self, other):
         return ufunc.multiply(other, self)
-    
+
     def __ror__(self, other):
         return ufunc.bitwise_or(other, self)
-    
+
     def __rpow__(self, other):
         return ufunc.power(other, self)
-    
+
     def __rrshift__(self, other):
         return ufunc.right_shift(other, self)
-    
+
     def __rshift__(self, other):
         return ufunc.right_shift(self, other)
 
     def __rsub__(self, other):
         return ufunc.subtract(other, self)
-    
+
     def __rtruediv__(self, other):
         return ufunc.true_divide(other, self)
-    
+
     def __rxor__(self, other):
         return ufunc.bitwise_xor(other, self)
-    
+
     def __sub__(self, other):
         return ufunc.subtract(self, other)
-    
+
     def __truediv__(self, other):
         return ufunc.true_divide(self, other)
-    
+
     def __xor__(self, other):
         return ufunc.bitwise_xor(self, other)
 
@@ -1594,7 +1714,7 @@ def _adjustShape(shape, order, spatialDimensions, channelCount, axistags, name):
                 shape = (channelCount,) + shape
             else:
                 shape = shape + (channelCount,)
-    else:        
+    else:
         if channelCount is None or len(shape) != spatialDimensions + 1:
             raise RuntimeError("%s: input shape has wrong length." % name)
         if channelCount > 0:
@@ -1656,66 +1776,66 @@ def _adjustInput(obj, order, spatialDimensions, channelCount, axistags, name):
 
 #################################################################
 
-def Image(obj, dtype=numpy.float32, order=None, 
+def Image(obj, dtype=numpy.float32, order=None,
           init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing an image (i.e. an array with 
-    two spatial axes 'x' and 'y' and optionally a channel axis 'c'). 
+    Factory function for a :class:`~vigra.VigraArray` representing an image (i.e. an array with
+    two spatial axes 'x' and 'y' and optionally a channel axis 'c').
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are not image-like.
     '''
     obj, axistags = _adjustInput(obj, order, 2, 0, axistags, "vigra.Image()")
     return VigraArray(obj, dtype, None, init, value, axistags)
-        
-def ScalarImage(obj, dtype=numpy.float32, order=None, 
+
+def ScalarImage(obj, dtype=numpy.float32, order=None,
                 init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a single-band image (i.e. an 
-    array with two spatial axes 'x' and 'y' and no channel axis). 
+    Factory function for a :class:`~vigra.VigraArray` representing a single-band image (i.e. an
+    array with two spatial axes 'x' and 'y' and no channel axis).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for a single-band image.
     '''
     obj, axistags = _adjustInput(obj, order, 2, None, axistags, "vigra.ScalarImage()")
     return VigraArray(obj, dtype, None, init, value, axistags)
-        
-def Vector2Image(obj, dtype=numpy.float32, order=None, 
+
+def Vector2Image(obj, dtype=numpy.float32, order=None,
                  init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a 2-band image (i.e. an 
-    array with two spatial axes 'x' and 'y' and channel axis 'c' with 2 channels). 
+    Factory function for a :class:`~vigra.VigraArray` representing a 2-band image (i.e. an
+    array with two spatial axes 'x' and 'y' and channel axis 'c' with 2 channels).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for a 2-band image.
     '''
     obj, axistags = _adjustInput(obj, order, 2, 2, axistags, "vigra.Vector2Image()")
     return VigraArray(obj, dtype, None, init, value, axistags)
 
-def Vector3Image(obj, dtype=numpy.float32, order=None, 
+def Vector3Image(obj, dtype=numpy.float32, order=None,
                  init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a 3-band image (i.e. an 
-    array with two spatial axes 'x' and 'y' and channel axis 'c' with 3 channels). 
+    Factory function for a :class:`~vigra.VigraArray` representing a 3-band image (i.e. an
+    array with two spatial axes 'x' and 'y' and channel axis 'c' with 3 channels).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for a 3-band image.
     '''
     obj, axistags = _adjustInput(obj, order, 2, 3, axistags, "vigra.Vector3Image()")
     return VigraArray(obj, dtype, None, init, value, axistags)
 
-def Vector4Image(obj, dtype=numpy.float32, order=None, 
+def Vector4Image(obj, dtype=numpy.float32, order=None,
                  init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a 4-band image (i.e. an 
-    array with two spatial axes 'x' and 'y' and channel axis 'c' with 4 channels). 
+    Factory function for a :class:`~vigra.VigraArray` representing a 4-band image (i.e. an
+    array with two spatial axes 'x' and 'y' and channel axis 'c' with 4 channels).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for a 4-band image.
     '''
     obj, axistags = _adjustInput(obj, order, 2, 4, axistags, "vigra.Vector4Image()")
     return VigraArray(obj, dtype, None, init, value, axistags)
 
-def RGBImage(obj, dtype=numpy.float32, order=None, 
+def RGBImage(obj, dtype=numpy.float32, order=None,
              init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a RGB image (i.e. an 
-    array with two spatial axes 'x' and 'y' and channel axis 'c' with 3 channels). 
+    Factory function for a :class:`~vigra.VigraArray` representing a RGB image (i.e. an
+    array with two spatial axes 'x' and 'y' and channel axis 'c' with 3 channels).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for an RGB image.
     '''
@@ -1726,77 +1846,77 @@ def RGBImage(obj, dtype=numpy.float32, order=None,
 
 #################################################################
 
-def Volume(obj, dtype=numpy.float32, order=None, 
+def Volume(obj, dtype=numpy.float32, order=None,
            init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a volume (i.e. an array with 
-    three spatial axes 'x', 'y' and 'z' and optionally a channel axis 'c'). 
+    Factory function for a :class:`~vigra.VigraArray` representing a volume (i.e. an array with
+    three spatial axes 'x', 'y' and 'z' and optionally a channel axis 'c').
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are not volume-like.
     '''
     obj, axistags = _adjustInput(obj, order, 3, 0, axistags, "vigra.Volume()")
     return VigraArray(obj, dtype, None, init, value, axistags)
 
-def ScalarVolume(obj, dtype=numpy.float32, order=None, 
+def ScalarVolume(obj, dtype=numpy.float32, order=None,
                  init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a single-band volume (i.e. an 
-    array with three spatial axes 'x', 'y' and 'z' and no channel axis). 
+    Factory function for a :class:`~vigra.VigraArray` representing a single-band volume (i.e. an
+    array with three spatial axes 'x', 'y' and 'z' and no channel axis).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for a single-band volume.
     '''
     obj, axistags = _adjustInput(obj, order, 3, None, axistags, "vigra.ScalarVolume()")
     return VigraArray(obj, dtype, None, init, value, axistags)
 
-def Vector2Volume(obj, dtype=numpy.float32, order=None, 
+def Vector2Volume(obj, dtype=numpy.float32, order=None,
                   init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a 2-band volume (i.e. an 
-    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 2 channels). 
+    Factory function for a :class:`~vigra.VigraArray` representing a 2-band volume (i.e. an
+    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 2 channels).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for a 2-band volume.
     '''
     obj, axistags = _adjustInput(obj, order, 3, 2, axistags, "vigra.Vector2Volume()")
     return VigraArray(obj, dtype, None, init, value, axistags)
 
-def Vector3Volume(obj, dtype=numpy.float32, order=None, 
+def Vector3Volume(obj, dtype=numpy.float32, order=None,
                   init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a 3-band volume (i.e. an 
-    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 3 channels). 
+    Factory function for a :class:`~vigra.VigraArray` representing a 3-band volume (i.e. an
+    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 3 channels).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for a 3-band volume.
     '''
     obj, axistags = _adjustInput(obj, order, 3, 3, axistags, "vigra.Vector3Volume()")
     return VigraArray(obj, dtype, None, init, value, axistags)
 
-def Vector4Volume(obj, dtype=numpy.float32, order=None, 
+def Vector4Volume(obj, dtype=numpy.float32, order=None,
                   init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a 4-band volume (i.e. an 
-    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 4 channels). 
+    Factory function for a :class:`~vigra.VigraArray` representing a 4-band volume (i.e. an
+    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 4 channels).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for a 4-band volume.
     '''
     obj, axistags = _adjustInput(obj, order, 3, 4, axistags, "vigra.Vector4Volume()")
     return VigraArray(obj, dtype, None, init, value, axistags)
 
-def Vector6Volume(obj, dtype=numpy.float32, order=None, 
+def Vector6Volume(obj, dtype=numpy.float32, order=None,
                   init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing a 6-band volume (i.e. an 
-    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 6 channels). 
+    Factory function for a :class:`~vigra.VigraArray` representing a 6-band volume (i.e. an
+    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 6 channels).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for a 6-band volume.
     '''
     obj, axistags = _adjustInput(obj, order, 3, 6, axistags, "vigra.Vector6Volume()")
     return VigraArray(obj, dtype, None, init, value, axistags)
 
-def RGBVolume(obj, dtype=numpy.float32, order=None, 
+def RGBVolume(obj, dtype=numpy.float32, order=None,
               init=True, value=None, axistags=None):
     '''
-    Factory function for a :class:`~vigra.VigraArray` representing an RGB volume (i.e. an 
-    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 3 channels). 
+    Factory function for a :class:`~vigra.VigraArray` representing an RGB volume (i.e. an
+    array with three spatial axes 'x', 'y' and 'z' and channel axis 'c' with 3 channels).
     Paramters are interpreted as in the VigraArray constructor, but an exception
     will be raised if the shape or axistags are unsuitable for an RGB volume.
     '''
@@ -1814,15 +1934,16 @@ class ImagePyramid(list):
             and the given 'image' is copied to 'copyImageToLevel'. The images at other
             levels are filled with zeros and sized so that the shape is reduced by half
             when going up (to higher levels), and doubled when going down.
-            
+
             This class can handle multi-channel images, but only when image.channelIndex
-            exists and returns image.ndim-1 (i.e. the image must have axistags, and the 
+            exists and returns image.ndim-1 (i.e. the image must have axistags, and the
             channel axis must correspond to the last index, as in C- or V-order).
         '''
         if lowestLevel > copyImageToLevel or highestLevel < copyImageToLevel:
             raise ValueError('ImagePyramid(): copyImageToLevel must be between lowestLevel and highestLevel (inclusive)')
-        
-        list.__init__(self, [image.__class__(image, dtype=image.dtype)])
+
+        import copy
+        list.__init__(self, [copy.deepcopy(image)])
         self._lowestLevel = copyImageToLevel
         self._highestLevel = copyImageToLevel
         self.createLevel(lowestLevel)
@@ -1833,13 +1954,39 @@ class ImagePyramid(list):
         '''The pyramids lowest level.
         '''
         return self._lowestLevel
-    
+
     @property
     def highestLevel(self):
         '''The pyramids highest level (inclusive).
         '''
         return self._highestLevel
-    
+
+    @property
+    def ndim(self):
+        '''The dimension of the images in this pyramid.
+        '''
+        return self[self._highestLevel].ndim
+
+    @property
+    def dtype(self):
+        '''The pixel type of the images in this pyramid.
+        '''
+        return self[self._highestLevel].dtype
+
+    @property
+    def channelIndex(self):
+        '''The channel dimension of the images in this pyramid.
+           If the images have no axistags, or no channel axis is
+           specified, this defaults to 'ndim'.
+        '''
+        return getattr(self[self._highestLevel], 'channelIndex', self.ndim)
+
+    @property
+    def axistags(self):
+        '''The axistags of the images in this pyramid.
+        '''
+        return getattr(self[self._highestLevel], 'axistags', None)
+
     def __getitem__(self, level):
         '''Get the image at 'level'.
            Raises IndexError when the level does not exist.
@@ -1847,19 +1994,19 @@ class ImagePyramid(list):
         if level < self.lowestLevel or level > self.highestLevel:
             raise IndexError("ImagePyramid[level]: level out of range.")
         return list.__getitem__(self, level - self.lowestLevel)
-    
+
     def __setitem__(self, level, image):
         '''Copy the data of the given 'image' to the image at 'level'.
            Raises IndexError when the level does not exist.
         '''
         self[level][...] = image[...]
-        
+
     def expandImpl(self, src, dest, centerValue):
         import filters
-        
+
         ss, ds = src.shape, dest.shape
         s = [ss[k] if 2*ss[k] == ds[k] else -1 for k in range(len(ss))]
-    
+
         smooth1 = filters.explictKernel(-1, 1, numpy.array([0.5 - centerValue, 2.0*centerValue, 0.5 - centerValue]))
         smooth2 = filters.explictKernel(-1, 0, numpy.array([0.5, 0.5]));
 
@@ -1867,23 +2014,23 @@ class ImagePyramid(list):
         filters.convolve(src[:,:s[1]], (smooth1, smooth2), out=dest[::2,1::2])
         filters.convolve(src[:s[0],:], (smooth2, smooth1), out=dest[1::2,::2])
         filters.convolve(src[:s[0],:s[1]], (smooth2, smooth2), out=dest[1::2,1::2])
-    
+
     def reduce(self, srcLevel, destLevel, centerValue = 0.42):
         '''Reduce the image at 'srcLevel' to 'destLevel', using the Burt smoothing filter
            with the given 'centerValue'. srcLevel must be smaller than destLevel.
-           
+
            For more details, see pyramidReduceBurtFilter_ in the C++ documentation.
         '''
         # FIXME: This should be implemented in C++
         # FIXME: This should be implemented for arbitrary dimensions
         import filters
-        
+
         if srcLevel > destLevel:
             raise RuntimeError("ImagePyramid::reduce(): srcLevel <= destLevel required.")
         if srcLevel < self.lowestLevel or srcLevel > self.highestLevel:
             raise RuntimeError("ImagePyramid::reduce(): srcLevel does not exist.")
         self.createLevel(destLevel)
-        
+
         smooth = filters.burtFilterKernel(0.25 - 0.5*centerValue)
         for k in range(srcLevel, destLevel):
             i = filters.convolve(self[k], smooth)
@@ -1892,7 +2039,7 @@ class ImagePyramid(list):
     def expand(self, srcLevel, destLevel, centerValue = 0.42):
         '''Expand the image at 'srcLevel' to 'destLevel', using the Burt smoothing filter
            with the given 'centerValue'. srcLevel must be larger than destLevel.
-           
+
            For more details, see pyramidExpandBurtFilter_ in the C++ documentation.
         '''
         # FIXME: This should be implemented in C++
@@ -1910,13 +2057,13 @@ class ImagePyramid(list):
         '''Reduce the image at 'srcLevel' to 'destLevel', using the Burt smoothing filter
            with the given 'centerValue', and compute Laplacian images for the levels
            srcLevel ... destLevel-1. srcLevel must be smaller than destLevel.
-           
+
            For more details, see pyramidReduceBurtLaplacian_ in the C++ documentation.
         '''
         # FIXME: This should be implemented in C++
         # FIXME: This should be implemented for arbitrary dimensions
         import filters
-        
+
         if srcLevel > destLevel:
             raise RuntimeError("ImagePyramid::reduceLaplacian(): srcLevel <= destLevel required.")
         if srcLevel < self.lowestLevel or srcLevel > self.highestLevel:
@@ -1934,13 +2081,13 @@ class ImagePyramid(list):
         '''Expand the image at 'srcLevel' to 'destLevel', using the Burt smoothing filter
            with the given 'centerValue', and reconstruct the images for the levels
            srcLevel-1 ... destLevel from their Laplacian images. srcLevel must be larger than destLevel.
-           
+
            For more details, see pyramidExpandBurtLaplacian_ in the C++ documentation.
         '''
         # FIXME: This should be implemented in C++
         # FIXME: This should be implemented for arbitrary dimensions
         import filters
-        
+
         if srcLevel < destLevel:
             raise RuntimeError("ImagePyramid::expandLaplacian(): srcLevel >= destLevel required.")
         if srcLevel < self.lowestLevel or srcLevel > self.highestLevel:
@@ -1958,22 +2105,33 @@ class ImagePyramid(list):
         ''' Make sure that 'level' exists. If 'level' is outside the current range of levels,
             empty images of the appropriate shape are inserted into the pyramid.
         '''
+        channelIndex = self.channelIndex
+        hasChannels = channelIndex < self.ndim
+        axistags = self.axistags
         if level > self.highestLevel:
+            image = list.__getitem__(self, -1)
             for i in range(self.highestLevel, level):
-                image = list.__getitem__(self, -1)
                 newShape = [int((k + 1) / 2) for k in image.shape]
-                channelIndex = getattr(image, 'channelIndex', image.ndim)
-                if channelIndex < image.ndim:
+                if hasChannels:
                     newShape[channelIndex] = image.shape[channelIndex]
-                self.append(image.__class__(newShape, dtype=image.dtype))
+                if axistags:
+                    image = image.__class__(newShape, dtype=image.dtype, axistags=axistags)
+                else:
+                    image = image.__class__(newShape, dtype=image.dtype)
+                    image[...] = 0
+                self.append(image)
             self._highestLevel = level
         elif level < self.lowestLevel:
             image = list.__getitem__(self, 0)
             for i in range(self.lowestLevel, level, -1):
                 newShape = [2*k-1 for k in image.shape]
-                channelIndex = getattr(image, 'channelIndex', image.ndim)
-                if channelIndex < image.ndim:
+                if hasChannels:
                     newShape[channelIndex] = image.shape[channelIndex]
-                self.insert(0, image.__class__(newShape, dtype=image.dtype))
+                if axistags:
+                    image = image.__class__(newShape, dtype=image.dtype, axistags=axistags)
+                else:
+                    image = image.__class__(newShape, dtype=image.dtype)
+                    image[...] = 0
+                self.insert(0, image)
             self._lowestLevel = level
-             
+
diff --git a/vigranumpy/lib/pyqt/imagewindow.py b/vigranumpy/lib/pyqt/imagewindow.py
index 27220ac..449030a 100644
--- a/vigranumpy/lib/pyqt/imagewindow.py
+++ b/vigranumpy/lib/pyqt/imagewindow.py
@@ -50,7 +50,7 @@ except Exception, e:
     %s
 
     If VigraQt is missing on your system, you can download it from
-    http://kogs-www.informatik.uni-hamburg.de/~meine/software/vigraqt/.''' % str(e))
+    https://github.com/hmeine/vigraqt/#vigraqt4''' % str(e))
     from VigraQt import OverlayViewer, ImageCursor
 
 import quickdialog
diff --git a/vigranumpy/setup.py.in b/vigranumpy/setup.py.cmake2.in
similarity index 90%
copy from vigranumpy/setup.py.in
copy to vigranumpy/setup.py.cmake2.in
index 55ef0c0..8fc98c9 100644
--- a/vigranumpy/setup.py.in
+++ b/vigranumpy/setup.py.cmake2.in
@@ -21,7 +21,7 @@ shutil.copy(vigraimpex_dll, '@vigranumpy_tmp_dir@/dlls')
 msvc_runtime = ctypes.util.find_library(ctypes.util.find_msvcrt())
 shutil.copy(msvc_runtime, '@vigranumpy_tmp_dir@/dlls')
 
-docdir = '@DOCDIR@'    
+docdir = '@DOCDIR@'
 
 setup(name = 'vigranumpy',
       description = 'VIGRA Computer Vision Library',
@@ -32,6 +32,6 @@ setup(name = 'vigranumpy',
       version = '@vigra_version@',
       packages = ['vigra', 'vigra.pyqt'],
       package_dir = {'vigra': 'vigra', 'vigra.pyqt': 'vigra/pyqt'},
-      package_data = {'vigra': ['*.pyd', 'dlls/*.dll', 
-                  'doc/vigra/*.*', 'doc/vigra/documents/*.*', 
+      package_data = {'vigra': ['*.pyd', 'dlls/*.dll',
+                  'doc/vigra/*.*', 'doc/vigra/documents/*.*',
                   'doc/vigranumpy/*.*', 'doc/vigranumpy/_static/*.*']})
diff --git a/vigranumpy/setup.py.in b/vigranumpy/setup.py.in
index 55ef0c0..69e36b4 100644
--- a/vigranumpy/setup.py.in
+++ b/vigranumpy/setup.py.in
@@ -16,12 +16,12 @@ for d in dlls:
         continue
     dll = ctypes.util.find_library(os.path.splitext(os.path.basename(d))[0])
     shutil.copy(dll, '@vigranumpy_tmp_dir@/dlls')
-vigraimpex_dll='@VIGRAIMPEX_LOCATION@'.replace('$(OutDir)', 'release').replace('$(Configuration)', 'release')
+vigraimpex_dll = r'$<TARGET_FILE:vigraimpex>'
 shutil.copy(vigraimpex_dll, '@vigranumpy_tmp_dir@/dlls')
 msvc_runtime = ctypes.util.find_library(ctypes.util.find_msvcrt())
 shutil.copy(msvc_runtime, '@vigranumpy_tmp_dir@/dlls')
 
-docdir = '@DOCDIR@'    
+docdir = '@DOCDIR@'
 
 setup(name = 'vigranumpy',
       description = 'VIGRA Computer Vision Library',
@@ -32,6 +32,6 @@ setup(name = 'vigranumpy',
       version = '@vigra_version@',
       packages = ['vigra', 'vigra.pyqt'],
       package_dir = {'vigra': 'vigra', 'vigra.pyqt': 'vigra/pyqt'},
-      package_data = {'vigra': ['*.pyd', 'dlls/*.dll', 
-                  'doc/vigra/*.*', 'doc/vigra/documents/*.*', 
+      package_data = {'vigra': ['*.pyd', 'dlls/*.dll',
+                  'doc/vigra/*.*', 'doc/vigra/documents/*.*',
                   'doc/vigranumpy/*.*', 'doc/vigranumpy/_static/*.*']})
diff --git a/vigranumpy/src/core/CMakeLists.txt b/vigranumpy/src/core/CMakeLists.txt
index 1e8b04a..9def1c3 100644
--- a/vigranumpy/src/core/CMakeLists.txt
+++ b/vigranumpy/src/core/CMakeLists.txt
@@ -2,6 +2,22 @@ IF(MSVC)
     SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
 ENDIF()
 
+include(VigraConfigureThreading)
+VIGRA_CONFIGURE_THREADING(REQUIRED) # We require a working threading implementation.
+
+if(WITH_BOOST_THREAD)
+    INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})
+    SET(VIGRANUMPY_THREAD_LIBRARIES ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${Boost_CHRONO_LIBRARY})
+elseif(NOT MSVC)
+    IF (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0")
+        SET(CMAKE_CXX_FLAGS "-pthread -std=c++0x ${CMAKE_CXX_FLAGS}")
+    elseif(CMAKE_COMPILER_IS_GNUCXX)
+        SET(CMAKE_CXX_FLAGS "-pthread -std=c++11 ${CMAKE_CXX_FLAGS}")
+    else()
+        SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
+    endif()
+endif()
+
 # note special treatment of target vigranumpy_core: 
 # module name is automatically changed into vigranumpycore
 VIGRA_ADD_NUMPY_MODULE(core 
@@ -9,6 +25,9 @@ VIGRA_ADD_NUMPY_MODULE(core
     vigranumpycore.cxx
     converters.cxx
     axistags.cxx
+    multi_array_chunked.cxx
+  LIBRARIES   
+    ${VIGRANUMPY_IMPEX_LIBRARIES} ${VIGRANUMPY_THREAD_LIBRARIES}
   VIGRANUMPY)
 
 VIGRA_ADD_NUMPY_MODULE(impex 
@@ -22,15 +41,18 @@ VIGRA_ADD_NUMPY_MODULE(sampling
   SOURCES
     sampling.cxx
   VIGRANUMPY)
-   
+
 VIGRA_ADD_NUMPY_MODULE(filters SOURCES
     kernel.cxx
     convolution.cxx
     filters.cxx
     tensors.cxx
     morphology.cxx
+    non_local_mean.cxx
+  LIBRARIES 
+    ${VIGRANUMPY_THREAD_LIBRARIES}
   VIGRANUMPY)
-   
+  
 VIGRA_ADD_NUMPY_MODULE(analysis SOURCES
     segmentation.cxx
     edgedetection.cxx
@@ -63,3 +85,31 @@ VIGRA_ADD_NUMPY_MODULE(geometry SOURCES
 VIGRA_ADD_NUMPY_MODULE(optimization SOURCES
     optimization.cxx
   VIGRANUMPY)
+
+
+
+VIGRA_ADD_NUMPY_MODULE(graphs SOURCES
+    graphs.cxx
+    adjacencyListGraph.cxx
+    gridGraphNd.cxx
+    gridGraph2d.cxx
+    gridGraph3d.cxx
+    grid_graph_implicit_edge_maps.cxx
+    #eccentricity.cxx
+  LIBRARIES
+    ${VIGRANUMPY_IMPEX_LIBRARIES}  ${VIGRANUMPY_THREAD_LIBRARIES}
+  VIGRANUMPY)
+
+VIGRA_ADD_NUMPY_MODULE(histogram SOURCES
+    histogram.cxx
+  VIGRANUMPY)
+
+VIGRA_ADD_NUMPY_MODULE(utilities SOURCES
+    utilities.cxx
+  VIGRANUMPY)
+
+
+VIGRA_ADD_NUMPY_MODULE(blockwise SOURCES
+    blockwise.cxx
+  VIGRANUMPY)
+
diff --git a/vigranumpy/src/core/accumulator-region-singleband.cxx b/vigranumpy/src/core/accumulator-region-singleband.cxx
index c2d0a8c..ac19eac 100644
--- a/vigranumpy/src/core/accumulator-region-singleband.cxx
+++ b/vigranumpy/src/core/accumulator-region-singleband.cxx
@@ -37,12 +37,306 @@
 #define NO_IMPORT_ARRAY
 
 #include "pythonaccumulator.hxx"
+#include <vigra/skeleton.hxx>
 
 namespace python = boost::python;
 
 namespace vigra
 {
 
+// Helper functions for stringification of macro string constants
+#define STR(s) #s
+#define XSTR(s) s
+
+template <unsigned int N, class T>
+python::object
+extractConvexHullFeatures(NumpyArray<N, Singleband<T> > const & labels,
+                          python::object ignore_label,
+                          bool list_features_only=false)
+{
+    using namespace vigra::acc;
+
+    #define VIGRA_CONVEX_HULL_FEATURE_INPUT_COUNT "Input Count"
+    #define VIGRA_CONVEX_HULL_FEATURE_INPUT_PERIMETER "Input Perimeter"
+    #define VIGRA_CONVEX_HULL_FEATURE_INPUT_AREA "Input Area"
+    #define VIGRA_CONVEX_HULL_FEATURE_AREA "Area"
+    #define VIGRA_CONVEX_HULL_FEATURE_PERIMETER "Perimeter"
+    #define VIGRA_CONVEX_HULL_FEATURE_RUGOSITY "Rugosity"
+    #define VIGRA_CONVEX_HULL_FEATURE_CONVEXITY "Convexity"
+    #define VIGRA_CONVEX_HULL_FEATURE_DEFECT_COUNT "Defect Count"
+    #define VIGRA_CONVEX_HULL_FEATURE_DEFECT_MEAN_DISPLACEMENT "Defect Mean Displacement"
+    #define VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_LIST "Defect Area List"
+    #define VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_MEAN "Defect Area Mean"
+    #define VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_VARIANCE "Defect Area Variance"
+    #define VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_SKEWNESS "Defect Area Skewness"
+    #define VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_KURTOSIS "Defect Area Kurtosis"
+    #define VIGRA_CONVEX_HULL_FEATURE_POLYGON "Polygon"
+
+    #define VIGRA_CONVEX_HULL_VECTOR_FEATURE_INPUT_CENTER "Input Center"
+    #define VIGRA_CONVEX_HULL_VECTOR_FEATURE_CENTER "Center"
+    #define VIGRA_CONVEX_HULL_VECTOR_FEATURE_DEFECT_CENTER "Defect Center"
+
+    if(list_features_only)
+    {
+
+        python::list res;
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_INPUT_COUNT));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_INPUT_PERIMETER));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_INPUT_AREA));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_AREA));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_PERIMETER));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_RUGOSITY));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_CONVEXITY));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_POLYGON));
+
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_DEFECT_COUNT));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_DEFECT_MEAN_DISPLACEMENT));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_LIST));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_MEAN));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_VARIANCE));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_SKEWNESS));
+        res.append(XSTR(VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_KURTOSIS));
+
+        res.append(XSTR(VIGRA_CONVEX_HULL_VECTOR_FEATURE_INPUT_CENTER));
+        res.append(XSTR(VIGRA_CONVEX_HULL_VECTOR_FEATURE_CENTER));
+
+        res.append(XSTR(VIGRA_CONVEX_HULL_VECTOR_FEATURE_DEFECT_CENTER));
+
+        return res;
+    }
+
+    TinyVector<npy_intp, N> permutation = labels.template permuteLikewise<N>();
+
+    AccumulatorChainArray<CoupledArrays<N, T>, 
+                          Select<ConvexHull, DataArg<1>, LabelArg<1> >
+                         > acc;
+
+    MultiArrayIndex ignored_label = -1;
+    if(ignore_label != python::object())
+    {
+        ignored_label = python::extract<MultiArrayIndex>(ignore_label)();
+        acc.ignoreLabel(ignored_label);
+    }
+
+    {
+        PyAllowThreads _pythread;
+        
+        extractFeatures(labels, acc);
+    }
+    
+    int size = acc.maxRegionLabel()+1;
+    python::dict res;
+    {
+        NumpyArray<1, npy_uint32> array((Shape1(size)));
+        for(int k=0; k<size; ++k)
+        {
+            if(k == ignored_label)
+                continue;
+            array(k) = get<Count>(acc, k);
+        }
+        res[XSTR(VIGRA_CONVEX_HULL_FEATURE_INPUT_COUNT)] = array;
+    }
+    
+    #define VIGRA_CONVEX_HULL_FEATURE(TYPE, NAME, FUNCTION) \
+    { \
+        NumpyArray<1, TYPE> array((Shape1(size)));        \
+        for(int k=0; k<size; ++k) \
+        { \
+            if(k == ignored_label || get<Count>(acc, k) == 0) \
+                continue; \
+            array(k) = get<ConvexHull>(acc, k).FUNCTION(); \
+        } \
+        res[XSTR(NAME)] = array;                        \
+    }
+    
+    #define VIGRA_CONVEX_HULL_FEATURE_DEFECT(TYPE, NAME, FUNCTION) \
+    { \
+        NumpyArray<1, double> array((Shape1(size)));        \
+        for(int k=0; k<size; ++k) \
+        { \
+            if(k == ignored_label || get<Count>(acc, k) == 0) \
+              continue; \
+            array(k) = get<ConvexHull>(acc, k).meanDefectDisplacement(); \
+        } \
+        res[XSTR(NAME)] = array;                        \
+    }
+
+    VIGRA_CONVEX_HULL_FEATURE(double, VIGRA_CONVEX_HULL_FEATURE_INPUT_PERIMETER, inputPerimeter)
+    VIGRA_CONVEX_HULL_FEATURE(double, VIGRA_CONVEX_HULL_FEATURE_INPUT_AREA, inputArea)
+    VIGRA_CONVEX_HULL_FEATURE(double, VIGRA_CONVEX_HULL_FEATURE_PERIMETER, hullPerimeter)
+    VIGRA_CONVEX_HULL_FEATURE(double, VIGRA_CONVEX_HULL_FEATURE_AREA, hullArea)
+    VIGRA_CONVEX_HULL_FEATURE(double, VIGRA_CONVEX_HULL_FEATURE_CONVEXITY, convexity)
+    VIGRA_CONVEX_HULL_FEATURE(double, VIGRA_CONVEX_HULL_FEATURE_RUGOSITY, rugosity)
+    VIGRA_CONVEX_HULL_FEATURE(npy_uint32, VIGRA_CONVEX_HULL_FEATURE_DEFECT_COUNT, convexityDefectCount)
+
+    VIGRA_CONVEX_HULL_FEATURE_DEFECT(double, VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_MEAN, convexityDefectAreaMean)
+    VIGRA_CONVEX_HULL_FEATURE_DEFECT(double, VIGRA_CONVEX_HULL_FEATURE_DEFECT_MEAN_DISPLACEMENT, meanDefectDisplacement)
+    VIGRA_CONVEX_HULL_FEATURE_DEFECT(double, VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_VARIANCE, convexityDefectAreaVariance)
+    VIGRA_CONVEX_HULL_FEATURE_DEFECT(double, VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_SKEWNESS, convexityDefectAreaSkewness)
+    VIGRA_CONVEX_HULL_FEATURE_DEFECT(double, VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_KURTOSIS, convexityDefectAreaKurtosis)
+    
+    #undef VIGRA_CONVEX_HULL_FEATURE
+    
+    {
+        python::list hulls;
+        for(int k=0; k<size; ++k)
+        {
+            if(k == ignored_label || get<Count>(acc, k) == 0)
+            {
+                hulls.append(python::object());
+                continue;
+            }
+            int hull_size = get<ConvexHull>(acc, k).hull().size();
+            NumpyArray<2, double> array(Shape2(hull_size, N));
+            Polygon<TinyVector<double, 2> > poly = (permutation == Shape2(0,1))
+                                                       ? get<ConvexHull>(acc, k).hull()
+                                                       : reverse(transpose(get<ConvexHull>(acc, k).hull()));
+            for(int p=0; p<hull_size; ++p)
+            {
+                for(int j=0; j<N; ++j)
+                    array(p, j) = poly[p][j];
+            }
+            hulls.append(array);
+        }
+        res[XSTR(VIGRA_CONVEX_HULL_FEATURE_POLYGON)] = hulls;
+    }
+    
+    {
+        NumpyArray<2, double> array(Shape2(size, 3));
+        for(int k=0; k<size; ++k)
+        {
+            if(k == ignored_label || get<Count>(acc, k) == 0)
+                continue;
+            int defects = min<int>(3, get<ConvexHull>(acc, k).convexityDefectCount());
+            for(int j=0; j<defects; ++j)
+                array(k, j) = get<ConvexHull>(acc, k).defectAreaList()[j];
+        }
+        res[XSTR(VIGRA_CONVEX_HULL_FEATURE_DEFECT_AREA_LIST)] = array;
+    }
+    
+    #define VIGRA_CONVEX_HULL_VECTOR_FEATURE(NAME, FUNCTION) \
+    { \
+        NumpyArray<2, double> array(Shape2(size, N)); \
+        for(int k=0; k<size; ++k) \
+        { \
+            if(k == ignored_label || get<Count>(acc, k) == 0)        \
+                continue; \
+            for(int j=0; j<N; ++j) \
+                array(k, permutation[j]) = get<ConvexHull>(acc, k).FUNCTION()[j]; \
+        } \
+        res[XSTR(NAME)] = array; \
+    }
+    
+    #define VIGRA_CONVEX_HULL_VECTOR_FEATURE_DEFECT(NAME, FUNCTION) \
+    { \
+        NumpyArray<2, double> array(Shape2(size, N)); \
+        for(int k=0; k<size; ++k) \
+        { \
+            if(k == ignored_label || get<Count>(acc, k) == 0)        \
+                continue; \
+            for(int j=0; j<N; ++j) \
+                array(k, permutation[j]) = get<ConvexHull>(acc, k).FUNCTION()[j]; \
+        } \
+        res[XSTR(NAME)] = array; \
+    }
+    
+    VIGRA_CONVEX_HULL_VECTOR_FEATURE(VIGRA_CONVEX_HULL_VECTOR_FEATURE_INPUT_CENTER, inputCenter)
+    VIGRA_CONVEX_HULL_VECTOR_FEATURE(VIGRA_CONVEX_HULL_VECTOR_FEATURE_CENTER, hullCenter)
+
+    VIGRA_CONVEX_HULL_VECTOR_FEATURE_DEFECT(VIGRA_CONVEX_HULL_VECTOR_FEATURE_DEFECT_CENTER, convexityDefectCenter)
+
+    #undef VIGRA_CONVEX_HULL_VECTOR_FEATURE
+
+    return res;
+}
+
+template <unsigned int N, class T>
+python::object
+pyExtractSkeletonFeatures(NumpyArray<N, Singleband<T> > const & labels,
+                          double pruning_threshold,
+                          bool list_features_only=false)
+{
+    using namespace vigra::acc;
+
+    #define VIGRA_SKELETON_FEATURE_DIAMETER "Diameter"
+    #define VIGRA_SKELETON_FEATURE_EUCLIDEAN_DIAMETER "Euclidean Diameter"
+    #define VIGRA_SKELETON_FEATURE_TOTAL_LENGTH "Total Length"
+    #define VIGRA_SKELETON_FEATURE_AVERAGE_LENGTH "Average Length"
+    #define VIGRA_SKELETON_FEATURE_BRANCH_COUNT "Branch Count"
+    #define VIGRA_SKELETON_FEATURE_HOLE_COUNT "Hole Count"
+    #define VIGRA_SKELETON_VECTOR_FEATURE_CENTER "Center"
+    #define VIGRA_SKELETON_VECTOR_FEATURE_TERMINAL_1 "Terminal 1"
+    #define VIGRA_SKELETON_VECTOR_FEATURE_TERMINAL_2 "Terminal 2"
+
+    if(list_features_only)
+    {
+
+        python::list res;
+        res.append(XSTR(VIGRA_SKELETON_FEATURE_DIAMETER));
+        res.append(XSTR(VIGRA_SKELETON_FEATURE_EUCLIDEAN_DIAMETER));
+        res.append(XSTR(VIGRA_SKELETON_FEATURE_TOTAL_LENGTH));
+        res.append(XSTR(VIGRA_SKELETON_FEATURE_AVERAGE_LENGTH));
+        res.append(XSTR(VIGRA_SKELETON_FEATURE_BRANCH_COUNT));
+        res.append(XSTR(VIGRA_SKELETON_FEATURE_HOLE_COUNT));
+        res.append(XSTR(VIGRA_SKELETON_VECTOR_FEATURE_CENTER));
+        res.append(XSTR(VIGRA_SKELETON_VECTOR_FEATURE_TERMINAL_1));
+        res.append(XSTR(VIGRA_SKELETON_VECTOR_FEATURE_TERMINAL_2));
+
+        return res;
+    }
+
+    TinyVector<npy_intp, N> permutation = labels.template permuteLikewise<N>();
+    ArrayVector<SkeletonFeatures> features;
+
+    {
+        PyAllowThreads _pythread;
+        
+        extractSkeletonFeatures(labels, features, 
+                                SkeletonOptions().pruneSalienceRelative(pruning_threshold));
+    }
+    
+    int size = features.size();
+    python::dict res;
+    
+    #define VIGRA_SKELETON_FEATURE(TYPE, NAME, ATTRIBUTE) \
+    { \
+        NumpyArray<1, TYPE> array((Shape1(size))); \
+        for(int k=0; k<size; ++k) \
+        { \
+            array(k) = features[k].ATTRIBUTE; \
+        } \
+        res[XSTR(NAME)] = array; \
+    }
+    
+    VIGRA_SKELETON_FEATURE(double, VIGRA_SKELETON_FEATURE_DIAMETER, diameter)
+    VIGRA_SKELETON_FEATURE(double, VIGRA_SKELETON_FEATURE_EUCLIDEAN_DIAMETER, euclidean_diameter)
+    VIGRA_SKELETON_FEATURE(double, VIGRA_SKELETON_FEATURE_TOTAL_LENGTH, total_length)
+    VIGRA_SKELETON_FEATURE(double, VIGRA_SKELETON_FEATURE_AVERAGE_LENGTH, average_length)
+    VIGRA_SKELETON_FEATURE(npy_uint32, VIGRA_SKELETON_FEATURE_BRANCH_COUNT, branch_count)
+    VIGRA_SKELETON_FEATURE(npy_uint32,VIGRA_SKELETON_FEATURE_HOLE_COUNT, hole_count)
+    
+    #undef VIGRA_SKELETON_FEATURE
+        
+    #define VIGRA_SKELETON_VECTOR_FEATURE(NAME, ATTRIBUTE) \
+    { \
+        NumpyArray<2, double> array(Shape2(size, N)); \
+        for(int k=0; k<size; ++k) \
+        { \
+            for(int j=0; j<N; ++j) \
+                array(k, permutation[j]) = features[k].ATTRIBUTE[j]; \
+        } \
+        res[XSTR(NAME)] = array; \
+    }
+    
+    VIGRA_SKELETON_VECTOR_FEATURE(VIGRA_SKELETON_VECTOR_FEATURE_CENTER, center)
+    VIGRA_SKELETON_VECTOR_FEATURE(VIGRA_SKELETON_VECTOR_FEATURE_TERMINAL_1, terminal1)
+    VIGRA_SKELETON_VECTOR_FEATURE(VIGRA_SKELETON_VECTOR_FEATURE_TERMINAL_2, terminal2)
+    
+    #undef VIGRA_SKELETON_VECTOR_FEATURE
+
+    return res;
+}
+
 void defineSinglebandRegionAccumulators()
 {
     using namespace python;
@@ -60,6 +354,63 @@ void defineSinglebandRegionAccumulators()
                    > ScalarRegionAccumulators;
     definePythonAccumulatorArraySingleband<2, float, ScalarRegionAccumulators>();
     definePythonAccumulatorArraySingleband<3, float, ScalarRegionAccumulators>();
+    
+    def("extractConvexHullFeatures", 
+         registerConverters(&extractConvexHullFeatures<2, npy_uint32>),
+          (arg("labels"),
+           arg("ignoreLabel")=python::object(),
+           arg("list_features_only")=false),
+            "\nExtract convex hull features for each region of a labeled 2D image\n"
+            "(with dtype=numpy.uint32) and return a dictionary holding the\n"
+            "resulting feature arrays. Argument 'ignoreLabel' can be used to specify\n"
+            "an optional background label that is to be skipped. Note that the\n"
+            "convex hull itself and its features are computed from the interpixel\n"
+            "contour around each region. In the following, 'convexity defects'\n"
+            "are defined as the connected components of the set difference\n"
+            "between the convex hull and the original region.\n\n"
+            "The result dictionary holds the following keys:\n\n"
+            "   - 'InputCount':  the number of pixels in the original region\n\n"
+            "   - 'InputPerimeter':  the perimeter of the original interpixel contour\n\n"
+            "   - 'InputArea':  the areay enclosed by the original interpixel contour\n\n"
+            "   - 'InputCenter':  the centroid of the original interpixel contour polygon\n\n"
+            "   - 'Perimeter':  the perimeter of the convex hull polygon\n\n"
+            "   - 'Area':  the area enclosed by the convex hull polygon\n\n"
+            "   - 'Center':  the centroid of the convex hull polygon\n\n"
+            "   - 'Rugosity':  ratio between original perimeter and hull perimeter (>= 1)\n\n"
+            "   - 'Convexity':  the ratio between hull area and original area (<= 1)\n\n"
+            "   - 'DefectCount':  the number of convexity defects\n\n"
+            "   - 'DefectCenter':  the combined centroid of the defects\n\n"
+            "   - 'MeanDefectDisplacement':  mean distance between the centroids of the\n"
+            "                                original object and the centroids of the defects,\n"
+            "                                weighted by defect area\n\n"
+            "   - 'DefectAreaList':  the area of the three largest convexity defects\n\n"
+            "   - 'DefectAreaMean':  mean of the convexity defect areas\n\n"
+            "   - 'DefectAreaVariance':  variance of the convexity defect areas\n\n"
+            "   - 'DefectAreaSkewness':  skewness of the convexity defect areas\n\n"
+            "   - 'DefectAreaKurtosis':  kurtosis of the convexity defect areas\n\n"
+            "   - 'Polygon':  the convex hull polygon\n\n");
+    
+    def("extractSkeletonFeatures", 
+         registerConverters(&pyExtractSkeletonFeatures<2, npy_uint32>),
+         (arg("labels"),
+          arg("pruning_threshold")=0.2,
+          arg("list_features_only")=false),
+            "\nExtract skeleton features for each region of a labeled 2D image\n"
+            "(with dtype=numpy.uint32) and return a dictionary holding the\n"
+            "resulting feature arrays. Label 0 is always considered background\n"
+            "and therefore skipped. The skeleton is computed using mode\n"
+            "'PruneSalienceRelative' with the given 'pruning_threshold'.\n\n"
+            "The result dictionary holds the following keys:\n\n"
+            "   - 'Diameter':  the longest path between two terminals of the skeleton\n\n"
+            "   - 'Center':  the center point of this path\n\n"
+            "   - 'Terminal1':  first end point of this path\n\n"
+            "   - 'Terminal2':  second end point of this path\n\n"
+            "   - 'EuclideanDiameter':  the Euclidean distance between Terminal1 and Terminal2\n\n"
+            "   - 'TotalLength':  total length of the (pruned) skeleton\n\n"
+            "   - 'AverageLength':  the average length of the skeleton's branches after pruning\n\n"
+            "   - 'BranchCount':  the number of skeleton branches (i.e. end points after pruning)\n\n"
+            "   - 'HoleCount':  the number of cycles in the skeleton\n"
+            "                  (i.e. the number of cavities in the region)\n\n");
 }
 
 } // namespace vigra
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/vigranumpy/src/core/adjacencyListGraph.cxx
similarity index 54%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to vigranumpy/src/core/adjacencyListGraph.cxx
index 37a8c81..7d12133 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/vigranumpy/src/core/adjacencyListGraph.cxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*                 Copyright 2011 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,71 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpygraphs_PyArray_API
+#define NO_IMPORT_ARRAY
+
+
+
+#include "export_graph_visitor.hxx"
+#include "export_graph_rag_visitor.hxx"
+#include "export_graph_algorithm_visitor.hxx"
+#include "export_graph_shortest_path_visitor.hxx"
+#include "export_graph_hierarchical_clustering_visitor.hxx"
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
 #include <vigra/numpy_array.hxx>
 #include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
-
+#include <vigra/adjacency_list_graph.hxx>
+#include <vigra/python_graph.hxx>
 namespace python = boost::python;
 
-namespace vigra {
+namespace vigra{
+
+
+
+    NumpyAnyArray pySerializeAdjacencyListGraph(
+        const AdjacencyListGraph & graph,
+        NumpyArray<1, UInt32> serialization 
+    ){
+        serialization.reshapeIfEmpty( NumpyArray<1, UInt32>::difference_type(graph.serializationSize()));
+        graph.serialize(serialization.begin());
+        return serialization;
+    }
+
+
+    void pyDeserializeAdjacencyListGraph(
+        AdjacencyListGraph & graph,
+        const NumpyArray<1, UInt32> & serialization 
+    ){
+        graph.clear();
+        graph.deserialize(serialization.begin(),serialization.end());
+    }
 
-UInt32 pychecksum(python::str const & s)
-{
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+    void defineAdjacencyListGraph(){
+        
+        typedef AdjacencyListGraph  Graph;
+        // define graph itself
+        const std::string clsName = "AdjacencyListGraph";
+        python::class_<Graph>(clsName.c_str(),"undirected adjacency list graph",
+            python::init< const size_t,const size_t >( )
+        )
+        .def(LemonUndirectedGraphCoreVisitor<Graph>(clsName))
+        .def(LemonUndirectedGraphAddItemsVisitor<Graph>(clsName))
+        .def(LemonGraphAlgorithmVisitor<Graph>(clsName))
+        .def(LemonGraphShortestPathVisitor<Graph>(clsName))
+        .def(LemonGraphRagVisitor<Graph>(clsName))
+        .def(LemonGraphHierachicalClusteringVisitor<Graph>(clsName))
 
-} // namespace vigra
+        // serialization helper
+        .def("serializationSize",&Graph::serializationSize, "number of integers needed to serialize graph")
+        .def("serialize",registerConverters(&pySerializeAdjacencyListGraph),
+            (
+                python::arg("serialization")=python::object()
+            )
+        )
+        .def("deserialize",registerConverters(&pyDeserializeAdjacencyListGraph) )
+        ;
+    }
+} 
 
-using namespace boost::python;
-using namespace vigra;
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
-{
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
-}
diff --git a/vigranumpy/src/core/axistags.cxx b/vigranumpy/src/core/axistags.cxx
index 1afbe33..a07f789 100644
--- a/vigranumpy/src/core/axistags.cxx
+++ b/vigranumpy/src/core/axistags.cxx
@@ -118,6 +118,16 @@ AxisInfo AxisInfo_z()
     return AxisInfo::z();
 }
 
+AxisInfo AxisInfo_n()
+{
+    return AxisInfo::n();
+}
+
+AxisInfo AxisInfo_e()
+{
+    return AxisInfo::e();
+}
+
 AxisInfo AxisInfo_t()
 {
     return AxisInfo::t();
@@ -188,6 +198,10 @@ AxisTags_create(python::object i1, python::object i2,
     {
         res = VIGRA_UNIQUE_PTR<AxisTags>(new AxisTags(tags()));
     }
+    else if(PyString_Check(i1.ptr()))
+    {
+        res = VIGRA_UNIQUE_PTR<AxisTags>(new AxisTags(python::extract<std::string>(i1)()));
+    }
     else if(PySequence_Check(i1.ptr()))
     {
         int size = len(i1);
@@ -298,6 +312,27 @@ std::string AxisTags_str(AxisTags const & axistags)
     return res;
 }
 
+python::list AxisTags_keys(AxisTags const & axistags)
+{
+    python::list res;
+    for(unsigned int k=0; k<axistags.size(); ++k)
+        res.append(axistags.get(k).key());
+    return res;
+}
+
+python::list AxisTags_values(AxisTags const & axistags)
+{
+    python::list res;
+    for(unsigned int k=0; k<axistags.size(); ++k)
+        res.append(axistags.get(k));
+    return res;
+}
+
+bool AxisTags_contains(AxisTags const & axistags, AxisInfo const & axisinfo)
+{
+    return axistags.contains(axisinfo.key());
+}
+
 python::object
 AxisTags_permutationToNormalOrder(AxisTags const & axistags)
 {
@@ -480,6 +515,7 @@ void defineAxisTags()
          ":class:`~vigra.AxisInfo` object. Possible values:\n\n"
          "   ``AxisType.Channels:``\n      a channel axis\n"
          "   ``AxisType.Space:``\n      a spatial axis\n"
+         "   ``AxisType.Edge:``\n      an edge axis\n"
          "   ``AxisType.Angle:``\n      an axis encoding angles (e.g. polar coordinates)\n"
          "   ``AxisType.Time:``\n      a temporal axis\n"
          "   ``AxisType.Frequency:``\n      an axis in the Fourier domain\n"
@@ -491,6 +527,7 @@ void defineAxisTags()
         .value("UnknownAxisType", AxisInfo::UnknownAxisType)
         .value("Channels", AxisInfo::Channels)
         .value("Space", AxisInfo::Space)
+        .value("Edge", AxisInfo::Edge)
         .value("Angle", AxisInfo::Angle)
         .value("Time", AxisInfo::Time)
         .value("Frequency", AxisInfo::Frequency)
@@ -522,6 +559,10 @@ void defineAxisTags()
          "        Factory for an axisinfo object describing the 'y' (spatial) axis.\n"
          "   ``AxisInfo.z`` or ``AxisInfo.z(resolution=0.0, description='')``:\n"
          "        Factory for an axisinfo object describing the 'z' (spatial) axis.\n"
+         "   ``AxisInfo.z`` or ``AxisInfo.n(resolution=0.0, description='')``:\n"
+         "        Factory for an axisinfo object describing the 'n' (spatial) axis.\n"
+         "   ``AxisInfo.e`` or ``AxisInfo.e(resolution=0.0, description='')``:\n"
+         "        Factory for an axisinfo object describing the 'e' (edge) axis.\n"
          "   ``AxisInfo.t`` or ``AxisInfo.t(resolution=0.0, description='')``:\n"
          "        Factory for an axisinfo object describing the 't' (time) axis.\n"
          "   ``AxisInfo.fx`` or ``AxisInfo.fx(resolution=0.0, description='')``:\n"
@@ -566,8 +607,11 @@ void defineAxisTags()
         .def("toFrequencyDomain", &AxisInfo::toFrequencyDomain, (arg("size") = 0, arg("sign") = 1))
         .def("fromFrequencyDomain", &AxisInfo::fromFrequencyDomain, (arg("size") = 0))
         .def("isSpatial", &AxisInfo::isSpatial, 
-             "\naxisinfo.isSSpactial() yields True when :attr:`~vigra.AxisInfo.typeFlags` "
+             "\naxisinfo.isSpactial() yields True when :attr:`~vigra.AxisInfo.typeFlags` "
              "contains AxisType.Space\n")
+        .def("isEdge", &AxisInfo::isEdge, 
+             "\naxisinfo.isEdge() yields True when :attr:`~vigra.AxisInfo.typeFlags` "
+             "contains AxisType.Edge\n")
         .def("isTemporal", &AxisInfo::isTemporal, 
              "\naxisinfo.isTemporal() yields True when :attr:`~vigra.AxisInfo.typeFlags` "
              "contains AxisType.Time\n")
@@ -599,6 +643,8 @@ void defineAxisTags()
         .add_static_property("x", &AxisInfo_x)
         .add_static_property("y", &AxisInfo_y)
         .add_static_property("z", &AxisInfo_z)
+        .add_static_property("n", &AxisInfo_n)
+        .add_static_property("e", &AxisInfo_e)
         .add_static_property("t", &AxisInfo_t)
         .add_static_property("fx", &AxisInfo_fx)
         .add_static_property("fy", &AxisInfo_fy)
@@ -648,11 +694,15 @@ void defineAxisTags()
             (void (AxisTags::*)(std::string const &, AxisInfo const &))&AxisTags::set)
         .def("__delitem__", (void (AxisTags::*)(int))&AxisTags::dropAxis)
         .def("__delitem__", (void (AxisTags::*)(std::string const &))&AxisTags::dropAxis)
+        .def("__contains__", &AxisTags_contains)
+        .def("__contains__", &AxisTags::contains)
         .def("insert", &AxisTags::insert)
         .def("append", &AxisTags::push_back)
         .def("dropChannelAxis", &AxisTags::dropChannelAxis)
         .def("insertChannelAxis", &AxisTags_insertChannelAxis)
         .def("swapaxes", &AxisTags::swapaxes)
+        .def("keys", &AxisTags_keys)
+        .def("values", &AxisTags_values)
         
         // NOTE: in contrast to arrays, AxisTags::transpose() works
         //       in-place, i.e. changes 'self'
diff --git a/vigranumpy/src/core/blockwise.cxx b/vigranumpy/src/core/blockwise.cxx
new file mode 100644
index 0000000..4e20c52
--- /dev/null
+++ b/vigranumpy/src/core/blockwise.cxx
@@ -0,0 +1,300 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2011 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpyblockwise_PyArray_API
+//#define NO_IMPORT_ARRAY
+
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+
+#include <vigra/multi_blocking.hxx>
+#include <vigra/multi_blockwise.hxx>
+
+namespace python = boost::python;
+
+
+
+
+namespace vigra{
+
+    template<unsigned int DIM, class T_IN, class T_OUT>
+    NumpyAnyArray pyBlockwiseGaussianSmoothMultiArray(
+        const NumpyArray<DIM, T_IN> &  source,
+        const BlockwiseConvolutionOptions<DIM>  & opt,
+        NumpyArray<DIM, T_OUT>  dest
+    ){
+        dest.reshapeIfEmpty(source.taggedShape());
+        gaussianSmoothMultiArray(source, dest, opt);
+        return dest;
+    }
+
+    template<unsigned int DIM, class T_IN, class T_OUT>
+    NumpyAnyArray pyBlockwiseGaussianGradientMagnitudeMultiArray(
+        const NumpyArray<DIM, T_IN> &  source,
+        const BlockwiseConvolutionOptions<DIM>  & opt,
+        NumpyArray<DIM, T_OUT>  dest
+    ){
+        dest.reshapeIfEmpty(source.taggedShape());
+        gaussianGradientMagnitudeMultiArray(source, dest, opt);
+        return dest;
+    }
+
+    template<unsigned int DIM, class T_IN, class T_OUT>
+    NumpyAnyArray pyBlockwiseGaussianGradientMultiArray(
+        const NumpyArray<DIM, T_IN> &  source,
+        const BlockwiseConvolutionOptions<DIM>  & opt,
+        NumpyArray<DIM, T_OUT>  dest
+    ){
+        dest.reshapeIfEmpty(source.taggedShape());
+        gaussianGradientMultiArray(source, dest, opt);
+        return dest;
+    }
+
+    template<unsigned int DIM, class T_IN, class T_OUT>
+    NumpyAnyArray pyBlockwiseHessianOfGaussianEigenvaluesMultiArray(
+        const NumpyArray<DIM, T_IN> &  source,
+        const BlockwiseConvolutionOptions<DIM>  & opt,
+        NumpyArray<DIM, T_OUT>  dest
+    ){
+        dest.reshapeIfEmpty(source.taggedShape());
+        hessianOfGaussianEigenvaluesMultiArray(source, dest, opt);
+        return dest;
+    }
+
+    template<unsigned int DIM, class T_IN, class T_OUT>
+    NumpyAnyArray pyBlockwiseHessianOfGaussianFirstEigenvalueMultiArray(
+        const NumpyArray<DIM, T_IN> &  source,
+        const BlockwiseConvolutionOptions<DIM>  & opt,
+        NumpyArray<DIM, T_OUT>  dest
+    ){
+        dest.reshapeIfEmpty(source.taggedShape());
+        hessianOfGaussianFirstEigenvalueMultiArray(source, dest, opt);
+        return dest;
+    }
+
+    template<unsigned int DIM, class T_IN, class T_OUT>
+    NumpyAnyArray pyBlockwiseHessianOfGaussianLastEigenvalueMultiArray(
+        const NumpyArray<DIM, T_IN> &  source,
+        const BlockwiseConvolutionOptions<DIM>  & opt,
+        NumpyArray<DIM, T_OUT>  dest
+    ){
+        dest.reshapeIfEmpty(source.taggedShape());
+        hessianOfGaussianLastEigenvalueMultiArray(source, dest, opt);
+        return dest;
+    }
+
+
+
+
+    template<unsigned int DIM, class T_IN>
+    void defineBlockwiseFilters(){
+        //typedef BlockwiseConvolutionOptions<DIM> Opt;
+
+        python::def("_gaussianSmooth",registerConverters(&pyBlockwiseGaussianSmoothMultiArray<DIM, T_IN, float>),
+            (
+                python::arg("source"),
+                python::arg("options"),
+                python::arg("out") = python::object()
+            )
+        );
+
+        python::def("_gaussianGradientMagnitude",registerConverters(&pyBlockwiseGaussianGradientMagnitudeMultiArray<DIM, T_IN, float>),
+            (
+                python::arg("source"),
+                python::arg("options"),
+                python::arg("out") = python::object()
+            )
+        );
+
+        python::def("_gaussianGradient",registerConverters(&pyBlockwiseGaussianGradientMultiArray<DIM, T_IN, TinyVector<float, DIM> >),
+            (
+                python::arg("source"),
+                python::arg("options"),
+                python::arg("out") = python::object()
+            )
+        );
+
+        python::def("_hessianOfGaussianEigenvalues",registerConverters(&pyBlockwiseHessianOfGaussianEigenvaluesMultiArray<DIM, T_IN, vigra::TinyVector<float, DIM> >),
+            (
+                python::arg("source"),
+                python::arg("options"),
+                python::arg("out") = python::object()
+            )
+        );
+        python::def("_hessianOfGaussianFirstEigenvalue",registerConverters(&pyBlockwiseHessianOfGaussianFirstEigenvalueMultiArray<DIM, T_IN, float>),
+            (
+                python::arg("source"),
+                python::arg("options"),
+                python::arg("out") = python::object()
+            )
+        );
+        python::def("_hessianOfGaussianLastEigenvalue",registerConverters(&pyBlockwiseHessianOfGaussianLastEigenvalueMultiArray<DIM, T_IN, float>),
+            (
+                python::arg("source"),
+                python::arg("options"),
+                python::arg("out") = python::object()
+            )
+        );
+    }
+
+    template<class  MB>
+    NumpyAnyArray intersectingBlocks(
+        const MB & mb,
+        const typename MB::Shape begin,
+        const typename MB::Shape end,
+        NumpyArray<1, UInt32> out
+    ){
+        std::vector<UInt32> outVec = mb.intersectingBlocks(begin,end);
+        out.reshapeIfEmpty(typename NumpyArray<1,UInt32>::difference_type(outVec.size()));
+        std::copy(outVec.begin(),outVec.end(), out.begin());
+        return out;
+    }
+
+    template<class  MB>
+    python::tuple getBlock(
+        const MB & mb,
+        const UInt32 blockIndex
+    ){
+        const auto iter = mb.blockBegin();
+        const auto & block = iter[blockIndex];
+        auto tl = block.begin();
+        auto br = block.end();
+        return python::make_tuple(tl,br);
+    }
+
+
+    template<class  MB>
+    python::tuple getBlock2(
+        const MB & mb,
+        const typename  MB::BlockDesc desc
+    ){
+        const auto block = mb.blockDescToBlock(desc);
+        auto tl = block.begin();
+        auto br = block.end();
+        return python::make_tuple(tl,br);
+    }
+
+    template<class BLOCK>
+    typename BLOCK::Vector
+    blockBegin(const BLOCK & b){
+        return b.begin();
+    }
+    template<class BLOCK>
+    typename BLOCK::Vector
+    blockEnd(const BLOCK & b){
+        return b.end();
+    }
+
+    template<class BLOCK>
+    typename BLOCK::Vector
+    blockShape(const BLOCK & b){
+        return b.size();
+    }
+
+
+    template<unsigned int DIM>
+    void defineMultiBlocking(const std::string & clsName){
+
+        typedef MultiBlocking<DIM> Blocking;
+        typedef typename Blocking::Shape Shape;
+        typedef typename Blocking::Block Block;
+
+        python::class_<Blocking>(clsName.c_str(), python::init<const Shape &, const Shape &>())
+            .def("intersectingBlocks",registerConverters(&intersectingBlocks<Blocking>),
+                (
+                    python::arg("begin"),
+                    python::arg("end"),
+                    python::arg("out") = python::object()
+                )
+            )
+            .def("__len__", &Blocking::numBlocks)
+            .def("__getitem__", &getBlock<Blocking>)
+            .def("__getitem__", &getBlock2<Blocking>)
+        ;
+
+        const std::string blockName = clsName + std::string("Block");
+
+        python::class_<Block>(blockName.c_str())
+            .add_property("begin",&blockBegin<Block>)
+            .add_property("end",  &blockEnd<Block>)
+            .add_property("shape",&blockShape<Block>)
+        ;
+    }
+
+
+
+    template<unsigned int DIM>
+    void defineBlockwiseConvolutionOptions(const std::string & clsName){
+
+        typedef BlockwiseConvolutionOptions<DIM> Opt;
+        python::class_<Opt>(clsName.c_str(), python::init<>())
+        .add_property("stdDev", &Opt::getStdDev, &Opt::setStdDev)
+        //.add_property("scale", &Opt::getScale, &Opt::setScale)
+        .add_property("innerScale", &Opt::getInnerScale,  &Opt::setInnerScale)
+        .add_property("outerScale", &Opt::getOuterScale,  &Opt::setOuterScale)
+        .add_property("blockShape", &Opt::readBlockShape, &Opt::setBlockShape)
+        .add_property("numThreads", &Opt::getNumThreads,  &Opt::setNumThreads)
+        ;
+    }
+
+
+
+}
+using namespace vigra;
+using namespace boost::python;
+
+
+
+
+
+
+
+BOOST_PYTHON_MODULE_INIT(blockwise)
+{
+    import_vigranumpy();
+
+    python::docstring_options doc_options(true, true, false);
+
+    defineMultiBlocking<2>("Blocking2D");
+    defineMultiBlocking<3>("Blocking3D");
+
+    defineBlockwiseConvolutionOptions<2>("BlockwiseConvolutionOptions2D");
+    defineBlockwiseConvolutionOptions<3>("BlockwiseConvolutionOptions3D");
+    defineBlockwiseConvolutionOptions<4>("BlockwiseConvolutionOptions4D");
+    defineBlockwiseConvolutionOptions<5>("BlockwiseConvolutionOptions4D");
+
+    defineBlockwiseFilters<2, float>();
+    defineBlockwiseFilters<3, float>();
+}
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/vigranumpy/src/core/clustering.cxx
similarity index 79%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to vigranumpy/src/core/clustering.cxx
index 37a8c81..3383ed2 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/vigranumpy/src/core/clustering.cxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*                 Copyright 2011 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,35 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpyclustering_PyArray_API
+//#define NO_IMPORT_ARRAY
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
 #include <boost/python.hpp>
+
 #include <vigra/numpy_array.hxx>
 #include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
-
+#include "vigra/merge_graph/merge_graph.hxx"
+#include "vigra/merge_graph/maps/multi_array_map.hxx"
+#include "vigra/merge_graph/maps/python_map.hxx"
+#include <vigra/merge_graph/min_indexed_pq.hxx>
 namespace python = boost::python;
 
-namespace vigra {
-
-UInt32 pychecksum(python::str const & s)
+namespace vigra
 {
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+void defineMergeGraphMaps();
+void defineMergeGraph();
+void defineMinIndexedPq();
 
 } // namespace vigra
 
-using namespace boost::python;
 using namespace vigra;
+using namespace boost::python;
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
+BOOST_PYTHON_MODULE_INIT(clustering)
 {
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
+    import_vigranumpy();
+    defineMinIndexedPq();
+    defineMergeGraph();
+    defineMergeGraphMaps();
 }
diff --git a/vigranumpy/src/core/colors.cxx b/vigranumpy/src/core/colors.cxx
index 9541ab4..9bfc3d1 100644
--- a/vigranumpy/src/core/colors.cxx
+++ b/vigranumpy/src/core/colors.cxx
@@ -275,6 +275,17 @@ pythonLinearRangeMapping(NumpyArray<N, Multiband<SrcPixelType> > image,
     return res;
 }
 
+template < class SrcPixelType>
+inline NumpyAnyArray
+pythonLinearRangeMapping2D(NumpyArray<3, Multiband<SrcPixelType> > image,
+                           python::object oldRange,
+                           python::object newRange,
+                           NumpyArray<3, Multiband<UInt8> > res)
+{
+    return pythonLinearRangeMapping(image, oldRange, newRange, res);
+}
+
+VIGRA_PYTHON_MULTITYPE_FUNCTOR(pyLinearRangeMapping2D, pythonLinearRangeMapping2D)
 
 template < class PixelType, unsigned int N, class Functor >
 NumpyAnyArray
@@ -316,7 +327,9 @@ NumpyAnyArray pythonApplyColortable(const NumpyArray<2, Singleband<T> >& valueIm
                        "pythonApplyColortable: shape of res is wrong");
     
     const unsigned int N = colortable.shape(0);
-   
+
+    bool startsWithTransparent = (colortable(0,3) == 0);
+
     for(MultiArrayIndex c=0; c<colortable.shape(1); ++c)
     {
         MultiArrayView<2, UInt8>::iterator channelIter = res.bind<2>(c).begin();
@@ -326,7 +339,24 @@ NumpyAnyArray pythonApplyColortable(const NumpyArray<2, Singleband<T> >& valueIm
         
         for(typename InputType::const_iterator v = valueImage.begin(); v != valueImage.end(); ++v, ++channelIter)
         {
-            const_cast<UInt8 &>(*channelIter) = ctable[*v % N];
+            if (*v == 0)
+            {
+                *channelIter = ctable[0];
+            }
+            else if (startsWithTransparent)
+            {
+                // Special behavior: If the colortable has too few values for the image,
+                // we simply repeat the table for the higher indexes (see below).
+                // BUT:
+                // It's common for the colortable to start with a transparent value for "background".
+                // In that case, we only repeat the remaining values in the colortable (don't repeat the transparent color)
+                *channelIter = ctable[((*v-1) % (N-1))+1];
+            }
+            else
+            {
+                // Use % to repeat the colortable if there aren't enough values in the colortable.
+                *channelIter = ctable[*v % N];
+            }
         }
     }
     
@@ -352,7 +382,7 @@ void pythonGray2QImage_ARGB32Premultiplied(
     TmpType pixelF;
     
     TmpType normalizeLow, normalizeHigh; 
-    if(normalize != boost::python::object())
+    if(normalize.pyObject() != Py_None)
     {
         vigra_precondition(normalize.shape(0) == 2,
             "gray2qimage_ARGB32Premultiplied(): normalize.shape[0] == 2 required.");
@@ -466,16 +496,18 @@ void defineColors()
 
     docstring_options doc_options(true, true, false);
 
-    multidef("applyColortable", pyApplyColortable<vigra::UInt8, vigra::Int16, vigra::UInt16, vigra::Int32, vigra::UInt32>(),
+    multidef("applyColortable", pyApplyColortable<vigra::Int8, vigra::UInt8, vigra::Int16, vigra::UInt16, vigra::Int32, vigra::UInt32>(),
         (arg("valueImage"), 
         arg("colortable"),
         arg("out")=python::object()), 
         "Applies a colortable to the given 2D valueImage.\n\n"
-        "Colortable must have 4 columns, each row represents a color (for example, RGBA).\n"
-        "Values in valueImage are first taken module the length of the colortable.\n\n"
+        "Colortable must have 4 columns, each row represents a color (for example, RGBA). \n"
+        "Values in valueImage are first taken modulo the length of the colortable. \n"
+        "In the special case where the first color in the table is transparent, that value "
+        "is NOT repeated for values outside the colortable length.\n\n"
         "Returns: uint8 image with 4 channels\n");
     
-    multidef("gray2qimage_ARGB32Premultiplied", pyGray2QImage_ARGB32Premultiplied<vigra::UInt8, vigra::Int16, vigra::UInt16, vigra::Int32, vigra::UInt32, float, double>(),
+    multidef("gray2qimage_ARGB32Premultiplied", pyGray2QImage_ARGB32Premultiplied<vigra::Int8, vigra::UInt8, vigra::Int16, vigra::UInt16, vigra::Int32, vigra::UInt32, float, double>(),
         (arg("image"), 
         arg("qimage"),
         arg("normalize")=python::object()), 
@@ -486,7 +518,7 @@ void defineColors()
         "normalize = numpy.asarray([10, 217], dtype=image.dtype)\n"
         "vigra.colors.gray2qimage_ARGB32Premultiplied(a, qimage2ndarray.byte_view(qimg), normalize)\n");
     
-    multidef("alphamodulated2qimage_ARGB32Premultiplied", pyAlphaModulated2QImage_ARGB32Premultiplied<vigra::UInt8, vigra::Int16, vigra::UInt16, vigra::Int32, vigra::UInt32, float, double>(),
+    multidef("alphamodulated2qimage_ARGB32Premultiplied", pyAlphaModulated2QImage_ARGB32Premultiplied<vigra::Int8, vigra::UInt8, vigra::Int16, vigra::UInt16, vigra::Int32, vigra::UInt32, float, double>(),
         (arg("image"), 
         arg("qimage"),
         arg("tintColor"),
@@ -557,8 +589,7 @@ void defineColors()
          (arg("volume"), arg("gamma"), arg("range")=make_tuple(0.0, 255.0), arg("out")=object()),
          "Likewise for a 3D scalar or multiband volume.\n");
 
-    def("linearRangeMapping",
-         registerConverters(&pythonLinearRangeMapping<float, UInt8, 3>),
+    multidef("linearRangeMapping", pyLinearRangeMapping2D<vigra::Int8, vigra::UInt8, vigra::Int16, vigra::UInt16, vigra::Int32, vigra::UInt32, float, double>(),
          (arg("image"), arg("oldRange")="auto", arg("newRange")=make_tuple(0.0, 255.0), arg("out")=object()),
         "Convert the intensity range of a 2D scalar or multiband image. The function applies a linear transformation "
         "to the intensities such that the value oldRange[0] is mapped onto newRange[0], "
@@ -574,22 +605,22 @@ void defineColors()
         "\n"
         "   range = image.min(), image.max()\n\n"
         "If 'newRange' is None or \"\" or \"auto\", it is set to (0, 255.0). "
-        "If 'out' is explicitly passed, it must be a uin8 image.\n");
+        "If 'out' is explicitly passed, it must be a uint8 image.\n");
 
     def("linearRangeMapping",
          registerConverters(&pythonLinearRangeMapping<float, float, 3>),
          (arg("image"), arg("oldRange")="auto", arg("newRange")=make_tuple(0.0, 255.0), arg("out")=object()),
-         "Likewise, but 'out' is a float32 image.\n");
+         "Likewise, but #in' and 'out' are float32 images.\n");
 
     def("linearRangeMapping",
          registerConverters(&pythonLinearRangeMapping<float, UInt8, 4>),
          (arg("volume"), arg("oldRange")="auto", arg("newRange")=make_tuple(0.0, 255.0), arg("out")=object()),
-         "Likewise for a 3D scalar or multiband volume, when 'out' is a unit8 volume.\n");
+         "Likewise for a 3D scalar or multiband volume, when 'in' is a float32 and 'out' a unit8 volume.\n");
 
     def("linearRangeMapping",
          registerConverters(&pythonLinearRangeMapping<float, float, 4>),
          (arg("volume"), arg("oldRange")="auto", arg("newRange")=make_tuple(0.0, 255.0), arg("out")=object()),
-         "Likewise, but 'out' is a float32 volume.\n");
+         "Likewise, but 'in' and 'out' are float32 volumes.\n");
 
 
     exportColorTransform(RGB2sRGB);
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/vigranumpy/src/core/construct_custodian_for.hpp
similarity index 60%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to vigranumpy/src/core/construct_custodian_for.hpp
index 37a8c81..d8543ba 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/vigranumpy/src/core/construct_custodian_for.hpp
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*                 Copyright 2014 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,62 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#ifndef VIGRA_CONSTRUCT_CUSTODIAN_FOR_HPP
+#define VIGRA_CONSTRUCT_CUSTODIAN_FOR_HPP
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
-#include <vigra/numpy_array.hxx>
-#include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
+#include <boost/version.hpp>
 
-namespace python = boost::python;
+#if BOOST_VERSION <= 105500
 
-namespace vigra {
+#include <boost/python/with_custodian_and_ward.hpp>
 
-UInt32 pychecksum(python::str const & s)
+namespace boost { namespace python { 
+
+template <std::size_t ward>
+struct construct_custodian_for : default_call_policies
 {
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
+    BOOST_STATIC_ASSERT(ward > 0);
+    
+    template <class ArgumentPackage>
+    static PyObject* postcall(ArgumentPackage const& args_, PyObject* result)
+    {
+        std::size_t arity_ = detail::arity(args_);
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
+        if (ward > arity_ )
+#else
+        // check if ward exceeds the arity
+        // (this weird formulation avoids "always false" warnings
+        // for arity_ = 0)
+        if ( (std::max<std::size_t>)(0, ward) > arity_ )
+#endif
+        {
+            PyErr_SetString(
+                PyExc_IndexError
+              , "boost::python::construct_custodian_for: argument index out of range"
+            );
+            return 0;
+        }
+        
+        PyObject* patient = detail::get_prev<ward>::execute(args_, result);
+        PyObject* nurse = detail::get_prev<1>::execute(args_.base);
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+        if (nurse == 0) return 0;
+    
+        result = default_call_policies::postcall(args_, result);
+        if (result == 0)
+            return 0;
+            
+        if (python::objects::make_nurse_and_patient(nurse, patient) == 0)
+        {
+            Py_XDECREF(result);
+            return 0;
+        }
+        return result;
+    }
+};
 
-} // namespace vigra
+}} // namespace boost::python
 
-using namespace boost::python;
-using namespace vigra;
+#  endif // BOOST_VERSION <= 105500
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
-{
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
-}
+#endif // VIGRA_CONSTRUCT_CUSTODIAN_FOR_HPP
diff --git a/vigranumpy/src/core/converters.cxx b/vigranumpy/src/core/converters.cxx
index 3677188..2ae2444 100644
--- a/vigranumpy/src/core/converters.cxx
+++ b/vigranumpy/src/core/converters.cxx
@@ -316,6 +316,9 @@ void registerNumpyShapeConvertersOneType()
     MultiArrayShapeConverter<5, T>();
     MultiArrayShapeConverter<6, T>();
     MultiArrayShapeConverter<7, T>();
+    MultiArrayShapeConverter<8, T>();
+    MultiArrayShapeConverter<9, T>();
+    MultiArrayShapeConverter<10, T>();
 }
 
 void registerNumpyShapeConvertersAllTypes()
@@ -324,6 +327,8 @@ void registerNumpyShapeConvertersAllTypes()
     registerNumpyShapeConvertersOneType<float>();
     registerNumpyShapeConvertersOneType<double>();
     registerNumpyShapeConvertersOneType<short>();
+    if(typeid(int) != typeid(MultiArrayIndex))
+        registerNumpyShapeConvertersOneType<int>();
     if(typeid(npy_intp) != typeid(MultiArrayIndex))
         MultiArrayShapeConverter<0, npy_intp>();
 }
diff --git a/vigranumpy/src/core/convolution.cxx b/vigranumpy/src/core/convolution.cxx
index 40f5908..1ebb185 100644
--- a/vigranumpy/src/core/convolution.cxx
+++ b/vigranumpy/src/core/convolution.cxx
@@ -55,7 +55,7 @@ namespace vigra
 {
 
 template < class VoxelType, unsigned int ndim >
-NumpyAnyArray 
+NumpyAnyArray
 pythonConvolveOneDimensionND(NumpyArray<ndim, Multiband<VoxelType> > array,
                              unsigned int dim,
                              Kernel const & kernel,
@@ -64,16 +64,16 @@ pythonConvolveOneDimensionND(NumpyArray<ndim, Multiband<VoxelType> > array,
     vigra_precondition(dim < ndim-1,
            "convolveOneDimension(): dim out of range.");
 
-    res.reshapeIfEmpty(array.taggedShape(), 
+    res.reshapeIfEmpty(array.taggedShape(),
             "convolveOneDimension(): Output array has wrong shape.");
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0;k<array.shape(ndim-1);++k)
         {
             MultiArrayView<ndim-1, VoxelType, StridedArrayTag> barray = array.bindOuter(k);
             MultiArrayView<ndim-1, VoxelType, StridedArrayTag> bres = res.bindOuter(k);
-            convolveMultiArrayOneDimension(srcMultiArrayRange(barray), 
+            convolveMultiArrayOneDimension(srcMultiArrayRange(barray),
                                            destMultiArray(bres), dim, kernel);
         }
     }
@@ -81,14 +81,14 @@ pythonConvolveOneDimensionND(NumpyArray<ndim, Multiband<VoxelType> > array,
 }
 
 template < class VoxelType, unsigned int ndim >
-NumpyAnyArray 
+NumpyAnyArray
 pythonSeparableConvolveND_1Kernel(NumpyArray<ndim, Multiband<VoxelType> > array,
                                   Kernel const & kernel,
                                   NumpyArray<ndim, Multiband<VoxelType> > res=python::object())
 {
-    res.reshapeIfEmpty(array.taggedShape(), 
+    res.reshapeIfEmpty(array.taggedShape(),
             "convolve(): Output array has wrong shape.");
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0;k<array.shape(ndim-1);++k)
@@ -102,36 +102,36 @@ pythonSeparableConvolveND_1Kernel(NumpyArray<ndim, Multiband<VoxelType> > array,
 }
 
 template < class VoxelType, unsigned int ndim >
-NumpyAnyArray 
+NumpyAnyArray
 pythonSeparableConvolveND_NKernels(NumpyArray<ndim, Multiband<VoxelType> > array,
                                    python::tuple pykernels,
                                    NumpyArray<ndim, Multiband<VoxelType> > res=python::object())
 {
     if(python::len(pykernels) == 1)
     {
-        return pythonSeparableConvolveND_1Kernel(array, 
+        return pythonSeparableConvolveND_1Kernel(array,
                     python::extract<Kernel1D<KernelValueType> const &>(pykernels[0]), res);
     }
-    
+
     vigra_precondition(python::len(pykernels) == ndim-1,
        "convolve(): Number of kernels must be 1 or equal to the number of spatial dimensions.");
-       
+
     ArrayVector<Kernel1D<KernelValueType> > kernels;
     for(unsigned int k=0; k < ndim-1; ++k)
         kernels.push_back(python::extract<Kernel1D<KernelValueType> const &>(pykernels[k]));
-        
+
     kernels = array.permuteLikewise(kernels);
 
-    res.reshapeIfEmpty(array.taggedShape(), 
+    res.reshapeIfEmpty(array.taggedShape(),
             "convolve(): Output array has wrong shape.");
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0; k < array.shape(ndim-1); ++k)
         {
             MultiArrayView<ndim-1, VoxelType, StridedArrayTag> barray = array.bindOuter(k);
             MultiArrayView<ndim-1, VoxelType, StridedArrayTag> bres = res.bindOuter(k);
-            separableConvolveMultiArray(srcMultiArrayRange(barray), 
+            separableConvolveMultiArray(srcMultiArrayRange(barray),
                                         destMultiArray(bres), kernels.begin());
         }
     }
@@ -139,12 +139,12 @@ pythonSeparableConvolveND_NKernels(NumpyArray<ndim, Multiband<VoxelType> > array
 }
 
 template <class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonConvolveImage(NumpyArray<3, Multiband<PixelType> > image,
-                    TwoDKernel const & kernel, 
+                    TwoDKernel const & kernel,
                     NumpyArray<3, Multiband<PixelType> > res = python::object())
 {
-    res.reshapeIfEmpty(image.taggedShape(), 
+    res.reshapeIfEmpty(image.taggedShape(),
             "convolve(): Output array has wrong shape.");
 
     {
@@ -161,10 +161,10 @@ pythonConvolveImage(NumpyArray<3, Multiband<PixelType> > image,
 }
 
 template <class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonNormalizedConvolveImage(NumpyArray<3, Multiband<PixelType> > image,
                               NumpyArray<3, Multiband<PixelType> > mask,
-                              TwoDKernel const & kernel, 
+                              TwoDKernel const & kernel,
                               NumpyArray<3, Multiband<PixelType> > res = python::object())
 {
     vigra_precondition(mask.shape(2)==1 || mask.shape(2)==image.shape(2),
@@ -172,7 +172,7 @@ pythonNormalizedConvolveImage(NumpyArray<3, Multiband<PixelType> > image,
     vigra_precondition(mask.shape(0)==image.shape(0) && mask.shape(1)==image.shape(1),
                "normalizedConvolveImage(): mask dimensions must be same as image dimensions");
 
-    res.reshapeIfEmpty(image.taggedShape(), 
+    res.reshapeIfEmpty(image.taggedShape(),
            "normalizedConvolveImage(): Output array has wrong shape.");
 
     {
@@ -190,38 +190,38 @@ pythonNormalizedConvolveImage(NumpyArray<3, Multiband<PixelType> > image,
 }
 
 template < class VoxelType, unsigned int ndim >
-NumpyAnyArray 
+NumpyAnyArray
 pythonGaussianSmoothing(NumpyArray<ndim, Multiband<VoxelType> > array,
                         python::object sigma,
                         NumpyArray<ndim, Multiband<VoxelType> > res=python::object(),
-                        python::object sigma_d = python::object(0.0), 
+                        python::object sigma_d = python::object(0.0),
                         python::object step_size = python::object(1.0),
-                        double window_size = 0.0, 
+                        double window_size = 0.0,
                         python::object roi = python::object())
 {
     static const unsigned int N = ndim - 1;
-    
+
     pythonScaleParam<N> params(sigma, sigma_d, step_size, "gaussianSmoothing");
-    
+
     params.permuteLikewise(array);
-    
+
     ConvolutionOptions<N> opt(params().filterWindowSize(window_size));
-    
+
     if(roi != python::object())
     {
         typedef typename MultiArrayShape<N>::type Shape;
         Shape start = array.permuteLikewise(python::extract<Shape>(roi[0])());
         Shape stop  = array.permuteLikewise(python::extract<Shape>(roi[1])());
         opt.subarray(start, stop);
-        res.reshapeIfEmpty(array.taggedShape().resize(stop-start), 
+        res.reshapeIfEmpty(array.taggedShape().resize(stop-start),
                 "gaussianSmoothing(): Output array has wrong shape.");
     }
     else
     {
-        res.reshapeIfEmpty(array.taggedShape(), 
+        res.reshapeIfEmpty(array.taggedShape(),
                 "gaussianSmoothing(): Output array has wrong shape.");
     }
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0; k<array.shape(ndim-1); ++k)
@@ -231,12 +231,12 @@ pythonGaussianSmoothing(NumpyArray<ndim, Multiband<VoxelType> > array,
             gaussianSmoothMultiArray(srcMultiArrayRange(barray), destMultiArray(bres), opt);
         }
     }
-    
+
     return res;
 }
 
 template < class VoxelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonRecursiveGaussian(NumpyArray<3, Multiband<VoxelType> > image,
                         python::tuple sigmas,
                         NumpyArray<3, Multiband<VoxelType> > res=python::object())
@@ -247,19 +247,19 @@ pythonRecursiveGaussian(NumpyArray<3, Multiband<VoxelType> > image,
     unsigned int sigmaCount = python::len(sigmas);
     vigra_precondition(sigmaCount == 1 || sigmaCount == ndim-1,
        "recursiveGaussianSmoothing(): Number of kernels must be 1 or equal to the number of spatial dimensions.");
-       
+
     ArrayVector<double> scales;
     for(unsigned int k=0; k < sigmaCount; ++k)
     {
-        scales.push_back(python::extract<double>(sigmas[k]));        
+        scales.push_back(python::extract<double>(sigmas[k]));
     }
     for(unsigned int k=sigmaCount; k < ndim-1; ++k)
     {
         scales.push_back(scales.back());
     }
     scales = image.permuteLikewise(scales);
-    
-    res.reshapeIfEmpty(image.taggedShape(), 
+
+    res.reshapeIfEmpty(image.taggedShape(),
             "recursiveGaussianSmoothing(): Output array has wrong shape.");
 
     {
@@ -279,7 +279,7 @@ pythonRecursiveGaussian(NumpyArray<3, Multiband<VoxelType> > image,
 }
 
 template < class VoxelType >
-NumpyAnyArray 
+NumpyAnyArray
 pythonRecursiveGaussianIsotropic(NumpyArray<3, Multiband<VoxelType> > image,
                                  double sigma,
                                  NumpyArray<3, Multiband<VoxelType> > res=python::object())
@@ -288,17 +288,17 @@ pythonRecursiveGaussianIsotropic(NumpyArray<3, Multiband<VoxelType> > image,
 }
 
 template <class PixelType>
-NumpyAnyArray 
-pythonSimpleSharpening2D(NumpyArray<3, Multiband<PixelType> > image, 
+NumpyAnyArray
+pythonSimpleSharpening2D(NumpyArray<3, Multiband<PixelType> > image,
                          double sharpeningFactor,
                          NumpyArray<3, Multiband<PixelType> > res=python::object() )
 {
     vigra_precondition(sharpeningFactor >= 0 ,
        "simpleSharpening2D(): sharpeningFactor must be >= 0.");
-       
-    res.reshapeIfEmpty(image.taggedShape(), 
+
+    res.reshapeIfEmpty(image.taggedShape(),
           "simpleSharpening2D(): Output array has wrong shape.");
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0;k<image.shape(2);++k)
@@ -313,19 +313,19 @@ pythonSimpleSharpening2D(NumpyArray<3, Multiband<PixelType> > image,
 }
 
 template <class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonGaussianSharpening2D(NumpyArray<3, Multiband<PixelType> > image,
-                           double sharpeningFactor, double scale, 
+                           double sharpeningFactor, double scale,
                            NumpyArray<3, Multiband<PixelType> > res=python::object() )
 {
     vigra_precondition(sharpeningFactor >= 0 ,
        "gaussianSharpening2D(): sharpeningFactor must be >= 0.");
     vigra_precondition(sharpeningFactor >= 0 ,
        "gaussianSharpening2D(): scale must be >= 0.");
-       
-    res.reshapeIfEmpty(image.taggedShape(), 
+
+    res.reshapeIfEmpty(image.taggedShape(),
              "gaussianSharpening2D(): Output array has wrong shape.");
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0;k<image.shape(2);++k)
@@ -340,38 +340,38 @@ pythonGaussianSharpening2D(NumpyArray<3, Multiband<PixelType> > image,
 }
 
 template <class PixelType, unsigned int N>
-NumpyAnyArray 
+NumpyAnyArray
 pythonLaplacianOfGaussian(NumpyArray<N, Multiband<PixelType> > array,
                           python::object scale,
                           NumpyArray<N, Multiband<PixelType> > res=python::object(),
-                          python::object sigma_d = python::object(0.0), 
+                          python::object sigma_d = python::object(0.0),
                           python::object step_size = python::object(1.0),
-                          double window_size = 0.0, 
+                          double window_size = 0.0,
                           python::object roi = python::object())
 {
     pythonScaleParam<N - 1> params(scale, sigma_d, step_size, "laplacianOfGaussian");
     params.permuteLikewise(array);
-    
+
     std::string description("channel-wise Laplacian of Gaussian, scale=");
     description += asString(scale);
-    
+
     ConvolutionOptions<N-1> opt(params().filterWindowSize(window_size));
-    
+
     if(roi != python::object())
     {
         typedef typename MultiArrayShape<N-1>::type Shape;
         Shape start = array.permuteLikewise(python::extract<Shape>(roi[0])());
         Shape stop  = array.permuteLikewise(python::extract<Shape>(roi[1])());
         opt.subarray(start, stop);
-        res.reshapeIfEmpty(array.taggedShape().resize(stop-start).setChannelDescription(description), 
+        res.reshapeIfEmpty(array.taggedShape().resize(stop-start).setChannelDescription(description),
                 "laplacianOfGaussian(): Output array has wrong shape.");
     }
     else
     {
-        res.reshapeIfEmpty(array.taggedShape().setChannelDescription(description), 
+        res.reshapeIfEmpty(array.taggedShape().setChannelDescription(description),
                 "laplacianOfGaussian(): Output array has wrong shape.");
     }
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0; k<array.shape(N-1); ++k)
@@ -381,58 +381,58 @@ pythonLaplacianOfGaussian(NumpyArray<N, Multiband<PixelType> > array,
             laplacianOfGaussianMultiArray(srcMultiArrayRange(barray), destMultiArray(bres), opt);
         }
     }
-    
+
     return res;
 }
 
 template <class PixelType, unsigned int N>
-NumpyAnyArray 
+NumpyAnyArray
 pythonGaussianDivergence(NumpyArray<N, TinyVector<PixelType, N> > array,
                          python::object scale,
                          NumpyArray<N, Singleband<PixelType> > res=python::object(),
-                         python::object sigma_d = python::object(0.0), 
+                         python::object sigma_d = python::object(0.0),
                          python::object step_size = python::object(1.0),
-                         double window_size = 0.0, 
+                         double window_size = 0.0,
                          python::object roi = python::object())
 {
     pythonScaleParam<N> params(scale, sigma_d, step_size, "gaussianDivergence");
     params.permuteLikewise(array);
-    
+
     std::string description("divergence of a vector field using Gaussian derivatives, scale=");
     description += asString(scale);
-    
+
     ConvolutionOptions<N> opt(params().filterWindowSize(window_size));
-    
+
     if(roi != python::object())
     {
         typedef typename MultiArrayShape<N>::type Shape;
         Shape start = array.permuteLikewise(python::extract<Shape>(roi[0])());
         Shape stop  = array.permuteLikewise(python::extract<Shape>(roi[1])());
         opt.subarray(start, stop);
-        res.reshapeIfEmpty(array.taggedShape().resize(stop-start).setChannelDescription(description), 
+        res.reshapeIfEmpty(array.taggedShape().resize(stop-start).setChannelDescription(description),
                 "gaussianDivergence(): Output array has wrong shape.");
     }
     else
     {
-        res.reshapeIfEmpty(array.taggedShape().setChannelDescription(description), 
+        res.reshapeIfEmpty(array.taggedShape().setChannelDescription(description),
                 "gaussianDivergence(): Output array has wrong shape.");
     }
-    
+
     {
         PyAllowThreads _pythread;
         gaussianDivergenceMultiArray(array, res, opt);
     }
-    
+
     return res;
 }
 
 template <class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonRecursiveFilter1(NumpyArray<3, Multiband<PixelType> > image,
-                       double b, BorderTreatmentMode borderTreatment, 
+                       double b, BorderTreatmentMode borderTreatment,
                        NumpyArray<3, Multiband<PixelType> > res = python::object())
 {
-    res.reshapeIfEmpty(image.taggedShape(), 
+    res.reshapeIfEmpty(image.taggedShape(),
             "recursiveFilter2D(): Output array has wrong shape.");
 
     {
@@ -449,12 +449,12 @@ pythonRecursiveFilter1(NumpyArray<3, Multiband<PixelType> > image,
 }
 
 template <class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonRecursiveFilter2(NumpyArray<3, Multiband<PixelType> > image,
-                       double b1, double b2, 
+                       double b1, double b2,
                        NumpyArray<3, Multiband<PixelType> > res = python::object())
 {
-    res.reshapeIfEmpty(image.taggedShape(), 
+    res.reshapeIfEmpty(image.taggedShape(),
             "recursiveFilter2D(): Output array has wrong shape.");
 
     {
@@ -472,24 +472,24 @@ pythonRecursiveFilter2(NumpyArray<3, Multiband<PixelType> > image,
 
 
 template <class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonRecursiveSmooth(NumpyArray<3, Multiband<PixelType> > image,
-                      double scale, BorderTreatmentMode borderTreatment, 
+                      double scale, BorderTreatmentMode borderTreatment,
                       NumpyArray<3, Multiband<PixelType> > res = python::object())
 {
     return pythonRecursiveFilter1(image, std::exp(-1.0/scale), borderTreatment, res);
 }
 
 template <class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonRecursiveGradient(NumpyArray<2, Singleband<PixelType> > image,
-                        double scale, 
+                        double scale,
                         NumpyArray<2, TinyVector<PixelType, 2> > res = python::object())
 {
     std::string description("recursive gradient, scale=");
     description += asString(scale);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
             "recursiveGradient2D(): Output array has wrong shape.");
 
     {
@@ -502,22 +502,22 @@ pythonRecursiveGradient(NumpyArray<2, Singleband<PixelType> > image,
         recursiveSmoothX(srcImageRange(image), destImage(res, band), scale);
         recursiveFirstDerivativeY(srcImageRange(res, band), destImage(res, band), scale);
     }
-    
+
     return res;
 }
 
 template <class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonRecursiveLaplacian(NumpyArray<3, Multiband<PixelType> > image,
-                         double scale, 
+                         double scale,
                          NumpyArray<3, Multiband<PixelType> > res = python::object())
 {
     using namespace vigra::functor;
-    
+
     std::string description("channel-wise recursive Laplacian, scale=");
     description += asString(scale);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
             "recursiveLaplacian2D(): Output array has wrong shape.");
 
     {
@@ -534,7 +534,7 @@ pythonRecursiveLaplacian(NumpyArray<3, Multiband<PixelType> > image,
 
             recursiveSmoothX(srcImageRange(bimage), destImage(tmp), scale);
             recursiveSecondDerivativeY(srcImageRange(tmp), destImage(tmp), scale);
-            
+
             combineTwoImages(srcImageRange(bres), srcImage(tmp), destImage(bres), Arg1()+Arg2());
         }
     }
@@ -544,7 +544,7 @@ pythonRecursiveLaplacian(NumpyArray<3, Multiband<PixelType> > image,
 void defineConvolutionFunctions()
 {
     using namespace python;
-    
+
     docstring_options doc_options(true, true, false);
 
     def("convolveOneDimension",
@@ -557,9 +557,14 @@ void defineConvolutionFunctions()
 
     def("convolveOneDimension",
         registerConverters(&pythonConvolveOneDimensionND<float,4>),
-        (arg("volume"), arg("dim"), arg("kernel"), arg("out")=python::object()), 
+        (arg("volume"), arg("dim"), arg("kernel"), arg("out")=python::object()),
         "Likewise for a 3D scalar or multiband volume.\n");
 
+    def("convolveOneDimension",
+        registerConverters(&pythonConvolveOneDimensionND<float,5>),
+        (arg("volume"), arg("dim"), arg("kernel"), arg("out")=python::object()),
+        "Likewise for a 4D scalar or multiband volume.\n");
+
     def("convolve", registerConverters(&pythonSeparableConvolveND_1Kernel<float,3>),
         (arg("image"), arg("kernel"), arg("out")=python::object()),
         "Convolve an image with the given 'kernel' (or kernels).\n"
@@ -581,6 +586,10 @@ void defineConvolutionFunctions()
         (arg("volume"), arg("kernel"), arg("out")=python::object()),
         "Convolve a volume with the same 1D kernel along all dimensions.\n");
 
+    def("convolve", registerConverters(&pythonSeparableConvolveND_1Kernel<float,5>),
+        (arg("volume"), arg("kernel"), arg("out")=python::object()),
+        "Convolve a volume with the same 1D kernel along all dimensions.\n");
+
     def("convolve", registerConverters(&pythonSeparableConvolveND_NKernels<float,3>),
         (arg("image"), arg("kernels"), arg("out")=python::object()),
         "Convolve an image with a different 1D kernel along each dimensions.\n");
@@ -589,6 +598,10 @@ void defineConvolutionFunctions()
         (arg("volume"), arg("kernels"), arg("out")=python::object()),
         "Convolve a volume with a different 1D kernel along each dimensions.\n");
 
+    def("convolve", registerConverters(&pythonSeparableConvolveND_NKernels<float,5>),
+        (arg("volume"), arg("kernels"), arg("out")=python::object()),
+        "Convolve a volume with a different 1D kernel along each dimensions.\n");
+
     def("convolve", registerConverters(&pythonConvolveImage<float>),
         (arg("image"), arg("kernel"), arg("out") = python::object()),
         "Convolve an image with a 2D kernel.\n");
@@ -603,8 +616,14 @@ void defineConvolutionFunctions()
         "For details, see normalizedConvolveImage_ in the C++ documentation.\n");
 
     def("gaussianSmoothing",
+        registerConverters(&pythonGaussianSmoothing<float,2>),
+        (arg("array"), arg("sigma"), arg("out")=python::object(),
+         arg("sigma_d")=0.0, arg("step_size")=1.0, arg("window_size")=0.0, arg("roi")=python::object()),
+        "Smooth 1D sequence with Gaussian.\n");
+
+    def("gaussianSmoothing",
         registerConverters(&pythonGaussianSmoothing<float,3>),
-        (arg("array"), arg("sigma"), arg("out")=python::object(), 
+        (arg("array"), arg("sigma"), arg("out")=python::object(),
          arg("sigma_d")=0.0, arg("step_size")=1.0, arg("window_size")=0.0, arg("roi")=python::object()),
         "Perform Gaussian smoothing of a 2D or 3D scalar or multiband array.\n\n"
         "Each channel of the array is smoothed independently. "
@@ -634,12 +653,18 @@ void defineConvolutionFunctions()
 
     def("gaussianSmoothing",
         registerConverters(&pythonGaussianSmoothing<float,4>),
-        (arg("array"), arg("sigma"), arg("out")=python::object(), 
+        (arg("array"), arg("sigma"), arg("out")=python::object(),
          arg("sigma_d")=0.0, arg("step_size")=1.0, arg("window_size")=0.0, arg("roi")=python::object()),
         "Smooth volume with Gaussian.\n");
 
+    def("gaussianSmoothing",
+        registerConverters(&pythonGaussianSmoothing<float,5>),
+        (arg("array"), arg("sigma"), arg("out")=python::object(),
+         arg("sigma_d")=0.0, arg("step_size")=1.0, arg("window_size")=0.0, arg("roi")=python::object()),
+        "Smooth 5D array with Gaussian.\n");
+
     def("recursiveGaussianSmoothing2D",
-        registerConverters(&pythonRecursiveGaussian<float>),               
+        registerConverters(&pythonRecursiveGaussian<float>),
         (arg("image"), arg("sigma"), arg("out")=python::object()),
         "Compute a fast approximate Gaussian smoothing of a 2D scalar or multiband image.\n\n"
         "This function uses the third-order recursive filter approximation to the "
@@ -649,31 +674,31 @@ void defineConvolutionFunctions()
         "applied (i.e. each dimension is smoothed in the same way). "
         "If 'sigma' is a tuple of values, the amount of smoothing will be different "
         "for each spatial dimension. The length of the tuple must be equal to the "
-        "number of spatial dimensions.\n\n"        
+        "number of spatial dimensions.\n\n"
         "For details see recursiveGaussianFilterLine_ in the vigra C++ documentation.\n");
 
     def("recursiveGaussianSmoothing2D",
-        registerConverters(&pythonRecursiveGaussianIsotropic<float>),               
+        registerConverters(&pythonRecursiveGaussianIsotropic<float>),
         (arg("image"), arg("sigma"), arg("out")=python::object()),
         "Compute isotropic fast approximate Gaussian smoothing.\n");
 
-    def("simpleSharpening2D", 
+    def("simpleSharpening2D",
         registerConverters(&pythonSimpleSharpening2D<float>),
         (arg("image"), arg("sharpeningFactor")=1.0, arg("out") = python::object()),
         "Perform simple sharpening function.\n"
         "\n"
         "For details see simpleSharpening_ in the vigra C++ documentation.\n");
 
-    def("gaussianSharpening2D", 
+    def("gaussianSharpening2D",
         registerConverters(&pythonGaussianSharpening2D<float>),
         (arg("image"), arg("sharpeningFactor")=1.0, arg("scale")=1.0, arg("out") = python::object()),
           "Perform sharpening function with gaussian filter."
           "\n\n"
           "For details see gaussianSharpening_ in the vigra C++ documentation.\n");
-          
-    def("laplacianOfGaussian", 
+
+    def("laplacianOfGaussian",
          registerConverters(&pythonLaplacianOfGaussian<float,3>),
-         (arg("array"), arg("scale") = 1.0, arg("out") = python::object(), 
+         (arg("array"), arg("scale") = 1.0, arg("out") = python::object(),
           arg("sigma_d") = 0.0, arg("step_size") = 1.0, arg("window_size")=0.0, arg("roi")=python::object()),
           "Filter 2D or 3D scalar array with the Laplacian of Gaussian operator at the given scale.\n\n"
           "If 'sigma' is a single value, an isotropic filter at this scale is "
@@ -684,19 +709,19 @@ void defineConvolutionFunctions()
           "per axis, the optional 'step_size' (single, tuple, or list) the distance between two adjacent "
           "pixels for each dimension. "
           "The length of the tuples or lists must be equal to the "
-          "number of spatial dimensions.\n\n" 
+          "number of spatial dimensions.\n\n"
           "'window_size' and 'roi' have the same meaning as in :func:`gaussianSmoothing`.\n\n"
           "For details see laplacianOfGaussianMultiArray_ and ConvolutionOptions_ in the vigra C++ documentation.\n");
 
-    def("laplacianOfGaussian", 
+    def("laplacianOfGaussian",
          registerConverters(&pythonLaplacianOfGaussian<float,4>),
-         (arg("array"), arg("scale") = 1.0, arg("out") = python::object(), 
+         (arg("array"), arg("scale") = 1.0, arg("out") = python::object(),
          arg("sigma_d") = 0.0, arg("step_size") = 1.0, arg("window_size")=0.0, arg("roi")=python::object()),
          "Likewise for a scalar volume.\n");
 
-    def("gaussianDivergence", 
+    def("gaussianDivergence",
          registerConverters(&pythonGaussianDivergence<float,2>),
-         (arg("array"), arg("scale") = 1.0, arg("out") = python::object(), 
+         (arg("array"), arg("scale") = 1.0, arg("out") = python::object(),
           arg("sigma_d") = 0.0, arg("step_size") = 1.0, arg("window_size")=0.0, arg("roi")=python::object()),
           "Compute the divergence of a 2D vector field with a first derivative of Gaussian at the given scale.\n\n"
           "If 'sigma' is a single value, an isotropic filter at this scale is "
@@ -707,13 +732,13 @@ void defineConvolutionFunctions()
           "per axis, the optional 'step_size' (single, tuple, or list) the distance between two adjacent "
           "pixels for each dimension. "
           "The length of the tuples or lists must be equal to the "
-          "number of spatial dimensions.\n\n" 
+          "number of spatial dimensions.\n\n"
           "'window_size' and 'roi' have the same meaning as in :func:`gaussianSmoothing`.\n\n"
           "For details see gaussianDivergenceMultiArray_ and ConvolutionOptions_ in the vigra C++ documentation.\n");
 
-    def("gaussianDivergence", 
+    def("gaussianDivergence",
          registerConverters(&pythonGaussianDivergence<float,3>),
-         (arg("array"), arg("scale") = 1.0, arg("out") = python::object(), 
+         (arg("array"), arg("scale") = 1.0, arg("out") = python::object(),
          arg("sigma_d") = 0.0, arg("step_size") = 1.0, arg("window_size")=0.0, arg("roi")=python::object()),
          "Likewise for a 3D vector field.\n");
 
diff --git a/vigranumpy/src/core/export_graph_algorithm_visitor.hxx b/vigranumpy/src/core/export_graph_algorithm_visitor.hxx
new file mode 100644
index 0000000..16c8105
--- /dev/null
+++ b/vigranumpy/src/core/export_graph_algorithm_visitor.hxx
@@ -0,0 +1,1100 @@
+#ifndef VIGRA_EXPORT_GRAPH_ALGORITHM_VISITOR_HXX
+#define VIGRA_EXPORT_GRAPH_ALGORITHM_VISITOR_HXX
+//#define NO_IMPORT_ARRAY
+
+/*boost python before anything else*/
+#include <boost/python.hpp>
+
+/*std*/
+#include <sstream>
+#include <string>
+
+/*vigra*/
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/graphs.hxx>
+#include <vigra/graph_maps.hxx>
+#include <vigra/python_graph.hxx>
+#include <vigra/graph_algorithms.hxx>
+#include <vigra/metrics.hxx>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/error.hxx>
+#include <vigra/multi_watersheds.hxx>
+namespace python = boost::python;
+
+namespace vigra{
+
+
+template<class GRAPH>
+class LemonGraphAlgorithmVisitor 
+:   public boost::python::def_visitor<LemonGraphAlgorithmVisitor<GRAPH> >
+{
+public:
+
+    friend class def_visitor_access;
+
+    typedef GRAPH Graph;
+
+    typedef LemonGraphAlgorithmVisitor<GRAPH> VisitorType;
+    // Lemon Graph Typedefs
+    
+    typedef typename Graph::index_type       index_type;
+    typedef typename Graph::Edge             Edge;
+    typedef typename Graph::Node             Node;
+    typedef typename Graph::Arc              Arc;
+
+    typedef typename Graph::NodeIt              NodeIt;
+    typedef typename Graph::EdgeIt              EdgeIt;
+    typedef typename Graph::ArcIt               ArcIt;
+
+
+    typedef EdgeHolder<Graph> PyEdge;
+    typedef NodeHolder<Graph> PyNode;
+    typedef  ArcHolder<Graph> PyArc;
+
+
+    // predefined array (for map usage)
+    const static unsigned int EdgeMapDim = IntrinsicGraphShape<Graph>::IntrinsicEdgeMapDimension;
+    const static unsigned int NodeMapDim = IntrinsicGraphShape<Graph>::IntrinsicNodeMapDimension;
+
+    typedef NumpyArray<EdgeMapDim,   Singleband<float > > FloatEdgeArray;
+    typedef NumpyArray<EdgeMapDim,   Singleband<UInt32> > UInt32EdgeArray;
+    typedef NumpyArray<EdgeMapDim,   Singleband<Int32 > > Int32EdgeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<float > > FloatNodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<UInt32> > UInt32NodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<Int32 > > Int32NodeArray;
+    typedef NumpyArray<NodeMapDim +1,Multiband <float > > MultiFloatNodeArray;
+    typedef NumpyArray<EdgeMapDim +1,Multiband <float > > MultiFloatEdgeArray;
+
+
+    typedef NumpyScalarEdgeMap<Graph,FloatEdgeArray>         FloatEdgeArrayMap;
+    typedef NumpyScalarEdgeMap<Graph,UInt32EdgeArray>        UInt32EdgeArrayMap;
+    typedef NumpyScalarEdgeMap<Graph,Int32EdgeArray>         Int32EdgeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,FloatNodeArray>         FloatNodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,UInt32NodeArray>        UInt32NodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,Int32NodeArray>         Int32NodeArrayMap;
+    typedef NumpyMultibandNodeMap<Graph,MultiFloatNodeArray> MultiFloatNodeArrayMap;
+
+
+    typedef ShortestPathDijkstra<Graph,float> ShortestPathDijkstraType;
+
+
+    typedef typename GraphDescriptorToMultiArrayIndex<Graph>::IntrinsicNodeMapShape NodeCoordinate;
+    typedef NumpyArray<1,NodeCoordinate>  NodeCoorinateArray;
+
+    LemonGraphAlgorithmVisitor(const std::string clsName)
+    :clsName_(clsName){
+
+    }
+
+
+    void exportSegmentationAlgorithms()const{
+        python::def("_edgeWeightedWatershedsSegmentation",registerConverters(&pyEdgeWeightedWatershedsSegmentation),
+            (
+                python::arg("graph"),
+                python::arg("edgeWeights"),
+                python::arg("seeds"),
+                python::arg("out")=python::object()
+            ),
+            "Seeded watersheds on a edge weighted graph"
+        );
+
+        python::def("_nodeWeightedWatershedsSegmentation",registerConverters(&pyNodeWeightedWatershedsSegmentation),
+            (
+                python::arg("graph"),
+                python::arg("nodeWeights"),
+                python::arg("seeds"),
+                python::arg("method")=std::string("regionGrowing"),
+                python::arg("out")=python::object()
+            ),
+            "Seeded watersheds on a node weighted graph"
+        );
+        python::def("_nodeWeightedWatershedsSeeds",registerConverters(&pyNodeWeightedWatershedsSeeds),
+            (
+                python::arg("graph"),
+                python::arg("nodeWeights"),
+                python::arg("out")=python::object()
+            ),
+            "Generate seeds for node weighted watersheds"
+        );
+
+        python::def("_carvingSegmentation",registerConverters(&pyCarvingSegmentation),
+            (
+                python::arg("graph"),
+                python::arg("edgeWeights"),
+                python::arg("seeds"),
+                python::arg("backgroundLabel"),
+                python::arg("backgroundBias"),
+                python::arg("noBiasBelow") = 0.0,
+                python::arg("out")=python::object()
+            ),
+            "Seeded watersheds on a edge weighted graph"
+        );
+
+
+        python::def("_shortestPathSegmentation",registerConverters(&pyShortestPathSegmentation),
+            (
+                python::arg("graph"),
+                python::arg("edgeWeights"),
+                python::arg("nodeWeights"),
+                python::arg("seeds"),
+                python::arg("out")=python::object()
+            ),
+            "Seeded shorted path segmentation on a edge and node weighted graph"
+        );
+
+
+        python::def("_felzenszwalbSegmentation",registerConverters(&pyFelzenszwalbSegmentation),
+            (
+                python::arg("graph"),
+                python::arg("edgeWeights"),
+                python::arg("nodeSizes"),
+                python::arg("k")=300.0f,
+                python::arg("nodeNumStop")=-1,
+                python::arg("out")=python::object()
+            ),
+            "Felzenwalb graph based segmentation"
+        );
+    }
+
+    void exportMiscAlgorithms()const{
+
+        python::def("_nodeFeatureDistToEdgeWeight",registerConverters(&pyNodeFeatureDistToEdgeWeight),
+            (
+                python::arg("graph"),
+                python::arg("nodeFeatures"),
+                python::arg("metric"),
+                python::arg("out")=python::object()
+            ),
+            "convert node features to edge weights with the given metric"
+        );
+        python::def("_nodeFeatureSumToEdgeWeight",registerConverters(&pyNodeFeatureSumToEdgeWeight),
+            (
+                python::arg("graph"),
+                python::arg("nodeFeatures"),
+                python::arg("out")=python::object()
+            ),
+            "convert node features to edge weights"
+        );
+
+        python::def("_opengmMulticutDataStructure",registerConverters(&pyMulticutDataStructure),
+            (
+                python::arg("graph"),
+                python::arg("edgeWeights")
+            )
+        );
+
+        
+
+        python::def("nodeGtToEdgeGt",registerConverters(&pyNodeGtToEdgeGt),
+            (
+                python::arg("graph"),
+                python::arg("nodeGt"),
+                python::arg("ignoreLabel"),
+                python::arg("out")=python::object()
+            )
+        );
+
+        python::def("_opengmArgToLabeling",registerConverters(&pyMulticutArgToLabeling),
+            (
+                python::arg("graph"),
+                python::arg("arg"),
+                python::arg("out")=python::object()
+            )
+        );
+        python::def("_wardCorrection",registerConverters(&pyWardCorrection),
+            (
+                python::arg("graph"),
+                python::arg("edgeIndicator"),
+                python::arg("nodeSize"),
+                python::arg("out")=python::object()
+            ),
+            "apply wards method to an edgeIndicator"
+        );
+
+        python::def("find3Cycles", registerConverters(&pyFind3Cycles));
+        python::def("find3CyclesEdges", registerConverters(&pyFind3CyclesEdges));
+        python::def("cyclesEdges", registerConverters(&pyCyclesEdges),
+            (
+                python::arg("graph"),
+                python::arg("graph"),
+                python::arg("out") = python::object()
+            )
+        );
+    }
+
+    void exportSmoothingAlgorithms()const{
+
+        python::def("_recursiveGraphSmoothing",registerConverters(&pyRecursiveGraphSmoothing),
+            (
+                python::arg("graph"),
+                python::arg("nodeFeatures"),
+                python::arg("edgeIndicator"),
+                python::arg("gamma"),
+                python::arg("edgeThreshold"),
+                python::arg("scale"),
+                python::arg("iterations")=1,
+                python::arg("outBuffer")=python::object(),
+                python::arg("out")=python::object()
+            ),
+            "recursive edge weighted guided graph smoothing"
+        );
+
+    }
+
+    std::string clsName_;
+    template <class classT>
+    void visit(classT& c) const
+    {   
+        // - watersheds-segmentation
+        // - carving-segmentation
+        // - felzenwalb-segmentation
+        // - labeling
+        exportSegmentationAlgorithms();
+
+        // - node Labels (usefull to make grid graph labels from rag labels)
+        // - node feature distance to edge weights
+        exportMiscAlgorithms();
+
+        // - recursiveGraphSmoothing
+        exportSmoothingAlgorithms();
+    }
+
+
+    static NumpyAnyArray pyFind3Cycles(
+        const GRAPH & graph
+    ){
+        NumpyArray<1, vigra::TinyVector<Int32, 3> > cycles;
+
+        MultiArray<1, vigra::TinyVector<Int32, 3> > cyclesArray;
+        find3Cycles(graph, cyclesArray);
+        cycles.reshapeIfEmpty(cyclesArray.shape());
+        cycles = cyclesArray;
+        return cycles;
+    }
+
+
+    static NumpyAnyArray pyFind3CyclesEdges(
+        const GRAPH & graph
+    ){
+        NumpyArray<1, vigra::TinyVector<Int32, 3> > cyclesEdges;
+
+        MultiArray<1, vigra::TinyVector<Int32, 3> > cyclesNodes;
+
+        find3Cycles(graph, cyclesNodes);
+        cyclesEdges.reshapeIfEmpty(cyclesNodes.shape());
+        
+        Node nodes[3];
+        Edge edges[3];
+
+        for(std::ptrdiff_t i=0; i<cyclesNodes.size(); ++i){
+            for(size_t j=0; j<3; ++j){
+                nodes[j] = graph.nodeFromId(cyclesNodes(i)[j]);
+            }
+            edges[0] = graph.findEdge(nodes[0],nodes[1]);
+            edges[1] = graph.findEdge(nodes[0],nodes[2]);
+            edges[2] = graph.findEdge(nodes[1],nodes[2]);
+            for(size_t j=0; j<3; ++j){
+                cyclesEdges(i)[j] = graph.id(edges[j]);
+            }
+        }
+
+        return cyclesEdges;
+    }
+
+    static NumpyAnyArray pyCyclesEdges(
+        const GRAPH & graph,
+        NumpyArray<1, vigra::TinyVector<Int32, 3> > cycles,
+        NumpyArray<1, vigra::TinyVector<Int32, 3> > edgesOut       
+    ){
+
+        Node nodes[3];
+        Edge edges[3];
+
+        edgesOut.reshapeIfEmpty(cycles.shape());
+        for(std::ptrdiff_t i=0; i<cycles.size(); ++i){
+            for(size_t j=0; j<3; ++j){
+                nodes[j] = graph.nodeFromId(cycles(i)[j]);
+            }
+            edges[0] = graph.findEdge(nodes[0],nodes[1]);
+            edges[1] = graph.findEdge(nodes[0],nodes[2]);
+            edges[2] = graph.findEdge(nodes[1],nodes[2]);
+            for(size_t j=0; j<3; ++j){
+                edgesOut(i)[j] = graph.id(edges[j]);
+            }
+        }   
+        return edgesOut;
+    }
+
+    
+
+    static NumpyAnyArray pyWardCorrection(
+        const Graph &           g,
+        const FloatEdgeArray    edgeWeightsArray,
+        const FloatNodeArray    nodeSizeArray,
+        const float             wardness,
+        FloatEdgeArray    outArray
+    ){
+        outArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g));
+
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap  edgeWeightsArrayMap(g,edgeWeightsArray);
+        FloatNodeArrayMap  nodeSizeArrayMap(g,nodeSizeArray);
+        FloatEdgeArrayMap  outArrayMap(g,outArray);
+
+        for(EdgeIt iter(g);iter!=lemon::INVALID;++iter){
+            const float uSize=nodeSizeArrayMap[g.u(*iter)];
+            const float vSize=nodeSizeArrayMap[g.v(*iter)];
+            const float w = edgeWeightsArrayMap[*iter];
+            const float ward  = 1.0f/(1.0f/std::log(uSize) + 1.0f/std::log(vSize)  );
+            const float wardF = wardness*ward + (1.0-wardness);
+            outArrayMap[*iter]=w*wardF;
+        }
+        return outArray;
+
+    }
+
+
+
+
+    static python::tuple pyMulticutDataStructure(
+        const Graph &           g,
+        const FloatEdgeArray    edgeWeightsArray
+    ){
+        UInt32NodeArray toDenseArray( IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(g));
+
+        // numpy arrays => lemon maps
+        UInt32NodeArrayMap toDenseArrayMap(g,toDenseArray);
+        FloatEdgeArrayMap  edgeWeightsArrayMap(g,edgeWeightsArray);
+
+        NumpyArray<2,UInt32> vis      ((    typename NumpyArray<2,UInt64>::difference_type(g.edgeNum(),2)));
+        NumpyArray<1,float > weights  ((    typename NumpyArray<1,double>::difference_type(g.edgeNum()  )));
+        
+        size_t denseIndex = 0 ;
+        for(NodeIt iter(g);iter!=lemon::INVALID;++iter){
+            toDenseArrayMap[*iter]=denseIndex;
+            ++denseIndex;
+        }
+        denseIndex=0;
+        for(EdgeIt iter(g);iter!=lemon::INVALID;++iter){
+            const size_t dU=toDenseArrayMap[g.u(*iter)];
+            const size_t dV=toDenseArrayMap[g.v(*iter)];
+            vis(denseIndex,0)=std::min(dU,dV);
+            vis(denseIndex,1)=std::max(dU,dV);
+            weights(denseIndex)=edgeWeightsArrayMap[*iter];
+            ++denseIndex;
+        }
+        return python::make_tuple(vis,weights);
+
+    }
+
+
+    static NumpyAnyArray pyNodeGtToEdgeGt(
+        const Graph &           g,
+        const UInt32NodeArray & nodeGt,
+        const Int64 ignoreLabel,
+        UInt32EdgeArray edgeGt
+    ){
+        edgeGt.reshapeIfEmpty(IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g));
+
+        // numpy arrays => lemon maps
+        UInt32NodeArrayMap nodeGtMap(g,nodeGt);
+        UInt32EdgeArrayMap  edgeGtMap(g,edgeGt);
+        nodeGtToEdgeGt(g, nodeGtMap, ignoreLabel, edgeGtMap);
+        return edgeGt;
+    }
+
+
+
+    static NumpyAnyArray pyMulticutArgToLabeling(
+        const Graph &              g,
+        const NumpyArray<1,UInt32> arg,
+        UInt32NodeArray            labelsArray
+    ){
+        labelsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(g));
+        UInt32NodeArrayMap labelsArrayMap(g,labelsArray);
+        size_t denseIndex = 0 ;
+        for(NodeIt iter(g);iter!=lemon::INVALID;++iter){
+            labelsArrayMap[*iter]=arg(denseIndex);
+            ++denseIndex;
+        }
+        return labelsArray;
+    }
+    /*
+    static NumpyAnyArray pyNodeIdsLabels(
+        const GRAPH & g,
+        NumpyArray<1,Singleband<UInt32> >  nodeIds,
+        UInt32NodeArray                    nodeLabelArray,
+        NumpyArray<1,Singleband<UInt32> >  out
+    ){
+        // reshape out
+        out.reshapeIfEmpty(nodeIds.shape());
+
+        // numpy arrays => lemon maps
+        UInt32NodeArrayMap nodeLabelArrayMap(g,nodeLabelArray);
+
+        for(size_t i=0;i<nodeIds.shape(0);++i)
+            out(i)=nodeLabelArrayMap[g.nodeFromId(nodeIds(i))];
+        return out;
+    }
+    
+    static NumpyAnyArray pyNodeIdsFeatures(
+        const GRAPH & g,
+        NumpyArray<1,Singleband<UInt32> >  nodeIds,
+        MultiFloatNodeArray                nodeFeaturesArray,
+        NumpyArray<2,Multiband<float >  >  out
+    ){
+        //  reshape out ?
+        typename NumpyArray<2,Multiband<float> >::difference_type outShape(nodeIds.shape(0),nodeFeaturesArray.shape(NodeMapDim));
+        out.reshapeIfEmpty(  NumpyArray<2,Multiband<float >  >::ArrayTraits::taggedShape(outShape,"xc"));
+
+        // numpy arrays => lemon maps
+        MultiFloatNodeArrayMap nodeFeaturesArrayMap(g,nodeFeaturesArray);
+
+        typedef typename  NumpyArray<1,int>::difference_type Coord1;
+        for(size_t i=0;i<nodeIds.shape(0);++i)
+            out[Coord1(i)]=nodeFeaturesArrayMap[g.nodeFromId(nodeIds(i))];
+        return out;
+    }
+    */
+    static NumpyAnyArray pyNodeFeatureDistToEdgeWeight(
+        const GRAPH & g,
+        const MultiFloatNodeArray & nodeFeaturesArray,
+        const std::string & functor,
+        FloatEdgeArray edgeWeightsArray
+    ){
+        edgeWeightsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g) );
+
+        if(functor==std::string("euclidean") || functor==std::string("norm") || functor==std::string("l2")){
+            typedef  metrics::Norm<float> DistFunctor;
+            DistFunctor f;
+            return pyNodeFeatureDistToEdgeWeightT<DistFunctor>(g,nodeFeaturesArray,f,edgeWeightsArray);
+        }
+        if(functor==std::string("squaredNorm")){
+            typedef  metrics::SquaredNorm<float> DistFunctor;
+            DistFunctor f;
+            return pyNodeFeatureDistToEdgeWeightT<DistFunctor>(g,nodeFeaturesArray,f,edgeWeightsArray);
+        }
+        else if (functor==std::string("manhattan") || functor==std::string("l1")){
+            typedef  metrics::Manhattan<float> DistFunctor;
+            DistFunctor f;
+            return pyNodeFeatureDistToEdgeWeightT<DistFunctor>(g,nodeFeaturesArray,f,edgeWeightsArray);
+        }
+        else if (functor==std::string("chiSquared")){
+            typedef  metrics::ChiSquared<float> DistFunctor;
+            DistFunctor f;
+            return pyNodeFeatureDistToEdgeWeightT<DistFunctor>(g,nodeFeaturesArray,f,edgeWeightsArray);
+        }
+        else{
+            throw std::runtime_error(
+                "distance not supported\n"
+                "supported distance types:\n"
+                "- euclidean/norm/l2\n"
+                "- squaredNorm\n"
+                "- manhattan/l1\n"
+                "- chiSquared\n"
+            );
+        }
+    }
+
+
+
+    static NumpyAnyArray pyNodeFeatureSumToEdgeWeight(
+        const GRAPH & g,
+        const FloatNodeArray & nodeFeaturesArray,
+        FloatEdgeArray edgeWeightsArray
+    ){
+        // reshape out?
+        edgeWeightsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g) );
+
+        // numpy arrays => lemon maps
+        FloatNodeArrayMap  nodeFeatureArrayMap(g,nodeFeaturesArray);
+        FloatEdgeArrayMap  edgeWeightsArrayMap(g,edgeWeightsArray);
+        
+        for(EdgeIt e(g);e!=lemon::INVALID;++e){
+            const Edge edge(*e);
+            const Node u=g.u(edge);
+            const Node v=g.v(edge);
+            edgeWeightsArrayMap[edge]=nodeFeatureArrayMap[u]+nodeFeatureArrayMap[v];
+        }
+        return edgeWeightsArray;
+    }
+
+    template<class FUNCTOR>
+    static NumpyAnyArray pyNodeFeatureDistToEdgeWeightT(
+        const GRAPH & g,
+        const MultiFloatNodeArray & nodeFeaturesArray,
+        FUNCTOR & functor,
+        FloatEdgeArray edgeWeightsArray
+    ){
+        // reshape out?
+        edgeWeightsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g) );
+
+        // numpy arrays => lemon maps
+        MultiFloatNodeArrayMap nodeFeatureArrayMap(g,nodeFeaturesArray);
+        FloatEdgeArrayMap      edgeWeightsArrayMap(g,edgeWeightsArray);
+        
+        for(EdgeIt e(g);e!=lemon::INVALID;++e){
+            const Edge edge(*e);
+            const Node u=g.u(edge);
+            const Node v=g.v(edge);
+            edgeWeightsArrayMap[edge]=functor(nodeFeatureArrayMap[u],nodeFeatureArrayMap[v]);
+        }
+        return edgeWeightsArray;
+    }
+
+    static NumpyAnyArray pyEdgeWeightedWatershedsSegmentation(
+        const GRAPH & g,
+        FloatEdgeArray edgeWeightsArray,
+        UInt32NodeArray seedsArray,
+        UInt32NodeArray labelsArray
+    ){
+        // resize output ? 
+        labelsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(g) );
+
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap edgeWeightsArrayMap(g,edgeWeightsArray);
+        UInt32NodeArrayMap seedsArrayMap(g,seedsArray);
+        UInt32NodeArrayMap labelsArrayMap(g,labelsArray);
+
+        // call algorithm itself
+        edgeWeightedWatershedsSegmentation(g,edgeWeightsArrayMap,seedsArrayMap,labelsArrayMap);
+
+        // retun labels
+        return labelsArray;
+    }
+
+    static NumpyAnyArray pyNodeWeightedWatershedsSegmentation(
+        const Graph &       g,
+        FloatNodeArray      nodeWeightsArray,
+        UInt32NodeArray     seedsArray,
+        const std::string & method,
+        UInt32NodeArray     labelsArray
+    ){
+
+        // resize output ? 
+        labelsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(g) );
+
+
+        WatershedOptions watershedsOption;
+        if(method==std::string("regionGrowing"))
+            watershedsOption.regionGrowing();
+        else
+            watershedsOption.unionFind();
+
+        // numpy arrays => lemon maps
+        FloatNodeArrayMap  nodeWeightsArrayMap(g,nodeWeightsArray);
+        UInt32NodeArrayMap labelsArrayMap(g,labelsArray);
+
+        std::copy(seedsArray.begin(),seedsArray.end(),labelsArray.begin());
+
+        //lemon_graph::graph_detail::generateWatershedSeeds(g, nodeWeightsArrayMap, labelsArrayMap, watershedsOption.seed_options);
+        lemon_graph::watershedsGraph(g, nodeWeightsArrayMap, labelsArrayMap, watershedsOption);
+        //lemon_graph::graph_detail::seededWatersheds(g, nodeWeightsArrayMap, seedsArrayMap, watershedsOption);
+        
+        return labelsArray;
+    }
+
+
+
+
+
+    static NumpyAnyArray pyNodeWeightedWatershedsSeeds(
+        const Graph &       g,
+        FloatNodeArray      nodeWeightsArray,
+        UInt32NodeArray     seedsArray
+    ){
+        const std::string method="regionGrowing";
+        // resize output ? 
+        seedsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(g) );
+
+        WatershedOptions watershedsOption;
+        if(method==std::string("regionGrowing"))
+            watershedsOption.regionGrowing();
+
+        // numpy arrays => lemon maps
+        FloatNodeArrayMap  nodeWeightsArrayMap(g,nodeWeightsArray);
+        UInt32NodeArrayMap seedsArrayMap(g,seedsArray);
+
+        lemon_graph::graph_detail::generateWatershedSeeds(g, nodeWeightsArrayMap, seedsArrayMap, watershedsOption.seed_options);
+
+        return seedsArray;
+    }
+
+    static NumpyAnyArray pyCarvingSegmentation(
+        const GRAPH & g,
+        FloatEdgeArray edgeWeightsArray,
+        UInt32NodeArray seedsArray,
+        const UInt32    backgroundLabel,
+        const float     backgroundBias,
+        const float     noBiasBelow,
+        UInt32NodeArray labelsArray
+    ){
+        // resize output ? 
+        labelsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(g) );
+
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap edgeWeightsArrayMap(g,edgeWeightsArray);
+        UInt32NodeArrayMap seedsArrayMap(g,seedsArray);
+        UInt32NodeArrayMap labelsArrayMap(g,labelsArray);
+
+        // call algorithm itself
+        carvingSegmentation(g,edgeWeightsArrayMap,seedsArrayMap,backgroundLabel,backgroundBias,noBiasBelow,labelsArrayMap);
+
+        // retun labels
+        return labelsArray;
+    }
+
+    static NumpyAnyArray pyShortestPathSegmentation(
+        const Graph &       g,
+        FloatEdgeArray      edgeWeightsArray,
+        FloatNodeArray      nodeWeightsArray,
+        UInt32NodeArray     seedsArray,
+        UInt32NodeArray     labelsArray
+    ){
+
+        // resize output ? 
+        labelsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(g) );
+
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap  edgeWeightsArrayMap(g,edgeWeightsArray);
+        FloatNodeArrayMap  nodeWeightsArrayMap(g,nodeWeightsArray);
+        UInt32NodeArrayMap labelsArrayMap(g,labelsArray);
+
+
+
+        std::copy(seedsArray.begin(),seedsArray.end(),labelsArray.begin());
+
+        shortestPathSegmentation<
+            Graph,FloatEdgeArrayMap, FloatNodeArrayMap, UInt32NodeArrayMap, float
+        >(g, edgeWeightsArrayMap, nodeWeightsArrayMap, labelsArrayMap);
+     
+        
+        return labelsArray;
+    }
+
+
+    static NumpyAnyArray pyFelzenszwalbSegmentation(
+        const GRAPH & g,
+        FloatEdgeArray edgeWeightsArray,
+        FloatNodeArray nodeSizesArray,
+        const float k,
+        const int nodeNumStop,
+        UInt32NodeArray labelsArray
+    ){
+        // resize output ? 
+        labelsArray.reshapeIfEmpty(  IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(g) );
+
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap  edgeWeightsArrayMap(g,edgeWeightsArray);
+        FloatNodeArrayMap  nodeSizesArrayMap(g,nodeSizesArray);
+        UInt32NodeArrayMap labelsArrayMap(g,labelsArray);
+
+        // call algorithm itself
+        felzenszwalbSegmentation(g,edgeWeightsArrayMap,nodeSizesArrayMap,k,labelsArrayMap,nodeNumStop);
+
+        // retun labels
+        return labelsArray;
+    }
+
+    static NumpyAnyArray pyRecursiveGraphSmoothing(
+        const GRAPH & g,
+        MultiFloatNodeArray nodeFeaturesArray,
+        FloatEdgeArray      edgeIndicatorArray,
+        const float         lambda,
+        const float         edgeThreshold,
+        const float         scale,
+        const size_t        iterations,
+        MultiFloatNodeArray nodeFeaturesBufferArray,
+        MultiFloatNodeArray nodeFeaturesOutArray
+    ){
+        TaggedShape inShape  = nodeFeaturesArray.taggedShape();
+        TaggedShape outShape = TaggedGraphShape<Graph>::taggedNodeMapShape(g);
+        if(inShape.hasChannelAxis()){
+            outShape.setChannelCount(inShape.channelCount());
+        }
+        nodeFeaturesBufferArray.reshapeIfEmpty(outShape);
+        nodeFeaturesOutArray.reshapeIfEmpty(outShape);
+
+        // numpy arrays => lemon maps
+        MultiFloatNodeArrayMap nodeFeaturesArrayMap(g,nodeFeaturesArray);
+        FloatEdgeArrayMap edgeIndicatorArrayMap(g,edgeIndicatorArray);
+        MultiFloatNodeArrayMap nodeFeaturesBufferArrayMap(g,nodeFeaturesBufferArray);
+        MultiFloatNodeArrayMap nodeFeaturesOutArrayMap(g,nodeFeaturesOutArray);
+
+        // call algorithm itself
+        recursiveGraphSmoothing(g,nodeFeaturesArrayMap,edgeIndicatorArrayMap,lambda,edgeThreshold,scale,iterations,nodeFeaturesBufferArrayMap,nodeFeaturesOutArrayMap);
+
+        // retun smoothed features
+        return nodeFeaturesOutArray;
+    }
+
+};
+
+
+template<class GRAPH>
+class LemonGridGraphAlgorithmAddonVisitor 
+:   public boost::python::def_visitor<LemonGridGraphAlgorithmAddonVisitor<GRAPH> >
+{
+public:
+
+    friend class def_visitor_access;
+
+    typedef GRAPH Graph;
+
+    typedef LemonGraphAlgorithmVisitor<GRAPH> VisitorType;
+    // Lemon Graph Typedefs
+    
+    typedef typename Graph::index_type       index_type;
+    typedef typename Graph::Edge             Edge;
+    typedef typename Graph::Node             Node;
+    typedef typename Graph::Arc              Arc;
+
+    typedef typename Graph::NodeIt              NodeIt;
+    typedef typename Graph::EdgeIt              EdgeIt;
+    typedef typename Graph::ArcIt               ArcIt;
+
+
+    typedef EdgeHolder<Graph> PyEdge;
+    typedef NodeHolder<Graph> PyNode;
+    typedef  ArcHolder<Graph> PyArc;
+
+
+    // predefined array (for map usage)
+    const static unsigned int EdgeMapDim = IntrinsicGraphShape<Graph>::IntrinsicEdgeMapDimension;
+    const static unsigned int NodeMapDim = IntrinsicGraphShape<Graph>::IntrinsicNodeMapDimension;
+
+    typedef NumpyArray<EdgeMapDim,   Singleband<float > > FloatEdgeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<float > > FloatNodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<UInt32> > UInt32NodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<Int32 > > Int32NodeArray;
+    typedef NumpyArray<NodeMapDim +1,Multiband <float > > MultiFloatNodeArray;
+    typedef NumpyArray<EdgeMapDim +1,Multiband <float > > MultiFloatEdgeArray;
+
+
+    typedef NumpyScalarEdgeMap<Graph,FloatEdgeArray>         FloatEdgeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,FloatNodeArray>         FloatNodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,UInt32NodeArray>        UInt32NodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,Int32NodeArray>         Int32NodeArrayMap;
+    typedef NumpyMultibandNodeMap<Graph,MultiFloatNodeArray> MultiFloatNodeArrayMap;
+    typedef NumpyMultibandEdgeMap<Graph,MultiFloatEdgeArray> MultiFloatEdgeArrayMap;
+
+    typedef ShortestPathDijkstra<Graph,float> ShortestPathDijkstraType;
+
+
+    typedef typename GraphDescriptorToMultiArrayIndex<Graph>::IntrinsicNodeMapShape NodeCoordinate;
+    typedef NumpyArray<1,NodeCoordinate>  NodeCoorinateArray;
+
+    LemonGridGraphAlgorithmAddonVisitor(const std::string & clsName){}
+
+
+    template <class classT>
+    void visit(classT& c) const
+    {   
+
+        // - edge weights from interpolated image
+        exportMiscAlgorithms(c);
+
+    }
+
+    template <class classT>
+    void exportMiscAlgorithms(classT & c)const{
+        
+
+
+        python::def("edgeFeaturesFromInterpolatedImage",registerConverters(&pyEdgeWeightsFromInterpolatedImage),
+            (
+                python::arg("graph"),
+                python::arg("image"),
+                python::arg("out")=python::object()
+            ),
+            "convert an image with with ``shape = graph.shape*2 - 1`` to an edge weight array"
+        );
+
+        python::def("edgeFeaturesFromImage",registerConverters(&pyEdgeWeightsFromImage),
+            (
+                python::arg("graph"),
+                python::arg("image"),
+                python::arg("out")=python::object()
+            ),
+            "convert an image with with shape = graph.shape OR shape = graph.shape *2 -1 to an edge weight array"
+        );
+
+        python::def("edgeFeaturesFromImage",registerConverters(&pyEdgeWeightsFromImageMb),
+            (
+                python::arg("graph"),
+                python::arg("image"),
+                python::arg("out")=python::object()
+            ),
+            "convert an image with with shape = graph.shape OR shape = graph.shape *2 -1 to an edge weight array"
+        );
+
+
+        c
+        .def("affiliatedEdgesSerializationSize",&pyAffiliatedEdgesSerializationSize,
+            (
+                python::arg("rag"),
+                python::arg("affiliatedEdges")
+            )
+        );
+
+
+        //'python::def("edgeFeaturesFromInterpolatedImageCorrected",registerConverters(&pyEdgeWeightsFromInterpolatedImageCorrected),
+        //'    (
+        //'        python::arg("graph"),
+        //'        python::arg("image"),
+        //'        python::arg("out")=python::object()
+        //'    ),
+        //'    "convert an image with with shape = graph.shape *2 -1 to an edge weight array"
+        //'    ""
+        //');
+
+
+    }
+
+
+    
+
+
+    static size_t pyAffiliatedEdgesSerializationSize(
+        const GRAPH & gridGraph,
+        const AdjacencyListGraph & rag,
+        const typename AdjacencyListGraph:: template EdgeMap< std::vector<Edge> > & affiliatedEdges
+    ){
+        return affiliatedEdgesSerializationSize(gridGraph, rag, affiliatedEdges);
+    }
+
+
+    static NumpyAnyArray pyEdgeWeightsFromImage(
+        const GRAPH & g,
+        const FloatNodeArray & image,
+        FloatEdgeArray edgeWeightsArray
+    ){
+
+        bool regularShape=true;
+        bool topologicalShape=true;
+
+        for(size_t d=0;d<NodeMapDim;++d){
+            if(image.shape(d)!=g.shape()[d]){
+                regularShape=false;
+            }
+            if(image.shape(d)!=2*g.shape()[d]-1){
+                topologicalShape=false;
+            }
+        }
+       
+        if(regularShape)
+            return pyEdgeWeightsFromOrginalSizeImage(g,image,edgeWeightsArray);
+        else if(topologicalShape)
+            return pyEdgeWeightsFromInterpolatedImage(g,image,edgeWeightsArray);
+        else{
+            vigra_precondition(false, "shape of edge image does not match graph shape");
+            // to avid no return warnings
+            return pyEdgeWeightsFromOrginalSizeImage(g,image,edgeWeightsArray);
+        }
+    }
+
+
+    static NumpyAnyArray pyEdgeWeightsFromImageMb(
+        const GRAPH & g,
+        const MultiFloatNodeArray & image,
+        MultiFloatEdgeArray edgeWeightsArray
+    ){
+
+        bool regularShape=true;
+        bool topologicalShape=true;
+
+        for(size_t d=0;d<NodeMapDim;++d){
+            if(image.shape(d)!=g.shape()[d]){
+                regularShape=false;
+            }
+            if(image.shape(d)!=2*g.shape()[d]-1){
+                topologicalShape=false;
+            }
+        }
+       
+        if(regularShape)
+            return pyEdgeWeightsFromOrginalSizeImageMb(g,image,edgeWeightsArray);
+        else if(topologicalShape)
+            return pyEdgeWeightsFromInterpolatedImageMb(g,image,edgeWeightsArray);
+        else{
+            vigra_precondition(false, "shape of edge image does not match graph shape");
+            // to avid no return warnings
+            return pyEdgeWeightsFromOrginalSizeImageMb(g,image,edgeWeightsArray);
+        }
+    }
+
+
+    static NumpyAnyArray pyEdgeWeightsFromInterpolatedImage(
+        const GRAPH & g,
+        const FloatNodeArray & interpolatedImage,
+        FloatEdgeArray edgeWeightsArray
+    ){
+
+        for(size_t d=0;d<NodeMapDim;++d){
+            //std::cout<<"is "<<interpolatedImage.shape(d)<<"gs "<<2*g.shape()[d]-1<<"\n";
+            vigra_precondition(interpolatedImage.shape(d)==2*g.shape()[d]-1, "interpolated shape must be shape*2 -1");
+        }
+        edgeWeightsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g) );
+
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap edgeWeightsArrayMap(g,edgeWeightsArray);
+        typedef typename FloatNodeArray::difference_type CoordType;
+        for(EdgeIt iter(g); iter!=lemon::INVALID; ++ iter){
+
+            const Edge edge(*iter);
+            const CoordType uCoord(g.u(edge));
+            const CoordType vCoord(g.v(edge));
+            const CoordType tCoord = uCoord+vCoord;
+            edgeWeightsArrayMap[edge]=interpolatedImage[tCoord];
+        }
+        return edgeWeightsArray;
+    }
+
+    static NumpyAnyArray pyEdgeWeightsFromOrginalSizeImage(
+        const GRAPH & g,
+        const FloatNodeArray & image,
+        FloatEdgeArray edgeWeightsArray
+    ){
+
+        for(size_t d=0;d<NodeMapDim;++d){
+            //std::cout<<"is "<<image.shape(d)<<"gs "<<2*g.shape()[d]-1<<"\n";
+            vigra_precondition(image.shape(d)==g.shape()[d], "interpolated shape must be shape*2 -1");
+        }
+        edgeWeightsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g) );
+
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap edgeWeightsArrayMap(g,edgeWeightsArray);
+        typedef typename FloatNodeArray::difference_type CoordType;
+        for(EdgeIt iter(g); iter!=lemon::INVALID; ++ iter){
+
+            const Edge edge(*iter);
+            const CoordType uCoord(g.u(edge));
+            const CoordType vCoord(g.v(edge));
+            edgeWeightsArrayMap[edge]=(image[uCoord]+image[vCoord])/2.0;
+        }
+        return edgeWeightsArray;
+    }
+
+
+
+    static NumpyAnyArray pyEdgeWeightsFromInterpolatedImageMb(
+        const GRAPH & g,
+        const MultiFloatNodeArray & interpolatedImage,
+        MultiFloatEdgeArray edgeWeightsArray
+    ){
+
+        for(size_t d=0;d<NodeMapDim;++d){
+            //std::cout<<"is "<<interpolatedImage.shape(d)<<"gs "<<2*g.shape()[d]-1<<"\n";
+            vigra_precondition(interpolatedImage.shape(d)==2*g.shape()[d]-1, "interpolated shape must be shape*2 -1");
+        }
+
+        // resize out
+        typename MultiArray<EdgeMapDim+1,int>::difference_type outShape;
+        for(size_t d=0;d<EdgeMapDim;++d){
+            outShape[d]=IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g)[d];
+        }
+        outShape[EdgeMapDim] = interpolatedImage.shape(NodeMapDim);
+
+        edgeWeightsArray.reshapeIfEmpty(   MultiFloatEdgeArray::ArrayTraits::taggedShape(outShape,"nc") );
+
+        
+        // numpy arrays => lemon maps
+        MultiFloatEdgeArrayMap edgeWeightsArrayMap(g,edgeWeightsArray);
+        typedef typename FloatNodeArray::difference_type CoordType;
+        for(EdgeIt iter(g); iter!=lemon::INVALID; ++ iter){
+
+            const Edge edge(*iter);
+            const CoordType uCoord(g.u(edge));
+            const CoordType vCoord(g.v(edge));
+            const CoordType tCoord = uCoord+vCoord;
+            edgeWeightsArrayMap[edge]=interpolatedImage[tCoord];
+        }
+        return edgeWeightsArray;
+    }
+
+
+    static NumpyAnyArray pyEdgeWeightsFromOrginalSizeImageMb(
+        const GRAPH & g,
+        const MultiFloatNodeArray & image,
+        MultiFloatEdgeArray edgeWeightsArray
+    ){
+
+        for(size_t d=0;d<NodeMapDim;++d){
+            //std::cout<<"is "<<image.shape(d)<<"gs "<<2*g.shape()[d]-1<<"\n";
+            vigra_precondition(image.shape(d)==g.shape()[d], "interpolated shape must be shape*2 -1");
+        }
+
+        // resize out
+        typename MultiArray<EdgeMapDim+1,int>::difference_type outShape;
+        for(size_t d=0;d<EdgeMapDim;++d){
+            outShape[d]=IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g)[d];
+        }
+        outShape[EdgeMapDim] = image.shape(NodeMapDim);
+
+
+        //edgeWeightsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(outShape),"ec" );
+
+
+        edgeWeightsArray.reshapeIfEmpty(   MultiFloatEdgeArray::ArrayTraits::taggedShape(outShape,"nc") );
+
+
+        // numpy arrays => lemon maps
+        MultiFloatEdgeArrayMap edgeWeightsArrayMap(g,edgeWeightsArray);
+        typedef typename FloatNodeArray::difference_type CoordType;
+        for(EdgeIt iter(g); iter!=lemon::INVALID; ++ iter){
+
+            const Edge edge(*iter);
+            const CoordType uCoord(g.u(edge));
+            const CoordType vCoord(g.v(edge));
+            MultiArray<1, float>  val = image[uCoord];
+            val+=image[vCoord];
+            val/=2.0;
+            edgeWeightsArrayMap[edge]=val;
+        }
+        return edgeWeightsArray;
+    }
+
+
+    /*
+    static NumpyAnyArray pyEdgeWeightsFromInterpolatedImageCorrected(
+        const GRAPH & g,
+        const FloatNodeArray & interpolatedImage,
+        FloatEdgeArray edgeWeightsArray
+    ){
+
+        for(size_t d=0;d<NodeMapDim;++d){
+            //std::cout<<"is "<<interpolatedImage.shape(d)<<"gs "<<2*g.shape()[d]-1<<"\n";
+            vigra_precondition(interpolatedImage.shape(d)==2*g.shape()[d]-1, "interpolated shape must be shape*2 -1");
+        }
+
+
+        edgeWeightsArray.reshapeIfEmpty( IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape(g) );
+
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap edgeWeightsArrayMap(g,edgeWeightsArray);
+        typedef typename FloatNodeArray::difference_type CoordType;
+        for(EdgeIt iter(g); iter!=lemon::INVALID; ++ iter){
+
+            const Edge edge(*iter);
+            const CoordType uCoord(g.u(edge));
+            const CoordType vCoord(g.v(edge));
+            const CoordType tCoord = uCoord+vCoord;
+            int diffCounter = 0;
+            for(int i=0; i<NodeMapDim; ++i) {
+                if (uCoord[i] != vCoord[i]) {
+                    diffCounter++;
+                }
+            }
+            edgeWeightsArrayMap[edge]=sqrt(diffCounter)*interpolatedImage[tCoord];
+        }
+        return edgeWeightsArray;
+    }
+    */
+};
+
+
+
+} // end namespace vigra
+
+#endif // VIGRA_EXPORT_GRAPH_ALGORITHM_VISITOR_HXX
diff --git a/vigranumpy/src/core/export_graph_hierarchical_clustering_visitor.hxx b/vigranumpy/src/core/export_graph_hierarchical_clustering_visitor.hxx
new file mode 100644
index 0000000..f60a38f
--- /dev/null
+++ b/vigranumpy/src/core/export_graph_hierarchical_clustering_visitor.hxx
@@ -0,0 +1,477 @@
+#ifndef VIGRA_EXPORT_GRAPH_HIERARCHICAL_CLUSTERING_VISTITOR_HXX
+#define VIGRA_EXPORT_GRAPH_HIERARCHICAL_CLUSTERING_VISTITOR_HXX
+//#define NO_IMPORT_ARRAY
+
+/*boost python before anything else*/
+#include <boost/python.hpp>
+
+/*std*/
+#include <sstream>
+#include <string>
+
+/*vigra*/
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/graphs.hxx>
+#include <vigra/graph_maps.hxx>
+#include <vigra/python_graph.hxx>
+#include <vigra/graph_algorithms.hxx>
+#include <vigra/metrics.hxx>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/error.hxx>
+#include <vigra/merge_graph_adaptor.hxx>
+#include <vigra/hierarchical_clustering.hxx>
+#include <vigra/timing.hxx>
+namespace python = boost::python;
+
+namespace vigra{
+
+
+
+template<class GRAPH>
+class LemonGraphHierachicalClusteringVisitor 
+:   public boost::python::def_visitor<LemonGraphHierachicalClusteringVisitor<GRAPH> >
+{
+public:
+
+    friend class def_visitor_access;
+
+    typedef GRAPH Graph;
+    typedef MergeGraphAdaptor<Graph> MergeGraph;
+
+    typedef LemonGraphHierachicalClusteringVisitor<GRAPH> VisitorType;
+    // Lemon Graph Typedefs
+    
+    typedef typename Graph::index_type       index_type;
+    typedef typename Graph::Edge             Edge;
+    typedef typename Graph::Node             Node;
+    typedef typename Graph::Arc              Arc;
+    typedef typename Graph::NodeIt           NodeIt;
+    typedef typename Graph::EdgeIt           EdgeIt;
+    typedef typename Graph::ArcIt            ArcIt;
+
+
+    typedef EdgeHolder<Graph> PyEdge;
+    typedef NodeHolder<Graph> PyNode;
+    typedef  ArcHolder<Graph> PyArc;
+
+
+    // predefined array (for map usage)
+    const static unsigned int EdgeMapDim = IntrinsicGraphShape<Graph>::IntrinsicEdgeMapDimension;
+    const static unsigned int NodeMapDim = IntrinsicGraphShape<Graph>::IntrinsicNodeMapDimension;
+
+    typedef NumpyArray<EdgeMapDim,   Singleband<float > > FloatEdgeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<float > > FloatNodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<UInt32> > UInt32NodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<Int32 > > Int32NodeArray;
+    typedef NumpyArray<NodeMapDim +1,Multiband <float > > MultiFloatNodeArray;
+
+    typedef NumpyScalarEdgeMap<Graph,FloatEdgeArray>         FloatEdgeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,FloatNodeArray>         FloatNodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,UInt32NodeArray>        UInt32NodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,Int32NodeArray>         Int32NodeArrayMap;
+    typedef NumpyMultibandNodeMap<Graph,MultiFloatNodeArray> MultiFloatNodeArrayMap;
+
+
+    typedef cluster_operators::EdgeWeightNodeFeatures<
+        MergeGraph,
+        FloatEdgeArrayMap,
+        FloatEdgeArrayMap,
+        MultiFloatNodeArrayMap,
+        FloatNodeArrayMap,
+        FloatEdgeArrayMap,
+        UInt32NodeArrayMap
+    > DefaultClusterOperator;
+
+
+    //typedef cluster_operators::EdgeWeightNodeFeatures2<
+    //    MergeGraph,
+    //    FloatEdgeArrayMap,
+    //    FloatEdgeArrayMap,
+    //    MultiFloatNodeArrayMap,
+    //    FloatNodeArrayMap,
+    //    FloatEdgeArrayMap
+    //> NeuroClusterOperator;
+
+    typedef cluster_operators::PythonOperator<MergeGraph> PythonClusterOperator;
+
+   
+
+
+    LemonGraphHierachicalClusteringVisitor(const std::string clsName)
+    :clsName_(clsName){
+
+    }
+
+
+
+    void exportMergeGraph()const{
+        const std::string mgAdaptorClsName = clsName_ + std::string("MergeGraph");
+        python::class_<MergeGraph,boost::noncopyable>(
+            mgAdaptorClsName.c_str(),python::init<const Graph &>()[python::with_custodian_and_ward<1 /*custodian == self*/, 2 /*ward == const InputLabelingView & */>()]
+        )
+        .def(LemonUndirectedGraphCoreVisitor<MergeGraph>(mgAdaptorClsName))
+        .def("inactiveEdgesNode",&pyInactiveEdgesNode)
+        .def("graph",&pyMergeGraphsGraph, python::return_internal_reference<>())
+        .def("contractEdge",&pyContractEdgeA)
+        .def("contractEdge",&pyContractEdgeB)
+        .def("hasEdgeId",&pyHasEdgeId)
+
+        .def("graphLabels",registerConverters(&pyCurrentLabeling<MergeGraph>),
+            (
+                python::arg("out")=python::object()
+            )
+        )
+
+        ;
+
+        python::def("__mergeGraph",&pyMergeGraphConstructor ,  
+            python::with_custodian_and_ward_postcall< 0,1 ,
+                    python::return_value_policy<   python::manage_new_object      >  >()  
+        )
+        ;
+    }
+
+    void exportHierarchicalClusteringOperators()const{
+        {   
+            const std::string operatorName = clsName_ + std::string("MergeGraph") + std::string("MinEdgeWeightNodeDistOperator");
+            python::class_<DefaultClusterOperator  >(operatorName.c_str(),python::no_init)
+            .def("__init__", python::make_constructor(&pyEdgeWeightNodeFeaturesConstructor))
+            ;
+            python::def("__minEdgeWeightNodeDistOperator",registerConverters(&pyEdgeWeightNodeFeaturesConstructor),
+                python::with_custodian_and_ward_postcall< 0,1 ,
+                    python::with_custodian_and_ward_postcall< 0 ,2,
+                        python::with_custodian_and_ward_postcall< 0 ,3,
+                            python::with_custodian_and_ward_postcall< 0 ,4,
+                                python::with_custodian_and_ward_postcall< 0 ,5,
+                                    python::with_custodian_and_ward_postcall< 0 ,6,
+                                        python::with_custodian_and_ward_postcall< 0 ,7,
+                                            python::return_value_policy<   python::manage_new_object      
+                >  >    >   >   >   >   >   >()  
+            );
+
+        }
+        //{   
+        //    const std::string operatorName = clsName_ + std::string("MergeGraph") + std::string("NeuroOperator");
+        //    python::class_<NeuroClusterOperator  >(operatorName.c_str(),python::no_init)
+        //    .def("__init__", python::make_constructor(&pyNeuroConstructor))
+        //    ;
+        //    python::def("__neuroOperator",registerConverters(&pyNeuroConstructor),
+        //        python::with_custodian_and_ward_postcall< 0,1 ,
+        //            python::with_custodian_and_ward_postcall< 0 ,2,
+        //                python::with_custodian_and_ward_postcall< 0 ,3,
+        //                    python::with_custodian_and_ward_postcall< 0 ,4,
+        //                        python::with_custodian_and_ward_postcall< 0 ,5,
+        //                            python::with_custodian_and_ward_postcall< 0 ,6,
+        //                                python::return_value_policy<   python::manage_new_object      
+        //        >  >    >   >   >   >   >()  
+        //    );
+        //}
+        {
+
+            const std::string operatorName = clsName_ + std::string("MergeGraph") + std::string("PythonOperator");
+            python::class_<PythonClusterOperator  >(operatorName.c_str(),python::no_init)
+            .def("__init__", python::make_constructor(&pyPythonOperatorConstructor))//,
+                //python::return_value_policy<python::manage_new_object>() )
+            ;
+            python::def("__pythonClusterOperator",registerConverters(&pyPythonOperatorConstructor),
+                python::with_custodian_and_ward_postcall< 0,1 ,
+                    python::with_custodian_and_ward_postcall< 0,2 ,
+                        python::return_value_policy<   python::manage_new_object      >  >  >()  
+            );
+        }
+    }
+
+    template<class CLUSTER_OPERATOR>
+    void exportHierarchicalClustering(const std::string & opClsName)const{
+        typedef CLUSTER_OPERATOR ClusterOperator;
+        typedef HierarchicalClustering<ClusterOperator> HCluster;
+
+        const std::string clsName = std::string("HierarchicalClustering")+ opClsName;
+        python::class_<HCluster,boost::noncopyable>(
+            clsName.c_str(),python::init<ClusterOperator &>()[python::with_custodian_and_ward<1 /*custodian == self*/, 2 /*ward == const InputLabelingView & */>()]
+        )
+        .def("cluster",&HCluster::cluster)
+        .def("reprNodeIds",registerConverters(&pyReprNodeIds<HCluster>))
+        .def("resultLabels",registerConverters(&pyResultLabels<HCluster>),
+            (
+                python::arg("out")=python::object()
+            )
+        )
+        ;
+
+        // free function
+        python::def("__hierarchicalClustering",registerConverters(&pyHierarchicalClusteringConstructor<ClusterOperator>),
+            python::with_custodian_and_ward_postcall< 0,1 ,
+                    python::return_value_policy<   python::manage_new_object      >  >()  
+        );
+    }
+
+    static const Graph & pyMergeGraphsGraph(const MergeGraph & mg){
+        return mg.graph();
+    }
+
+
+    static MergeGraph * pyMergeGraphConstructor(const GRAPH & graph){
+        return new MergeGraphAdaptor<GRAPH>(graph);
+    }
+
+
+    template<class MG>
+    static NumpyAnyArray pyCurrentLabeling(
+        const MG  & mergeGraph,
+        UInt32NodeArray   resultArray
+    ){
+        resultArray.reshapeIfEmpty(IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(mergeGraph.graph()));
+
+        UInt32NodeArrayMap resultArrayMap(mergeGraph.graph(),resultArray);
+        //std::cout<<"find result labels\n";
+
+        //USETICTOC;
+
+        //TIC;
+        for(NodeIt iter(mergeGraph.graph());iter!=lemon::INVALID;++iter ){
+            resultArrayMap[*iter]=mergeGraph.reprNodeId(mergeGraph.graph().id(*iter));
+        }
+        //TOC;
+        return resultArray;
+    }
+
+
+    template <class classT>
+    void visit(classT& c) const
+    {   
+        // the merge graph itself and factory functions to get a merge graph
+        exportMergeGraph();
+
+        // export the clustering operators
+        exportHierarchicalClusteringOperators();
+
+        // export Hierarchical Clustering (for all  cluster operators)
+        //{
+        //    const std::string operatorName = clsName_ + std::string("MergeGraph") + std::string("NeuroOperator");
+        //    exportHierarchicalClustering<NeuroClusterOperator>(operatorName);
+        //}
+        {
+            const std::string operatorName = clsName_ + std::string("MergeGraph") + std::string("MinEdgeWeightNodeDistOperator");
+            exportHierarchicalClustering<DefaultClusterOperator>(operatorName);
+        }
+        {
+            const std::string operatorName = clsName_ + std::string("MergeGraph") + std::string("PythonOperator");
+            exportHierarchicalClustering<PythonClusterOperator>(operatorName);
+        }
+
+    }
+
+
+
+    static NodeHolder<MergeGraph> pyInactiveEdgesNode(
+        const MergeGraph & mg,
+        const EdgeHolder<MergeGraph> & edge
+    ){
+        return NodeHolder<MergeGraph>(mg,mg.inactiveEdgesNode(edge));
+    }
+
+    static EdgeHolder<MergeGraph> pyReprEdgeID(
+        const MergeGraph & mg,
+        const EdgeHolder<MergeGraph> & edge
+    ){
+        return EdgeHolder<MergeGraph>(mg,mg.reprEdge(edge));
+    }
+    
+
+    static void pyContractEdgeA(
+        MergeGraph & mg,
+        const EdgeHolder<MergeGraph> & edge
+    ){
+        mg.contractEdge(edge);
+    }
+
+    static void pyContractEdgeB(
+        MergeGraph & mg,
+        const EdgeHolder<Graph> & graphEdge
+    ){
+        mg.contractEdge(mg.reprEdge(graphEdge));
+    }
+
+    static bool pyHasEdgeId(
+        MergeGraph & mg,
+        typename MergeGraph::index_type id
+    ){
+        return mg.hasEdgeId(id);
+    }
+
+
+
+    template<class CLUSTER_OP>
+    static HierarchicalClustering<CLUSTER_OP> * pyHierarchicalClusteringConstructor(
+        CLUSTER_OP & clusterOp,
+        const size_t nodeNumStopCond,
+        const bool buildMergeTreeEncoding
+
+
+    ){
+        typename HierarchicalClustering<CLUSTER_OP>::Parameter param;
+        param.nodeNumStopCond_=nodeNumStopCond;
+        param.buildMergeTreeEncoding_=buildMergeTreeEncoding;
+        param.verbose_=true;
+        return new  HierarchicalClustering<CLUSTER_OP>(clusterOp,param);
+    }
+
+
+
+
+    static DefaultClusterOperator * 
+    pyEdgeWeightNodeFeaturesConstructor(
+        MergeGraph &                mergeGraph,
+        FloatEdgeArray              edgeIndicatorMapArray,
+        FloatEdgeArray              edgeSizeMapArray,
+        MultiFloatNodeArray         nodeFeatureMapArray,
+        FloatNodeArray              nodeSizeMapArray,
+        FloatEdgeArray              edgeMinWeightMapArray,
+        UInt32NodeArray             nodeLabelArray,
+        const float                 beta,
+        const metrics::MetricType   nodeDistType,
+        const float                 wardness,
+        const float                 gamma
+    ){
+
+        FloatEdgeArrayMap       edgeIndicatorMap(mergeGraph.graph(),edgeIndicatorMapArray);
+        FloatEdgeArrayMap       edgeSizeMap(mergeGraph.graph(),edgeSizeMapArray);   
+        MultiFloatNodeArrayMap  nodeFeatureMap(mergeGraph.graph(),nodeFeatureMapArray);
+        FloatNodeArrayMap       nodeSizeMap(mergeGraph.graph(),nodeSizeMapArray);
+        FloatEdgeArrayMap       edgeMinWeightMap(mergeGraph.graph(),edgeMinWeightMapArray);
+        UInt32NodeArrayMap      nodeLabelMap(mergeGraph.graph(),nodeLabelArray);
+
+
+        return new DefaultClusterOperator(mergeGraph,
+            edgeIndicatorMap,edgeSizeMap,
+            nodeFeatureMap, nodeSizeMap,
+            edgeMinWeightMap,nodeLabelMap,
+            beta,nodeDistType,wardness, gamma
+        );
+    }
+
+
+
+
+
+
+    static PythonClusterOperator * 
+    pyPythonOperatorConstructor(
+        MergeGraph & mergeGraph,
+        python::object object,
+        const bool useMergeNodeCallback,
+        const bool useMergeEdgesCallback,
+        const bool useEraseEdgeCallback
+    ){
+        return new PythonClusterOperator(mergeGraph,object,useMergeNodeCallback,useMergeEdgesCallback,useEraseEdgeCallback);
+    }   
+
+
+
+    template<class HCLUSTER>
+    static void pyReprNodeIds(
+        const HCLUSTER &     hcluster,
+        NumpyArray<1,UInt32> labels
+    ){
+        for(MultiArrayIndex i=0; i<labels.shape(0); ++i)
+            labels(i)=hcluster.reprNodeId(labels(i));
+    }
+
+
+    template<class HCLUSTER>
+    static NumpyAnyArray pyResultLabels(
+        const HCLUSTER  & hcluster,
+        UInt32NodeArray   resultArray
+    ){
+        resultArray.reshapeIfEmpty(IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(hcluster.graph()));
+
+        UInt32NodeArrayMap resultArrayMap(hcluster.graph(),resultArray);
+        //std::cout<<"find result labels\n";
+
+        //USETICTOC;
+
+        //TIC;
+        for(NodeIt iter(hcluster.graph());iter!=lemon::INVALID;++iter ){
+            resultArrayMap[*iter]=hcluster.mergeGraph().reprNodeId(hcluster.graph().id(*iter));
+        }
+        //TOC;
+        return resultArray;
+    }
+
+    template<class HCLUSTER>
+    static python::tuple mergeTreeEncodingAsNumpyArray(const HCLUSTER & hcluster) {
+        typedef typename HCLUSTER::MergeTreeEncoding      MergeTreeEncoding;
+        typedef typename HCLUSTER::MergeGraphIndexType    MergeGraphIndexType;
+        typedef typename HCLUSTER::ValueType              ValueType;
+        const MergeTreeEncoding & encoding = hcluster.mergeTreeEndcoding();
+        const MergeGraphIndexType numMerges = encoding.size();
+        //CPP BUG?!?
+        NumpyArray<1,ValueType> w = NumpyArray<1,ValueType>(typename NumpyArray<1,ValueType>::difference_type(numMerges));
+        NumpyArray<2,MergeGraphIndexType> indices = NumpyArray<2,MergeGraphIndexType>(typename NumpyArray<2,MergeGraphIndexType>::difference_type(numMerges,3));
+        for(MergeGraphIndexType m=0;m<numMerges;++m){
+            w(int(m))=encoding[m].w_;
+            indices(m,0)=encoding[m].a_;
+            indices(m,1)=encoding[m].b_;
+            indices(m,2)=encoding[m].r_;
+        }
+        return python::make_tuple(indices,w);
+    } 
+
+
+    template<class HCLUSTER>
+    static python::tuple leafNodeIdsAsNumpyArray(
+        const HCLUSTER &            hcluster,
+        const typename HCLUSTER::MergeGraphIndexType treeNodeId,
+        NumpyArray<1,UInt32>  leafes  = (NumpyArray<1,UInt32>())
+    ) {        
+        leafes.reshapeIfEmpty( typename NumpyArray<1,UInt32>::difference_type( hcluster.graph().nodeNum()) );
+        if(leafes.shape(0)!=hcluster.graph().nodeNum()){
+            throw std::runtime_error("out.shape(0) must be equal nodeNum");
+        }
+
+        // todo make leafes size check
+        const size_t leafNum=hcluster.leafNodeIds(treeNodeId,leafes.begin());
+        return python::make_tuple(leafes,leafNum);
+    } 
+
+    /*
+
+    template<class T>
+    static NumpyAnyArray pyRagProjectNodeFeaturesToBaseGraph(
+        const RagGraph &                                         rag,
+        const Graph    &                                         graph,
+        const typename PyNodeMapTraits<Graph,   UInt32>::Array & labelsWhichGeneratedRagArray,
+        const typename PyNodeMapTraits<RagGraph,T     >::Array & ragNodeFeaturesArray,
+        const Int32                                              ignoreLabel=-1,
+        typename PyNodeMapTraits<Graph,T>::Array                 graphNodeFeaturesArray=typename PyNodeMapTraits<Graph,T>::Array() // out
+    ){
+        // reshape out  ( last argument (out) will be reshaped if empty, and #channels is taken from second argument)
+        reshapeNodeMapIfEmpty(graph,ragNodeFeaturesArray,graphNodeFeaturesArray);
+        // numpy arrays => lemon maps 
+        typename PyNodeMapTraits<Graph,   UInt32>::Map labelsWhichGeneratedRagArrayMap(graph, labelsWhichGeneratedRagArray);
+        typename PyNodeMapTraits<RagGraph,T     >::Map ragNodeFeaturesArrayMap(rag,ragNodeFeaturesArray);
+        typename PyNodeMapTraits<Graph,   T     >::Map graphNodeFeaturesArrayMap(graph,graphNodeFeaturesArray);
+        // run algorithm
+        for(typename Graph::NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+            if(ignoreLabel==-1 || static_cast<Int32>(labelsWhichGeneratedRagArrayMap[*iter])!=ignoreLabel)
+                graphNodeFeaturesArrayMap[*iter]=ragNodeFeaturesArrayMap[rag.nodeFromId(labelsWhichGeneratedRagArrayMap[*iter])];
+            else{
+                // ???
+                // aks U. Koethe here
+            }
+        }
+        return graphNodeFeaturesArray; // out
+    }
+    */
+private:
+    std::string clsName_;
+};
+
+
+
+
+} // end namespace vigra
+
+#endif // VIGRA_EXPORT_GRAPH_HIERARCHICAL_CLUSTERING_VISTITOR_HXX
diff --git a/vigranumpy/src/core/export_graph_rag_visitor.hxx b/vigranumpy/src/core/export_graph_rag_visitor.hxx
new file mode 100644
index 0000000..9cbe58a
--- /dev/null
+++ b/vigranumpy/src/core/export_graph_rag_visitor.hxx
@@ -0,0 +1,950 @@
+#ifndef VIGRA_EXPORT_GRAPH_RAG_VISITOR_HXX
+#define VIGRA_EXPORT_GRAPH_RAG_VISITOR_HXX
+//#define NO_IMPORT_ARRAY
+
+/*boost python before anything else*/
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+
+/*std*/
+#include <sstream>
+#include <string>
+
+/*vigra*/
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/graphs.hxx>
+#include <vigra/graph_maps.hxx>
+#include <vigra/python_graph.hxx>
+#include <vigra/graph_algorithms.hxx>
+#include <vigra/metrics.hxx>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/error.hxx>
+#include <vigra/graph_rag_project_back.hxx>
+namespace python = boost::python;
+
+namespace vigra{
+
+
+
+template<class GRAPH>
+class LemonGraphRagVisitor 
+:   public boost::python::def_visitor<LemonGraphRagVisitor<GRAPH> >
+{
+public:
+
+    friend class def_visitor_access;
+
+    typedef GRAPH Graph;
+    typedef AdjacencyListGraph RagGraph;
+
+    typedef LemonGraphRagVisitor<GRAPH> VisitorType;
+    // Lemon Graph Typedefs
+    
+    typedef typename Graph::index_type       index_type;
+    typedef typename Graph::Edge             Edge;
+    typedef typename Graph::Node             Node;
+    typedef typename Graph::Arc              Arc;
+    typedef typename Graph::NodeIt           NodeIt;
+    typedef typename Graph::EdgeIt           EdgeIt;
+    typedef typename Graph::ArcIt            ArcIt;
+
+    typedef typename RagGraph::Edge             RagEdge;
+    typedef typename RagGraph::Node             RagNode;
+    typedef typename RagGraph::Arc              RagArc;
+    typedef typename RagGraph::OutArcIt         RagOutArcIt;
+    typedef typename RagGraph::NodeIt           RagNodeIt;
+    typedef typename RagGraph::EdgeIt           RagEdgeIt;
+    typedef typename RagGraph::ArcIt            RagArcIt;
+
+
+    typedef EdgeHolder<Graph> PyEdge;
+    typedef NodeHolder<Graph> PyNode;
+    typedef  ArcHolder<Graph> PyArc;
+
+    typedef NodeHolder<RagGraph> PyRagNode;
+
+    // predefined array (for map usage)
+    const static unsigned int EdgeMapDim = IntrinsicGraphShape<Graph>::IntrinsicEdgeMapDimension;
+    const static unsigned int NodeMapDim = IntrinsicGraphShape<Graph>::IntrinsicNodeMapDimension;
+
+    typedef NumpyArray<EdgeMapDim,   Singleband<float > > FloatEdgeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<float > > FloatNodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<UInt32> > UInt32NodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<Int32 > > Int32NodeArray;
+    typedef NumpyArray<NodeMapDim +1,Multiband <float > > MultiFloatNodeArray;
+
+    typedef NumpyScalarEdgeMap<Graph,FloatEdgeArray>         FloatEdgeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,FloatNodeArray>         FloatNodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,UInt32NodeArray>        UInt32NodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,Int32NodeArray>         Int32NodeArrayMap;
+    typedef NumpyMultibandNodeMap<Graph,MultiFloatNodeArray> MultiFloatNodeArrayMap;
+
+
+   
+    const static unsigned int RagEdgeMapDim = IntrinsicGraphShape<RagGraph>::IntrinsicEdgeMapDimension;
+    const static unsigned int RagNodeMapDim = IntrinsicGraphShape<RagGraph>::IntrinsicNodeMapDimension;
+
+    typedef NumpyArray<RagEdgeMapDim,   Singleband<float > > RagFloatEdgeArray;
+    typedef NumpyArray<RagNodeMapDim,   Singleband<float > > RagFloatNodeArray;
+    typedef NumpyArray<RagNodeMapDim,   Singleband<UInt32> > RagUInt32NodeArray;
+    typedef NumpyArray<RagNodeMapDim,   Singleband<Int32 > > RagInt32NodeArray;
+    typedef NumpyArray<RagNodeMapDim +1,Multiband <float > > RagMultiFloatNodeArray;
+    typedef NumpyArray<RagEdgeMapDim +1,Multiband <float > > RagMultiFloatEdgeArray;
+
+    typedef NumpyScalarEdgeMap<RagGraph,RagFloatEdgeArray>         RagFloatEdgeArrayMap;
+    typedef NumpyScalarNodeMap<RagGraph,RagFloatNodeArray>         RagFloatNodeArrayMap;
+    typedef NumpyScalarNodeMap<RagGraph,RagUInt32NodeArray>        RagUInt32NodeArrayMap;
+    typedef NumpyScalarNodeMap<RagGraph,RagInt32NodeArray>         RagInt32NodeArrayMap;
+    typedef NumpyMultibandNodeMap<RagGraph,RagMultiFloatNodeArray> RagMultiFloatNodeArrayMap;
+
+
+
+    typedef typename RagGraph:: template EdgeMap< std::vector<Edge> > RagAffiliatedEdges;
+    typedef std::vector<Edge> EdgeVec;
+
+    typedef typename GraphDescriptorToMultiArrayIndex<Graph>::IntrinsicNodeMapShape NodeCoordinate;
+    typedef NumpyArray<1,NodeCoordinate>  NodeCoorinateArray;
+
+    LemonGraphRagVisitor(const std::string clsName)
+    :clsName_(clsName){
+
+    }
+
+    void exportRagAffiliatedEdges()const{
+
+        const std::string hyperEdgeMapNamClsName = clsName_ + std::string("RagAffiliatedEdges");
+        python::class_<RagAffiliatedEdges>(hyperEdgeMapNamClsName.c_str(),python::init<const RagGraph &>())
+                .def("getUVCoordinates",registerConverters(&getUVCoordinatesArray))
+        ;
+
+    }
+
+
+    template <class classT>
+    void visit(classT& c) const
+    {   
+
+        // something like RagEdgeMap< std::vector< Edge > >
+        exportRagAffiliatedEdges();
+
+        // make the region adjacency graph
+        python::def("_regionAdjacencyGraph",registerConverters(&pyMakeRegionAdjacencyGraph),
+            python::return_value_policy<  python::manage_new_object >()
+        );
+
+
+
+        // on the fly rag edge mean 
+        {
+
+
+            typedef OnTheFlyEdgeMap2<
+                Graph, typename PyNodeMapTraits<Graph,float>::Map,
+                MeanFunctor<float>, float
+            > ImplicitEdgeMap;
+
+            
+            python::def("_ragEdgeFeatures",
+                registerConverters(
+                    &pyRagEdgeMeanFromImplicit< float, float, ImplicitEdgeMap >
+                ),
+                (
+                    python::arg("rag"),
+                    python::arg("graph"),
+                    python::arg("affiliatedEdges"),
+                    python::arg("edgeFeatures"),
+                    python::arg("accumulator"),
+                    python::arg("out")=python::object()
+                )
+            );
+
+        }
+
+        
+        // explicit rag features
+        python::def("_ragEdgeFeaturesMb",registerConverters(&pyRagEdgeFeaturesMb<Multiband<float> >),
+            (
+                python::arg("rag"),
+                python::arg("graph"),
+                python::arg("affiliatedEdges"),
+                python::arg("edgeFeatures"),
+                python::arg("edgeSizes"),
+                python::arg("acc"),
+                python::arg("out")=python::object()
+            )
+        );
+
+
+        // explicit rag features
+        python::def("_ragEdgeFeatures",registerConverters(&pyRagEdgeFeatures<Singleband<float> >),
+            (
+                python::arg("rag"),
+                python::arg("graph"),
+                python::arg("affiliatedEdges"),
+                python::arg("edgeFeatures"),
+                python::arg("edgeSizes"),
+                python::arg("acc"),
+                python::arg("out")=python::object()
+            )
+        );
+
+        python::def("_ragFindEdges",registerConverters(&pyRagFindEdges<Singleband<float> >),
+            (
+                python::arg("rag"),
+                python::arg("graph"),
+                python::arg("affiliatedEdges"),
+                python::arg("labels"),
+                python::arg("node")
+            )
+        );
+
+        python::def("_ragNodeFeatures",registerConverters(&pyRagNodeFeaturesMultiband),
+            (
+                python::arg("rag"),
+                python::arg("graph"),
+                python::arg("labels"),
+                python::arg("nodeFeatures"),
+                python::arg("nodeSizes"),
+                python::arg("acc"),
+                python::arg("ignoreLabel")=-1,
+                python::arg("out")=python::object()
+            )
+        );
+        python::def("_ragNodeFeatures",registerConverters(&pyRagNodeFeaturesSingleband),
+            (
+                python::arg("rag"),
+                python::arg("graph"),
+                python::arg("labels"),
+                python::arg("nodeFeatures"),
+                python::arg("nodeSizes"),
+                python::arg("acc"),
+                python::arg("ignoreLabel")=-1,
+                python::arg("out")=python::object()
+            )
+        );
+
+        python::def("_ragNodeSize",registerConverters(&pyRagNodeSize),
+            (
+                python::arg("rag"),
+                python::arg("graph"),
+                python::arg("labels"),
+                python::arg("ignoreLabel")=-1,
+                python::arg("out")=python::object()
+            )
+        );
+        python::def("_ragEdgeSize",registerConverters(&pyRagEdgeSize),
+            (
+                python::arg("rag"),
+                python::arg("affiliatedEdges"),
+                python::arg("out")=python::object()
+            )
+        );
+
+
+        python::def("_ragProjectGroundTruth",registerConverters(& pyProjectGroundTruth),
+            (
+                python::arg("rag"),
+                python::arg("graph"),
+                python::arg("labels"),
+                python::arg("gt"),
+                python::arg("ragGt")=python::object(),
+                python::arg("ragGtQuality")=python::object()
+            )
+        );
+
+        python::def("_pyAccNodeSeeds",registerConverters(&pyAccNodeSeeds),
+            (
+                python::arg("rag"),
+                python::arg("graph"),
+                python::arg("labels"),
+                python::arg("seeds"),
+                python::arg("out")=python::object()
+            )
+        );
+
+
+        exportPyRagProjectNodeFeaturesToBaseGraph< Singleband<float > >();
+        exportPyRagProjectNodeFeaturesToBaseGraph< Singleband<UInt32> >();
+        exportPyRagProjectNodeFeaturesToBaseGraph< Multiband< float > >();
+        exportPyRagProjectNodeFeaturesToBaseGraph< Multiband< UInt32> >();
+
+    }
+
+
+
+    static NumpyAnyArray getUVCoordinatesArray(
+        const RagAffiliatedEdges & vecVec, 
+        const Graph & graph,
+        const size_t ragEdgeIndex 
+    ){
+        const size_t pseudoDim = IntrinsicGraphShape<Graph>::IntrinsicNodeMapDimension;
+        typedef typename GraphDescriptorToMultiArrayIndex<Graph>::IntrinsicNodeMapShape Shape;
+
+        const size_t nEdges = vecVec[ragEdgeIndex].size();
+        vigra::TinyVector<MultiArrayIndex, 2> shape(nEdges,pseudoDim*2);
+        NumpyArray<2, UInt32> coords(shape);
+
+
+
+        for(size_t e=0; e<nEdges; ++e){
+            const Edge edge = vecVec[ragEdgeIndex][e];
+            const Node u = graph.u(edge);
+            const Node v = graph.v(edge);
+            const Shape uCoord = GraphDescriptorToMultiArrayIndex<Graph>::intrinsicNodeCoordinate(graph, u);
+            const Shape vCoord = GraphDescriptorToMultiArrayIndex<Graph>::intrinsicNodeCoordinate(graph, v);
+
+            for(size_t i=0; i<pseudoDim; ++i)
+                coords(e, i) = uCoord[i];
+            for(size_t i=pseudoDim; i<2*pseudoDim; ++i)
+                coords(e, i) = vCoord[i-pseudoDim];
+        }
+        return coords;
+    }
+
+
+
+    static NumpyAnyArray pyAccNodeSeeds(
+        const RagGraph &           rag,
+        const Graph &              graph,
+        UInt32NodeArray            labelsArray,
+        UInt32NodeArray            seedsArray,
+        typename PyNodeMapTraits<RagGraph, UInt32>::Array  ragSeedsArray=RagUInt32NodeArray()
+    ){
+        ragSeedsArray.reshapeIfEmpty(TaggedGraphShape<RagGraph>::taggedNodeMapShape(rag));
+        std::fill(ragSeedsArray.begin(),ragSeedsArray.end(),0);
+
+        UInt32NodeArrayMap labelsArrayMap(graph,labelsArray);
+        UInt32NodeArrayMap seedsArrayMap(graph,seedsArray);
+
+        typename PyNodeMapTraits<RagGraph, UInt32>::Map ragSeedsArrayMap(rag, ragSeedsArray);
+
+
+        for(NodeIt iter(graph); iter!=lemon::INVALID; ++iter){
+            const UInt32 label = labelsArrayMap[*iter];
+            const UInt32 seed  = seedsArrayMap[*iter];
+            if(seed!=0){
+                RagNode node = rag.nodeFromId(label);
+                ragSeedsArrayMap[node] = seed;
+            } 
+        }
+
+        return ragSeedsArray;
+    }
+
+
+
+
+    static python::tuple 
+    pyProjectGroundTruth(
+        const RagGraph &    rag,
+        const Graph &       baseGraph,
+        UInt32NodeArray     baseGraphRagLabels,
+        UInt32NodeArray     baseGraphGt,
+        RagUInt32NodeArray  ragGt,
+        RagFloatNodeArray   ragGtQt
+    ){
+
+        // reshape both output arrays
+        ragGt.reshapeIfEmpty(TaggedGraphShape<RagGraph>::taggedNodeMapShape(rag));
+        ragGtQt.reshapeIfEmpty(TaggedGraphShape<RagGraph>::taggedNodeMapShape(rag));
+
+        // make lemon maps
+        UInt32NodeArrayMap baseGraphRagLabelsMap(baseGraph, baseGraphRagLabels);
+        UInt32NodeArrayMap baseGraphGtMap(baseGraph, baseGraphGt);
+        RagUInt32NodeArrayMap ragGtMap(rag, ragGt);
+        RagFloatNodeArrayMap ragGtQtMap(rag, ragGtQt);
+
+        // call algorithm
+        projectGroundTruth(rag, baseGraph, baseGraphRagLabelsMap,
+                           baseGraphGtMap, ragGtMap, ragGtQtMap);
+
+
+        return python::make_tuple(ragGt, ragGtQt);
+    }
+
+
+    static RagAffiliatedEdges * pyMakeRegionAdjacencyGraph(
+        const Graph &   graph,
+        UInt32NodeArray labelsArray,
+        RagGraph &      rag,
+        const Int32 ignoreLabel=-1
+    ){
+        // numpy arrays => lemon maps
+        UInt32NodeArrayMap labelsArrayMap(graph,labelsArray);
+
+        // allocate a new RagAffiliatedEdges
+        RagAffiliatedEdges * affiliatedEdges = new RagAffiliatedEdges(rag);
+
+        // call algorithm itself
+        makeRegionAdjacencyGraph(graph,labelsArrayMap,rag,*affiliatedEdges,ignoreLabel);
+
+        return affiliatedEdges;
+    }
+
+
+    static RagAffiliatedEdges * pyMakeRegionAdjacencyGraphFast(
+        const Graph &   graph,
+        UInt32NodeArray labelsArray,
+        RagGraph &      rag,
+        const UInt32 maxLabel,
+        const UInt32 reserveEdges
+    ){
+        // numpy arrays => lemon maps
+        UInt32NodeArrayMap labelsArrayMap(graph,labelsArray);
+
+        // allocate a new RagAffiliatedEdges
+        RagAffiliatedEdges * affiliatedEdges = new RagAffiliatedEdges(rag);
+
+        // call algorithm itself
+        makeRegionAdjacencyGraphFast(graph,labelsArrayMap,rag,*affiliatedEdges,maxLabel,reserveEdges);
+
+        return affiliatedEdges;
+    }
+
+
+    template<class T>
+    static NumpyAnyArray  pyRagEdgeFeatures(
+        const RagGraph &           rag,
+        const Graph &              graph,
+        const RagAffiliatedEdges & affiliatedEdges,
+        typename PyEdgeMapTraits<Graph,T >::Array edgeFeaturesArray ,
+        typename PyEdgeMapTraits<Graph,T >::Array edgeSizesArray,
+        const std::string &        accumulator,
+        typename PyEdgeMapTraits<RagGraph,T >::Array ragEdgeFeaturesArray
+    ){
+
+        vigra_precondition(rag.edgeNum()>=1,"rag.edgeNum()>=1 is violated");
+
+        vigra_precondition(accumulator==std::string("mean") || accumulator==std::string("sum") || 
+                           accumulator==std::string("min")  || accumulator==std::string("max"),
+            "currently the accumulators are limited to mean and sum and min and max"
+        );
+
+        // resize out
+        ragEdgeFeaturesArray.reshapeIfEmpty(TaggedGraphShape<RagGraph>::taggedEdgeMapShape(rag));
+        std::fill(ragEdgeFeaturesArray.begin(),ragEdgeFeaturesArray.end(),0.0f);
+        // numpy arrays => lemon maps
+        typename PyEdgeMapTraits<Graph   ,T >::Map edgeFeaturesArrayMap(graph,edgeFeaturesArray);
+        typename PyEdgeMapTraits<Graph   ,T >::Map edgeSizesArrayMap(graph,edgeSizesArray);
+        typename PyEdgeMapTraits<RagGraph,T >::Map ragEdgeFeaturesArrayMap(rag,ragEdgeFeaturesArray);
+
+
+        if(accumulator == std::string("mean") ){
+            for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagEdge ragEdge = *iter;
+                const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+                float weightSum=0.0;
+                for(size_t i=0;i<affEdges.size();++i){
+                    const float weight = edgeSizesArrayMap[affEdges[i]];
+                    ragEdgeFeaturesArrayMap[ragEdge]+=weight*edgeFeaturesArrayMap[affEdges[i]];
+                    weightSum+=weight;
+                }
+
+                ragEdgeFeaturesArrayMap[ragEdge]/=weightSum;
+            }
+        }
+        else if( accumulator == std::string("sum")){
+            for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagEdge ragEdge = *iter;
+                const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+                for(size_t i=0;i<affEdges.size();++i){
+                    ragEdgeFeaturesArrayMap[ragEdge]+=edgeFeaturesArrayMap[affEdges[i]];
+                }
+            }
+        }
+        else if(accumulator == std::string("min")){
+            for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagEdge ragEdge = *iter;
+                const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+                float minVal=std::numeric_limits<float>::infinity();
+                for(size_t i=0;i<affEdges.size();++i){
+                    minVal  = std::min(minVal,edgeFeaturesArrayMap[affEdges[i]]);
+                }
+                ragEdgeFeaturesArrayMap[ragEdge]=minVal;
+            }
+        }
+        else if(accumulator == std::string("max")){
+            for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagEdge ragEdge = *iter;
+                const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+                float maxVal=-1.0*std::numeric_limits<float>::infinity();
+                for(size_t i=0;i<affEdges.size();++i){
+                    maxVal  = std::max(maxVal,edgeFeaturesArrayMap[affEdges[i]]);
+                }
+                ragEdgeFeaturesArrayMap[ragEdge]=maxVal;
+            }
+        }
+        else{
+            throw std::runtime_error("not supported accumulator");
+        }
+
+        return ragEdgeFeaturesArray;
+    }
+
+
+    template<class T>
+    static NumpyAnyArray  pyRagEdgeFeaturesMb(
+        const RagGraph &           rag,
+        const Graph &              graph,
+        const RagAffiliatedEdges & affiliatedEdges,
+        typename PyEdgeMapTraits<Graph,T >::Array edgeFeaturesArray ,
+        typename PyEdgeMapTraits<Graph,float >::Array edgeSizesArray,
+        const std::string &        accumulator,
+        typename PyEdgeMapTraits<RagGraph,T >::Array ragEdgeFeaturesArray
+    ){
+
+        vigra_precondition(rag.edgeNum()>=1,"rag.edgeNum()>=1 is violated");
+
+        vigra_precondition(accumulator==std::string("mean") || accumulator==std::string("sum") || 
+                           accumulator==std::string("min")  || accumulator==std::string("max"),
+            "currently the accumulators are limited to mean and sum and min and max"
+        );
+
+
+
+
+        // resize out
+        typename MultiArray<RagEdgeMapDim+1,int>::difference_type outShape;
+        for(size_t d=0;d<RagEdgeMapDim;++d){
+            outShape[d]=IntrinsicGraphShape<RagGraph>::intrinsicEdgeMapShape(rag)[d];
+        }
+        outShape[RagEdgeMapDim]=edgeFeaturesArray.shape(EdgeMapDim);
+
+
+        ragEdgeFeaturesArray.reshapeIfEmpty(   RagMultiFloatEdgeArray::ArrayTraits::taggedShape(outShape,"ec") );
+        std::fill(ragEdgeFeaturesArray.begin(),ragEdgeFeaturesArray.end(),0.0f);
+
+
+
+
+
+        // resize out
+        //ragEdgeFeaturesArray.reshapeIfEmpty(TaggedGraphShape<RagGraph>::taggedEdgeMapShape(rag));
+        std::fill(ragEdgeFeaturesArray.begin(),ragEdgeFeaturesArray.end(),0.0f);
+        // numpy arrays => lemon maps
+        typename PyEdgeMapTraits<Graph   ,T >::Map edgeFeaturesArrayMap(graph,edgeFeaturesArray);
+        typename PyEdgeMapTraits<Graph   ,float >::Map edgeSizesArrayMap(graph,edgeSizesArray);
+        typename PyEdgeMapTraits<RagGraph,T >::Map ragEdgeFeaturesArrayMap(rag,ragEdgeFeaturesArray);
+
+        //typedef typename PyEdgeMapTraits<Graph,float >::Array::value_type ValType;
+
+        if(accumulator == std::string("mean") ){
+            for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagEdge ragEdge = *iter;
+                const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+                float weightSum=0.0;
+                for(size_t i=0;i<affEdges.size();++i){
+                    const float weight = edgeSizesArrayMap[affEdges[i]];
+                    vigra::MultiArray<1,float> val = edgeFeaturesArrayMap[affEdges[i]];
+                    val*=weight;
+                    ragEdgeFeaturesArrayMap[ragEdge]+=val;
+                    weightSum+=weight;
+                }
+                ragEdgeFeaturesArrayMap[ragEdge]/=weightSum;
+            }
+        }
+        else if( accumulator == std::string("sum")){
+            for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagEdge ragEdge = *iter;
+                const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+                for(size_t i=0;i<affEdges.size();++i){
+                    ragEdgeFeaturesArrayMap[ragEdge]+=edgeFeaturesArrayMap[affEdges[i]];
+                }
+            }
+        }
+        else{
+            throw std::runtime_error("not supported accumulator");
+        }
+
+        return ragEdgeFeaturesArray;
+    }
+
+
+    template<class T_PIXEL, class T, class OTF_EDGES>
+    static NumpyAnyArray pyRagEdgeMeanFromImplicit(
+        const RagGraph &           rag,
+        const Graph &              graph,
+        const RagAffiliatedEdges & affiliatedEdges,
+        const OTF_EDGES & otfEdgeMap,
+        const std::string & accumulator,
+        typename PyEdgeMapTraits<RagGraph,T >::Array ragEdgeFeaturesArray
+    ){
+
+        // preconditions
+        vigra_precondition(rag.edgeNum()>=1,"rag.edgeNum()>=1 is violated");
+
+        // resize out
+        ragEdgeFeaturesArray.reshapeIfEmpty(TaggedGraphShape<RagGraph>::taggedEdgeMapShape(rag));
+        
+
+
+        // numpy arrays => lemon maps
+        typename PyEdgeMapTraits<RagGraph,T >::Map ragEdgeFeaturesArrayMap(rag,ragEdgeFeaturesArray);
+
+
+        if(accumulator == std::string("mean") || accumulator == std::string("sum") ){
+            std::fill(ragEdgeFeaturesArray.begin(),ragEdgeFeaturesArray.end(),0.0f);
+            for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagEdge ragEdge = *iter;
+                const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+                for(size_t i=0;i<affEdges.size();++i){
+                    ragEdgeFeaturesArrayMap[ragEdge]+=otfEdgeMap[affEdges[i]];
+                }
+                if(accumulator == std::string("mean")){
+                    ragEdgeFeaturesArrayMap[ragEdge]/=affEdges.size();
+                }
+            }
+        }
+        if(accumulator == std::string("min") ){
+            std::fill(ragEdgeFeaturesArray.begin(),ragEdgeFeaturesArray.end(),std::numeric_limits<float>::infinity());
+            for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagEdge ragEdge = *iter;
+                const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+                for(size_t i=0;i<affEdges.size();++i){
+                    ragEdgeFeaturesArrayMap[ragEdge] = std::min(otfEdgeMap[affEdges[i]], ragEdgeFeaturesArrayMap[ragEdge]);
+                }
+            }
+        }
+        if(accumulator == std::string("max") ){
+            std::fill(ragEdgeFeaturesArray.begin(),ragEdgeFeaturesArray.end(),-1.0f*std::numeric_limits<float>::infinity());
+            for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagEdge ragEdge = *iter;
+                const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+                for(size_t i=0;i<affEdges.size();++i){
+                    ragEdgeFeaturesArrayMap[ragEdge] = std::max(otfEdgeMap[affEdges[i]], ragEdgeFeaturesArrayMap[ragEdge]);
+                }
+            }
+        }
+        
+
+        // return 
+        return ragEdgeFeaturesArray;
+
+    }
+
+
+
+
+    template<class T>
+    static NumpyAnyArray  pyRagFindEdges(
+        const RagGraph &           rag,
+        const Graph &              graph,
+        const RagAffiliatedEdges & affiliatedEdges,
+        UInt32NodeArray            labelsArray,
+        const PyRagNode &          ragNode
+    ){
+        UInt32NodeArrayMap   labelsArrayMap(graph,labelsArray);
+        RagNode node = ragNode;
+        UInt32 nodeLabel = rag.id(node);
+
+        // Get number of points
+        UInt32 nPoints = 0;
+        for (RagOutArcIt iter(rag, node); iter != lemon::INVALID; ++iter) {
+            const RagEdge ragEdge(*iter);
+            const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+            nPoints += affEdges.size();
+        }
+        NumpyArray<2, UInt32> edgePoints(NumpyArray<2, UInt32>::difference_type(nPoints, NodeMapDim));
+
+        // Find edges
+        size_t nNext = 0;
+        for(RagOutArcIt iter(rag, node); iter != lemon::INVALID; ++iter) {
+            const RagEdge ragEdge(*iter);
+            const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+            for (size_t i=0; i<affEdges.size(); ++i) {
+                Node u = graph.u(affEdges[i]);
+                Node v = graph.v(affEdges[i]);
+                UInt32 uLabel = labelsArrayMap[u];
+                UInt32 vLabel = labelsArrayMap[v];
+
+                NodeCoordinate coords;
+                if (uLabel == nodeLabel) {
+                    coords = GraphDescriptorToMultiArrayIndex<Graph>::intrinsicNodeCoordinate(graph, u);
+                } else if (vLabel == nodeLabel) {
+                    coords = GraphDescriptorToMultiArrayIndex<Graph>::intrinsicNodeCoordinate(graph, v);
+                } else {
+                    // If you get here, then there's an error. Maybe print a message?
+                }
+                for(size_t k=0; k<coords.size(); ++k) {
+                    edgePoints(nNext, k) = coords[k];
+                }
+                nNext++;
+            }
+        }
+        return edgePoints;
+    }
+
+
+
+    static NumpyAnyArray  pyRagNodeFeaturesSingleband(
+        const RagGraph &           rag,
+        const Graph &              graph,
+        UInt32NodeArray            labelsArray,
+        FloatNodeArray             nodeFeaturesArray,
+        FloatNodeArray             nodeSizesArray,
+        const std::string &        accumulator,
+        const Int32                ignoreLabel=-1,
+        RagFloatNodeArray          ragNodeFeaturesArray=RagFloatNodeArray()
+    ){
+
+        vigra_precondition(accumulator==std::string("mean") || accumulator==std::string("sum") || 
+                           accumulator==std::string("min")  || accumulator==std::string("max"),
+            "currently the accumulators are limited to mean and sum and min and max "
+        );
+
+        // resize out
+
+        ragNodeFeaturesArray.reshapeIfEmpty(TaggedGraphShape<RagGraph>::taggedNodeMapShape(rag));
+        std::fill(ragNodeFeaturesArray.begin(),ragNodeFeaturesArray.end(),0.0f);
+
+        // numpy arrays => lemon maps
+        UInt32NodeArrayMap   labelsArrayMap(graph,labelsArray);
+        FloatNodeArrayMap    nodeFeaturesArrayMap(graph,nodeFeaturesArray);
+        FloatNodeArrayMap    nodeSizesArrayMap(graph,nodeSizesArray);
+        RagFloatNodeArrayMap ragNodeFeaturesArrayMap(rag,ragNodeFeaturesArray);
+
+        if(accumulator == std::string("mean")){
+            typename RagGraph:: template NodeMap<float> counting(rag,0.0f);
+            for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+                UInt32 l = labelsArrayMap[*iter];
+                if(ignoreLabel==-1 || static_cast<Int32>(l)!=ignoreLabel){
+                    const float  weight = nodeSizesArrayMap[*iter];
+                    const RagNode ragNode   = rag.nodeFromId(l);
+                    ragNodeFeaturesArrayMap[ragNode]+= weight*nodeFeaturesArrayMap[*iter];
+                    counting[ragNode]+=weight;
+                }
+            }
+            for(RagNodeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagNode ragNode   = *iter;
+                ragNodeFeaturesArrayMap[ragNode]/=counting[ragNode];
+            }
+        }
+        else if(accumulator == std::string("sum")){
+            for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+                UInt32 l = labelsArrayMap[*iter];
+                if(ignoreLabel==-1 || static_cast<Int32>(l)!=ignoreLabel){
+                    const RagNode ragNode   = rag.nodeFromId(l);
+                    ragNodeFeaturesArrayMap[ragNode]+=nodeFeaturesArrayMap[*iter];
+                }
+            }
+        }
+        else if(accumulator == std::string("min")){
+            for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+                UInt32 l = labelsArrayMap[*iter];
+                if(ignoreLabel==-1 || static_cast<Int32>(l)!=ignoreLabel){
+                    const RagNode ragNode   = rag.nodeFromId(l);
+                    ragNodeFeaturesArrayMap[ragNode]=std::numeric_limits<float>::infinity();
+                }
+            }
+            for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+                UInt32 l = labelsArrayMap[*iter];
+                if(ignoreLabel==-1 || static_cast<Int32>(l)!=ignoreLabel){
+                    const RagNode ragNode   = rag.nodeFromId(l);
+                    ragNodeFeaturesArrayMap[ragNode]=std::min(nodeFeaturesArrayMap[*iter],ragNodeFeaturesArrayMap[ragNode]);
+                }
+            }
+        }
+        else if(accumulator == std::string("max")){
+            for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+                UInt32 l = labelsArrayMap[*iter];
+                if(ignoreLabel==-1 || static_cast<Int32>(l)!=ignoreLabel){
+                    const RagNode ragNode   = rag.nodeFromId(l);
+                    ragNodeFeaturesArrayMap[ragNode]= -1.0*std::numeric_limits<float>::infinity();
+                }
+            }
+            for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+                UInt32 l = labelsArrayMap[*iter];
+                if(ignoreLabel==-1 || static_cast<Int32>(l)!=ignoreLabel){
+                    const RagNode ragNode   = rag.nodeFromId(l);
+                    ragNodeFeaturesArrayMap[ragNode]=std::max(nodeFeaturesArrayMap[*iter],ragNodeFeaturesArrayMap[ragNode]);
+                }
+            }
+        }
+        else{
+           
+        }
+        return ragNodeFeaturesArray;
+    }
+
+
+    static NumpyAnyArray  pyRagNodeFeaturesMultiband(
+        const RagGraph &           rag,
+        const Graph &              graph,
+        UInt32NodeArray            labelsArray,
+        MultiFloatNodeArray        nodeFeaturesArray,
+        FloatNodeArray             nodeSizesArray,
+        const std::string &        accumulator,
+        const Int32                ignoreLabel=-1,
+        RagMultiFloatNodeArray     ragNodeFeaturesArray=RagMultiFloatNodeArray()
+    ){
+        vigra_precondition(accumulator==std::string("mean") || accumulator==std::string("sum"),
+            "currently the accumulators are limited to mean and sum"
+        );
+
+        // resize out
+        typename MultiArray<RagNodeMapDim+1,int>::difference_type outShape;
+        for(size_t d=0;d<RagNodeMapDim;++d){
+            outShape[d]=IntrinsicGraphShape<RagGraph>::intrinsicNodeMapShape(rag)[d];
+        }
+        outShape[RagNodeMapDim]=nodeFeaturesArray.shape(NodeMapDim);
+
+        ragNodeFeaturesArray.reshapeIfEmpty(   RagMultiFloatNodeArray::ArrayTraits::taggedShape(outShape,"nc") );
+        std::fill(ragNodeFeaturesArray.begin(),ragNodeFeaturesArray.end(),0.0f);
+
+        // numpy arrays => lemon maps
+        UInt32NodeArrayMap        labelsArrayMap(graph,labelsArray);
+        MultiFloatNodeArrayMap    nodeFeaturesArrayMap(graph,nodeFeaturesArray);
+        FloatNodeArrayMap         nodeSizesArrayMap(graph,nodeSizesArray);
+        RagMultiFloatNodeArrayMap ragNodeFeaturesArrayMap(rag,ragNodeFeaturesArray);
+
+        if(accumulator == std::string("mean")){
+            typename RagGraph:: template NodeMap<float> counting(rag,0.0f);
+            for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+                UInt32 l = labelsArrayMap[*iter];
+                if(ignoreLabel==-1 || static_cast<Int32>(l)!=ignoreLabel){
+                    const float weight = nodeSizesArrayMap[*iter];
+                    const RagNode ragNode   = rag.nodeFromId(l);
+                    typename MultiFloatNodeArrayMap::Value feat = nodeFeaturesArrayMap[*iter];
+                    feat*=weight;
+                    ragNodeFeaturesArrayMap[ragNode]+=feat;
+                    counting[ragNode]+=weight;
+                }
+            }
+            for(RagNodeIt iter(rag);iter!=lemon::INVALID;++iter){
+                const RagNode ragNode   = *iter;
+                ragNodeFeaturesArrayMap[ragNode]/=counting[ragNode];
+            }
+        }
+        else if(accumulator == std::string("sum")){
+            for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+                UInt32 l = labelsArrayMap[*iter];
+                if(ignoreLabel==-1 || static_cast<Int32>(l)!=ignoreLabel){
+                    const RagNode ragNode   = rag.nodeFromId(l);
+                    ragNodeFeaturesArrayMap[ragNode]+=nodeFeaturesArrayMap[*iter];
+                }
+            }
+        }
+        else{
+            throw std::runtime_error("for multiband only mean and sum is implemented");
+        }
+        return ragNodeFeaturesArray;
+    }
+
+    static NumpyAnyArray  pyRagNodeSize(
+        const RagGraph &           rag,
+        const Graph &              graph,
+        UInt32NodeArray            labelsArray,
+        const Int32                ignoreLabel=-1,
+        RagFloatNodeArray          ragNodeSizeArray=RagFloatNodeArray()
+    ){
+        // resize out
+        ragNodeSizeArray.reshapeIfEmpty(TaggedGraphShape<RagGraph>::taggedNodeMapShape(rag));
+        std::fill(ragNodeSizeArray.begin(),ragNodeSizeArray.end(),0.0f);
+
+        // numpy arrays => lemon maps
+        UInt32NodeArrayMap labelsArrayMap(graph,labelsArray);
+        RagFloatNodeArrayMap ragNodeSizeArrayMap(rag,ragNodeSizeArray);
+        for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+            UInt32 l = labelsArrayMap[*iter];
+            if(ignoreLabel==-1 || static_cast<Int32>(l)!=ignoreLabel){
+                const RagNode ragNode   = rag.nodeFromId(l);
+                ragNodeSizeArrayMap[ragNode]+=1.0f;
+            }
+        }
+
+        return ragNodeSizeArray;
+    }
+
+    static NumpyAnyArray  pyRagEdgeSize(
+        const RagGraph &           rag,
+        const RagAffiliatedEdges & affiliatedEdges,
+        RagFloatEdgeArray          ragEdgeFeaturesArray
+    ){
+        // reshape out
+        ragEdgeFeaturesArray.reshapeIfEmpty(TaggedGraphShape<RagGraph>::taggedEdgeMapShape(rag));
+        // numpy arrays => lemon maps
+        RagFloatEdgeArrayMap ragEdgeFeaturesArrayMap(rag,ragEdgeFeaturesArray);
+
+        for(RagEdgeIt iter(rag);iter!=lemon::INVALID;++iter){
+            const RagEdge ragEdge = *iter;
+            const std::vector<Edge> & affEdges = affiliatedEdges[ragEdge];
+            ragEdgeFeaturesArrayMap[ragEdge]=static_cast<float>(affEdges.size());
+        }
+        return ragEdgeFeaturesArray;
+    }
+
+
+
+    template<class T>
+    static void exportPyRagProjectNodeFeaturesToBaseGraph(){
+        python::def("_ragProjectNodeFeaturesToBaseGraph",
+            registerConverters(  &pyRagProjectNodeFeaturesToBaseGraph< T > ),
+            (
+                python::arg("rag"),
+                python::arg("baseGraph"),
+                python::arg("baseGraphLabels"),
+                python::arg("ragNodeFeatures"),
+                python::arg("ignoreLabel")=-1,
+                python::arg("out")=python::object()
+            )
+        );
+    }
+
+    template<class T>
+    static NumpyAnyArray pyRagProjectNodeFeaturesToBaseGraph(
+        const RagGraph &                                         rag,
+        const Graph    &                                         graph,
+        const typename PyNodeMapTraits<Graph,   UInt32>::Array & labelsWhichGeneratedRagArray,
+        const typename PyNodeMapTraits<RagGraph,T     >::Array & ragNodeFeaturesArray,
+        const Int32                                              ignoreLabel=-1,
+        typename PyNodeMapTraits<Graph,T>::Array                 graphNodeFeaturesArray=(typename PyNodeMapTraits<Graph,T>::Array()) // out
+    ){
+
+        TaggedShape ragNodeFeaturesArrayShape = ragNodeFeaturesArray.taggedShape();
+        TaggedShape graphNodeFeaturesArrayShape = TaggedGraphShape<Graph>::taggedNodeMapShape(graph);
+        if(ragNodeFeaturesArrayShape.hasChannelAxis()){
+            graphNodeFeaturesArrayShape.setChannelCount(ragNodeFeaturesArrayShape.channelCount());
+        }
+        graphNodeFeaturesArray.reshapeIfEmpty(graphNodeFeaturesArrayShape);
+
+
+        // reshape out  ( last argument (out) will be reshaped if empty, and #channels is taken from second argument)
+        //reshapeNodeMapIfEmpty(graph,ragNodeFeaturesArray,graphNodeFeaturesArray);
+        // numpy arrays => lemon maps 
+        typename PyNodeMapTraits<Graph,   UInt32>::Map labelsWhichGeneratedRagArrayMap(graph, labelsWhichGeneratedRagArray);
+        typename PyNodeMapTraits<RagGraph,T     >::Map ragNodeFeaturesArrayMap(rag,ragNodeFeaturesArray);
+        typename PyNodeMapTraits<Graph,   T     >::Map graphNodeFeaturesArrayMap(graph,graphNodeFeaturesArray);
+        
+
+        projectBack(rag, graph, ignoreLabel, labelsWhichGeneratedRagArrayMap, 
+                    ragNodeFeaturesArrayMap, graphNodeFeaturesArrayMap);
+
+
+        /*
+
+        // run algorithm
+        for(typename Graph::NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+            if(ignoreLabel==-1 || static_cast<Int32>(labelsWhichGeneratedRagArrayMap[*iter])!=ignoreLabel)
+                graphNodeFeaturesArrayMap[*iter]=ragNodeFeaturesArrayMap[rag.nodeFromId(labelsWhichGeneratedRagArrayMap[*iter])];
+            else{
+                // do nothing
+            }
+        }
+        */
+        return graphNodeFeaturesArray; // out
+        
+    }
+
+private:
+    std::string clsName_;
+};
+
+
+
+
+
+
+} // end namespace vigra
+
+#endif // VIGRA_EXPORT_GRAPH_RAG_VISITOR_HXX
diff --git a/vigranumpy/src/core/export_graph_shortest_path_visitor.hxx b/vigranumpy/src/core/export_graph_shortest_path_visitor.hxx
new file mode 100644
index 0000000..0d38b74
--- /dev/null
+++ b/vigranumpy/src/core/export_graph_shortest_path_visitor.hxx
@@ -0,0 +1,348 @@
+#ifndef VIGRA_EXPORT_GRAPH_SHORTEST_PATH_VISITOR_HXX
+#define VIGRA_EXPORT_GRAPH_SHORTEST_PATH_VISITOR_HXX
+//#define NO_IMPORT_ARRAY
+
+/*boost python before anything else*/
+#include <boost/python.hpp>
+
+/*std*/
+#include <sstream>
+#include <string>
+
+/*vigra*/
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/graphs.hxx>
+#include <vigra/graph_maps.hxx>
+#include <vigra/python_graph.hxx>
+#include <vigra/graph_algorithms.hxx>
+#include <vigra/metrics.hxx>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/error.hxx>
+namespace python = boost::python;
+
+namespace vigra{
+
+
+template<class GRAPH,class PREDECESSORS,class IDS_ARRAY>
+void pathIds(
+    const GRAPH & g,
+    const typename  GRAPH::Node source,
+    const typename  GRAPH::Node target,
+    const PREDECESSORS & predecessors,
+    IDS_ARRAY & ids
+){
+    if(predecessors[target]!=lemon::INVALID){
+
+        ids(0)=g.id(target);
+        typename GRAPH::Node currentNode = target;
+        size_t length=1;
+        while(currentNode!=source){
+            currentNode=predecessors[currentNode];
+            ids(length)=g.id(currentNode);
+            length+=1;
+        }
+        // reverse such ids[0]==g.id(source)
+        std::reverse(ids.begin(),ids.begin()+length);
+    }
+}
+
+template<class GRAPH,class PREDECESSORS,class COORDINATE_ARRAY>
+void pathCoordinates(
+    const GRAPH & g,
+    const typename  GRAPH::Node source,
+    const typename  GRAPH::Node target,
+    const PREDECESSORS & predecessors,
+    COORDINATE_ARRAY & coords
+){
+    typedef GraphDescriptorToMultiArrayIndex<GRAPH> DescToCoord;
+    if(predecessors[target]!=lemon::INVALID){
+        coords(0)=DescToCoord::intrinsicNodeCoordinate(g,target);
+        typename GRAPH::Node currentNode = target;
+        size_t length=1;
+        while(currentNode!=source){
+            currentNode=predecessors[currentNode];
+            coords(length)=DescToCoord::intrinsicNodeCoordinate(g,currentNode);
+            length+=1;
+        }
+        // reverse such ids[0]==DescToCoord::intrinsicNodeCoordinate(g,source);
+        std::reverse(coords.begin(),coords.begin()+length);
+    }
+}
+
+
+
+
+
+
+template<class GRAPH>
+class LemonGraphShortestPathVisitor 
+:   public boost::python::def_visitor<LemonGraphShortestPathVisitor<GRAPH> >
+{
+public:
+
+    friend class def_visitor_access;
+
+    typedef GRAPH Graph;
+
+    typedef LemonGraphShortestPathVisitor<GRAPH> VisitorType;
+    // Lemon Graph Typedefs
+    
+    typedef typename Graph::index_type       index_type;
+    typedef typename Graph::Edge             Edge;
+    typedef typename Graph::Node             Node;
+    typedef typename Graph::Arc              Arc;
+
+    typedef typename Graph::NodeIt              NodeIt;
+    typedef typename Graph::EdgeIt              EdgeIt;
+    typedef typename Graph::ArcIt               ArcIt;
+
+
+    typedef EdgeHolder<Graph> PyEdge;
+    typedef NodeHolder<Graph> PyNode;
+    typedef  ArcHolder<Graph> PyArc;
+
+
+    // predefined array (for map usage)
+    const static unsigned int EdgeMapDim = IntrinsicGraphShape<Graph>::IntrinsicEdgeMapDimension;
+    const static unsigned int NodeMapDim = IntrinsicGraphShape<Graph>::IntrinsicNodeMapDimension;
+
+    typedef NumpyArray<EdgeMapDim,   Singleband<float > > FloatEdgeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<float > > FloatNodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<UInt32> > UInt32NodeArray;
+    typedef NumpyArray<NodeMapDim,   Singleband<Int32 > > Int32NodeArray;
+    typedef NumpyArray<NodeMapDim +1,Multiband <float > > MultiFloatNodeArray;
+
+    typedef NumpyScalarEdgeMap<Graph,FloatEdgeArray>         FloatEdgeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,FloatNodeArray>         FloatNodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,UInt32NodeArray>        UInt32NodeArrayMap;
+    typedef NumpyScalarNodeMap<Graph,Int32NodeArray>         Int32NodeArrayMap;
+    typedef NumpyMultibandNodeMap<Graph,MultiFloatNodeArray> MultiFloatNodeArrayMap;
+
+
+    typedef ShortestPathDijkstra<Graph,float> ShortestPathDijkstraType;
+
+
+    typedef OnTheFlyEdgeMap2<
+        Graph, typename PyNodeMapTraits<Graph,float>::Map,
+        MeanFunctor<float>, float
+    > ImplicitEdgeMap;
+
+
+    typedef typename GraphDescriptorToMultiArrayIndex<Graph>::IntrinsicNodeMapShape NodeCoordinate;
+    typedef NumpyArray<1,NodeCoordinate>  NodeCoorinateArray;
+
+    LemonGraphShortestPathVisitor(const std::string clsName)
+    :clsName_(clsName){
+
+    }
+
+    void exportShortestPathAlgorithms()const{
+        // class based algorithms (with factories):
+        // - ShortestPathDijkstra
+        const std::string dijkstraClsName = std::string("ShortestPathDijkstra")+clsName_;
+        python::class_<ShortestPathDijkstraType, boost::noncopyable >(dijkstraClsName.c_str(),python::init<const Graph &>())
+        .def("run",registerConverters(&runShortestPathNoTarget),
+            (
+                python::arg("edgeWeights"),
+                python::arg("source")
+            )
+        )
+        .def("run",registerConverters(&runShortestPath),
+            (
+                python::arg("edgeWeights"),
+                python::arg("source"),
+                python::arg("target")
+            )
+        )
+
+        .def("run",registerConverters(&runShortestPathImplicit),
+            (
+                python::arg("edgeWeights"),
+                python::arg("source")
+            )
+        )
+        .def("run",registerConverters(&runShortestPathNoTargetImplicit),
+            (
+                python::arg("edgeWeights"),
+                python::arg("source"),
+                python::arg("target")
+            )
+        )
+        .def("nodeIdPath",registerConverters(&makeNodeIdPath),
+            (
+                python::arg("target"),
+                python::arg("out")=python::object()
+            ) 
+        )
+        .def("nodeCoordinatePath",registerConverters(&makeNodeCoordinatePath),
+            (
+                python::arg("target"),
+                python::arg("out")=python::object()
+            ) 
+        )
+        .def("distance",&pyShortestPathSingleDist,
+            (
+                python::arg("target")
+            )
+        )
+        .def("distances",registerConverters(&pyShortestPathDistance),
+            (
+                python::arg("out")=python::object()
+            )
+        )
+        .def("predecessors",registerConverters(&pyShortestPathPredecessors),
+            (
+                python::arg("out")=python::object()
+            )
+        )
+        ;
+
+        python::def("_shortestPathDijkstra",&pyShortestPathDijkstraTypeFactory,
+            python::return_value_policy<python::manage_new_object>() 
+        );
+
+    }
+
+    std::string clsName_;
+    template <class classT>
+    void visit(classT& c) const
+    {   
+        // - Dijkstra
+        exportShortestPathAlgorithms();
+    }
+
+        static ShortestPathDijkstraType * pyShortestPathDijkstraTypeFactory(const Graph & g){
+        return new ShortestPathDijkstraType(g);
+    }
+
+    static NumpyAnyArray pyShortestPathDistance(
+        const ShortestPathDijkstraType & sp,
+        FloatNodeArray distanceArray = FloatNodeArray()
+    ){
+        // reshape output
+        distanceArray.reshapeIfEmpty(  IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(sp.graph()));
+
+        // numpy arrays => lemon maps
+        FloatNodeArrayMap distanceArrayMap(sp.graph(),distanceArray);
+
+        copyNodeMap(sp.graph(),sp.distances(),distanceArrayMap);
+
+        return distanceArray;
+    }
+
+    static float pyShortestPathSingleDist(
+        const ShortestPathDijkstraType & sp,
+        const PyNode & target
+    ){
+        return sp.distance(target);
+    }
+
+
+    static NumpyAnyArray pyShortestPathPredecessors(
+        const ShortestPathDijkstraType & sp,
+        Int32NodeArray predecessorsArray = FloatNodeArray()
+    ){
+        // reshape output
+        predecessorsArray.reshapeIfEmpty(  IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(sp.graph()));
+
+        // numpy arrays => lemon maps
+        Int32NodeArrayMap predecessorsArrayMap(sp.graph(),predecessorsArray);
+
+        for(NodeIt n(sp.graph());n!=lemon::INVALID;++n){
+            const Node pred = sp.predecessors()[*n];
+            predecessorsArrayMap[*n]= (pred!=lemon::INVALID ? sp.graph().id(pred) : -1);
+        }
+        return predecessorsArray;
+    }
+
+
+    static NumpyAnyArray makeNodeIdPath(
+        const ShortestPathDijkstraType & sp,
+        PyNode target,
+        NumpyArray<1,Singleband<UInt32> > nodeIdPath = (NumpyArray<1,Singleband<UInt32> >())
+    ){
+        const typename  ShortestPathDijkstraType::PredecessorsMap & predMap = sp.predecessors();
+        const Node source = sp.source();
+        //Node currentNode = target; 
+        // comput length of the path
+        const size_t length = pathLength(Node(source),Node(target),predMap);
+        nodeIdPath.reshapeIfEmpty(typename NumpyArray<1,Singleband<UInt32> >::difference_type(length));
+        pathIds(sp.graph(),source,target,predMap,nodeIdPath);
+        return nodeIdPath;
+        
+    }
+
+    static NumpyAnyArray makeNodeCoordinatePath(
+        const ShortestPathDijkstraType & sp,
+        PyNode target,
+        NodeCoorinateArray nodeCoordinates = NodeCoorinateArray()
+    ){
+        const typename  ShortestPathDijkstraType::PredecessorsMap & predMap = sp.predecessors();
+        const Node source = sp.source();
+        // comput length of the path
+        const size_t length = pathLength(Node(source),Node(target),predMap);
+        nodeCoordinates.reshapeIfEmpty(typename NumpyArray<1,Singleband<UInt32> >::difference_type(length));
+        pathCoordinates(sp.graph(),source,target,predMap,nodeCoordinates);
+        return nodeCoordinates;
+    }
+
+    static void runShortestPath(
+        ShortestPathDijkstraType & sp,
+        FloatEdgeArray edgeWeightsArray,
+        PyNode source,
+        PyNode target
+    ){
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap edgeWeightsArrayMap(sp.graph(),edgeWeightsArray);
+
+        // run algorithm itself
+        sp.run(edgeWeightsArrayMap,source,target);
+    }
+
+    static void runShortestPathNoTarget(
+        ShortestPathDijkstraType & sp,
+        FloatEdgeArray edgeWeightsArray,
+        PyNode source
+    ){
+        // numpy arrays => lemon maps
+        FloatEdgeArrayMap edgeWeightsArrayMap(sp.graph(),edgeWeightsArray);
+
+        // run algorithm itself
+        sp.run(edgeWeightsArrayMap,source);
+    }
+
+
+        static void runShortestPathImplicit(
+        ShortestPathDijkstraType & sp,
+        const ImplicitEdgeMap & edgeWeights,
+        PyNode source,
+        PyNode target
+    ){
+        // numpy arrays => lemon maps
+        //FloatEdgeArrayMap edgeWeightsArrayMap(sp.graph(),edgeWeightsArray);
+
+        // run algorithm itself
+        sp.run(edgeWeights,source,target);
+    }
+
+    static void runShortestPathNoTargetImplicit(
+        ShortestPathDijkstraType & sp,
+        const ImplicitEdgeMap & edgeWeights,
+        PyNode source
+    ){
+        // numpy arrays => lemon maps
+        //FloatEdgeArrayMap edgeWeightsArrayMap(sp.graph(),edgeWeightsArray);
+
+        // run algorithm itself
+        sp.run(edgeWeights,source);
+    }
+
+};
+
+
+
+
+} // end namespace vigra
+
+#endif // VIGRA_EXPORT_GRAPH_SHORTEST_PATH_VISITOR_HXX
diff --git a/vigranumpy/src/core/export_graph_visitor.hxx b/vigranumpy/src/core/export_graph_visitor.hxx
new file mode 100644
index 0000000..7ca3ef7
--- /dev/null
+++ b/vigranumpy/src/core/export_graph_visitor.hxx
@@ -0,0 +1,590 @@
+#ifndef EXPORT_GRAPH_VISITOR_HXX
+#define EXPORT_GRAPH_VISITOR_HXX
+//#define NO_IMPORT_ARRAY
+
+/*boost python before anything else*/
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+/*std*/
+#include <sstream>
+#include <string>
+
+/*vigra*/
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/graphs.hxx>
+#include <vigra/graph_maps.hxx>
+#include <vigra/graph_generalization.hxx>
+#include <vigra/python_graph.hxx>
+
+
+namespace python = boost::python;
+
+namespace vigra{
+
+
+
+
+template<class GRAPH>
+class LemonUndirectedGraphCoreVisitor 
+:   public boost::python::def_visitor<LemonUndirectedGraphCoreVisitor<GRAPH> >
+{
+public:
+
+    friend class def_visitor_access;
+
+    typedef GRAPH Graph;
+    typedef LemonUndirectedGraphCoreVisitor<GRAPH> VisitorType;
+    // Lemon Graph Typedefs
+    
+    typedef typename Graph::index_type       index_type;
+    typedef typename Graph::Edge             Edge;
+    typedef typename Graph::Node             Node;
+    typedef typename Graph::Arc              Arc;
+
+    typedef typename Graph::NodeIt              NodeIt;
+    typedef typename Graph::EdgeIt              EdgeIt;
+    typedef typename Graph::ArcIt               ArcIt;
+    //typedef typename Graph::NeighborNodeIt      NeighborNodeIt;
+    //typedef EdgeIteratorHolder<Graph> EdgeIteratorHolderType;
+    //typedef NodeIteratorHolder<Graph> NodeIteratorHolderType;
+    //typedef ArcIteratorHolder<Graph>  ArcIteratorHolderType;
+
+    typedef NodeIteratorHolder<Graph>          PyNodeIteratorHolder;
+    typedef EdgeIteratorHolder<Graph>          PyEdgeIteratorHolder;
+
+    typedef NeighbourNodeIteratorHolder<Graph> PyNeighbourNodeIteratorHolder;
+    typedef IncEdgeIteratorHolder<Graph>       PyIncEdgeIteratorHolder;
+
+    typedef EdgeHolder<Graph> PyEdge;
+    typedef NodeHolder<Graph> PyNode;
+    typedef  ArcHolder<Graph> PyArc;
+
+    typedef std::vector<PyEdge> PyEdgeVector;
+    typedef std::vector<PyNode> PyNodeVector;
+    typedef std::vector<PyArc > PyArcVector;
+
+
+        
+
+    LemonUndirectedGraphCoreVisitor(const std::string clsName)
+    :clsName_(clsName){
+
+    }
+    std::string clsName_;
+    template <class classT>
+    void visit(classT& c) const
+    {
+        
+        //import_vigranumpy();
+
+        const std::string edgeHolderClsName = std::string("Edge")+clsName_;
+        const std::string nodeHolderClsName = std::string("Node")+clsName_;
+        const std::string arcHolderClsName  = std::string("Arc") +clsName_;
+
+
+        const std::string edgeHolderVectorClsName = std::string("EdgeVector")+clsName_;
+        const std::string nodeHolderVectorClsName = std::string("NodeVector")+clsName_;
+        const std::string  arcHolderVectorClsName = std::string("ArcVector") +clsName_;
+
+        python::class_<PyEdge>(edgeHolderClsName.c_str(),python::init< >())
+        .add_property("id",  &PyEdge::id )
+        .add_property("u",  &PyEdge::u )
+        .add_property("v",  &PyEdge::v )
+        .def("__eq__",&eqToInvalid<PyEdge>)
+        .def("__ne__",&neqToInvalid<PyEdge>)
+        .def("coord",&PyEdge::intrinsicEdgeCoordinate)
+        ;
+
+        python::class_<PyNode>(nodeHolderClsName.c_str(),python::init< >())
+        .add_property("id",  &PyNode::id )
+        .def("__eq__",&eqToInvalid<PyNode>)
+        .def("__ne__",&neqToInvalid<PyNode>)
+        .def("coord",&PyNode::intrinsicNodeCoordinate)
+        ;
+
+        python::class_< PyArc>( arcHolderClsName.c_str(),python::init< >())
+        .add_property("id",  &PyArc::id )
+        .def("__eq__",&eqToInvalid<PyArc>)
+        .def("__ne__",&neqToInvalid<PyArc>)
+        .def("coord",&PyArc::intrinsicArcCoordinate)
+        ;
+
+
+        python::class_<PyEdgeVector>(edgeHolderVectorClsName.c_str(),python::init<>())
+        .def(python::vector_indexing_suite< PyEdgeVector >() );
+        ;   
+
+
+
+
+        const std::string nodeIteratorHolderClsName = std::string("NodeIteratorHolder")+clsName_;
+        python::class_<PyNodeIteratorHolder>(nodeIteratorHolderClsName.c_str(),python::no_init)
+        .def("__iter__",python::range(&PyNodeIteratorHolder::begin,&PyNodeIteratorHolder::end))
+        ;
+
+        const std::string edgeIteratorHolderClsName = std::string("EdgeIteratorHolder")+clsName_;
+        python::class_<PyEdgeIteratorHolder>(edgeIteratorHolderClsName.c_str(),python::no_init)
+        .def("__iter__",python::range(&PyEdgeIteratorHolder::begin,&PyEdgeIteratorHolder::end))
+        ;
+
+        const std::string neighbourNodeIteratorHolderClsName = std::string("NeighbourNodeIteratorHolder")+clsName_;
+        python::class_<PyNeighbourNodeIteratorHolder>(neighbourNodeIteratorHolderClsName.c_str(),python::no_init)
+        .def("__iter__",python::range(&PyNeighbourNodeIteratorHolder::begin,&PyNeighbourNodeIteratorHolder::end))
+        ;
+
+        const std::string incEdgeIteratorHolderClsName = std::string("IncEdgeIteratorHolder")+clsName_;
+        python::class_<PyIncEdgeIteratorHolder>(incEdgeIteratorHolderClsName.c_str(),python::no_init)
+        .def("__iter__",python::range(&PyIncEdgeIteratorHolder::begin,&PyIncEdgeIteratorHolder::end))
+        ;
+        //const std::string nodeIteratorHolderClsName = std::string("NodeIteratorHolder")+clsName_;
+        //python::class_<NodeIteratorHolderType>(nodeIteratorHolderClsName.c_str(),python::no_init)
+        //.def("__iter__",python::range(&NodeIteratorHolderType::begin,&NodeIteratorHolderType::end))
+        ;
+
+        c
+
+            //special members
+            // print graph
+            .def("__str__",&asStr)
+            .def("__len__",&Graph::edgeNum)
+
+
+            // basic properties
+            .add_property("nodeNum",  &Graph::nodeNum ,"number of nodes within the graph")
+            .add_property("edgeNum",  &Graph::edgeNum ,"number of edges within the graph")
+            .add_property("arcNum",   &Graph::arcNum  ,"number of arcs (2*edgeNum for undirected graphs)")
+            .add_property("maxNodeId",&Graph::maxNodeId,"maximum id of a valid edge in the graph")
+            .add_property("maxEdgeId",&Graph::maxEdgeId,"maximum id of a valid node in the graph")
+            .add_property("maxArcId" ,&Graph::maxNodeId,"maximum id of a valid arc in the graph")
+
+            // id functions
+            .def("id",&nodeId, "get the id of a given node")
+            .def("id",&edgeId, "get the id of a given edge")
+            .def("id",&arcId , "get the id of a given arc")
+
+            // item from id
+            .def("nodeFromId",&nodeFromId,
+                (
+                    python::arg("id")
+                ),
+                "get the node descriptor from the given id"
+            )
+            .def("edgeFromId",&edgeFromId,"get the edge descriptor from the given id")//,python::with_custodian_and_ward_postcall<0,1>())
+            .def("arcFromId", &arcFromId ,"get the arc descriptor from the given id")
+
+            // find edges
+            .def("findEdge",&findEdge,"find an edge between node u and v")
+            .def("findEdge",&findEdgeFromIds,"find the edge between two nodes given their id")
+            //  uv source target
+            .def("u",&u,"get the u node of an edge")
+            .def("v",&v,"geht the v node of an edge")
+            .def("uId",&uId)
+            .def("vId",&vId)
+            .def("uvId",&uvId)
+            .def("uvId",&uvIdFromId)
+
+            .def("source",&source)
+            .def("target",&target)
+
+
+            .def("edgeFromArc",&edgeFromArc)
+
+            // iterators
+            //.def("edgeIter",&edgeHolder,python::with_custodian_and_ward_postcall<0,1>() )  // graph may not be deleted bevore holder is deleted
+            //.def("nodeIter",&nodeHolder,python::with_custodian_and_ward_postcall<0,1>() )  // graph may not be deleted bevore holder is deleted
+
+            .def("nodeIter",&getNodeIteratorHolder,python::with_custodian_and_ward_postcall<0,1>())
+            .def("edgeIter",&getEdgeIteratorHolder,python::with_custodian_and_ward_postcall<0,1>())
+            .def("neighbourNodeIter",&getNeighbourNodeIteratorHolder,python::with_custodian_and_ward_postcall<0,1>())
+            .def("incEdgeIter",      &getIncEdgeIteratorHolder,python::with_custodian_and_ward_postcall<0,1>())
+
+            // intrinsic shape of maps
+            .def("intrinsicNodeMapShape",&IntrinsicGraphShape<Graph>::intrinsicNodeMapShape)
+            .def("intrinsicEdgeMapShape",&IntrinsicGraphShape<Graph>::intrinsicEdgeMapShape)
+            .def("intrinsicArcMapShape" , &IntrinsicGraphShape<Graph>::intrinsicArcMapShape)
+            // commented out because TaggedShape is currently not exported to Python
+            //.def("taggedNodeMapShape",&TaggedGraphShape<Graph>::taggedNodeMapShape)
+            //.def("taggedEdgeMapShape",&TaggedGraphShape<Graph>::taggedEdgeMapShape)
+            //.def("taggedArcMapShape" , &TaggedGraphShape<Graph>::taggedArcMapShape)
+            .def("axistagsNodeMap",&TaggedGraphShape<Graph>::axistagsNodeMap)
+            .def("axistagsEdgeMap",&TaggedGraphShape<Graph>::axistagsEdgeMap)
+            .def("axistagsArcMap" , &TaggedGraphShape<Graph>::axistagsArcMap)
+
+            // intrinsic coordinate of node/edge/arc
+            .def("intrinsicNodeCoordinate",& GraphDescriptorToMultiArrayIndex<Graph>::intrinsicNodeCoordinate)
+            .def("intrinsicEdgeCoordinate",&GraphDescriptorToMultiArrayIndex<Graph>::intrinsicEdgeCoordinate)
+            .def("intrinsicArcCoordinate",& GraphDescriptorToMultiArrayIndex<Graph>::intrinsicArcCoordinate )
+
+
+            ///////////////////////////////////
+            // vectorized  api
+            ///////////////////////////////////
+            .def("nodeIds",registerConverters(&itemIds<Node,NodeIt>),( python::arg("out")=python::object() ) )
+            .def("edgeIds",registerConverters(&itemIds<Edge,EdgeIt>),( python::arg("out")=python::object() ) )
+            .def("arcIds" ,registerConverters(&itemIds<Arc ,ArcIt >),( python::arg("out")=python::object() ) )
+
+            .def("nodeIdMap",registerConverters(&nodeIdMap),( python::arg("out")=python::object() ) )
+
+            .def("findEdges",registerConverters(&findEdges),( python::arg("nodeIdPairs"), python::arg("out")=python::object() ) )
+
+            .def("uIds" ,registerConverters(&uIds), ( python::arg("out")=python::object() ) )
+            .def("vIds" ,registerConverters(&vIds), ( python::arg("out")=python::object() ) )
+            .def("uvIds",registerConverters(&uvIds),( python::arg("out")=python::object() ) )
+            .def("uIds",registerConverters(&uIdsSubset),( python::arg("edgeIds"),python::arg("out")=python::object() ) )
+            .def("vIds",registerConverters(&vIdsSubset),( python::arg("edgeIds"),python::arg("out")=python::object() ) )
+            .def("uvIds",registerConverters(&uvIdsSubset),( python::arg("edgeIds"),python::arg("out")=python::object() ) )
+            
+
+
+            // these functions are defined on the "FULL SET"
+            .def("validEdgeIds",registerConverters(&validIds<Edge,EdgeIt>),( python::arg("out")=python::object() ) )
+            .def("validNodeIds",registerConverters(&validIds<Node,NodeIt>),( python::arg("out")=python::object() ) )
+            .def("validArcIds" ,registerConverters(&validIds<Arc ,ArcIt >),( python::arg("out")=python::object() ) )
+
+
+
+            //.def("dtypetest",registerConverters(&dtypetest<Edge,EdgeIt>),( python::arg("out")=python::object() ) )
+            
+        ;
+    }
+
+
+    static PyEdge edgeFromArc(const Graph & self, const PyArc & arcH){
+        const Arc arc(arcH);
+        const Edge edge(arc);
+        return PyEdge(self, edge);
+    }
+
+    static PyEdgeIteratorHolder getEdgeIteratorHolder(const Graph & self){
+        return PyEdgeIteratorHolder(self);
+    }
+
+    static PyNodeIteratorHolder getNodeIteratorHolder(const Graph & self){
+        return PyNodeIteratorHolder(self);
+    }
+
+
+    static PyIncEdgeIteratorHolder getIncEdgeIteratorHolder(const Graph & self,const PyNode & node){
+        return PyIncEdgeIteratorHolder(self,node);
+    }
+
+
+    static PyNeighbourNodeIteratorHolder getNeighbourNodeIteratorHolder(const Graph & self,const PyNode & node){
+        return PyNeighbourNodeIteratorHolder(self,node);
+    }
+
+    template<class ITEM,class ITEM_IT>
+    static NumpyAnyArray dtypetest(   
+        const Graph & g, 
+        NumpyArray<1,ITEM> out = (NumpyArray<1,ITEM>())
+    ){
+        typedef GraphItemHelper<Graph,ITEM> ItemHelper;
+        out.reshapeIfEmpty(typename NumpyArray<1,ITEM>::difference_type(  ItemHelper::itemNum(g)  ));
+        size_t  counter=0;
+        for(ITEM_IT i(g);i!=lemon::INVALID;++i){
+            const ITEM item = *i;
+            out(counter)=item;
+            ++counter;
+        }
+        return out;
+    }
+
+
+    static NumpyAnyArray findEdges(
+        const Graph & g,
+        NumpyArray<2,UInt32> nodeIdPairs, 
+        NumpyArray<1,Int32> out =(NumpyArray<1,Int32>())
+    ){
+        out.reshapeIfEmpty(typename NumpyArray<1,Int32>::difference_type(  nodeIdPairs.shape(0)  ));
+        for(MultiArrayIndex i=0; i<nodeIdPairs.shape(0); ++i){
+            const Edge e = g.findEdge(
+                g.nodeFromId(nodeIdPairs(i,0)),
+                g.nodeFromId(nodeIdPairs(i,1))
+            );
+            out(i) = e==lemon::INVALID ? -1 : g.id(e);
+        }
+       
+        return out;
+    }
+
+
+    static std::string asStr(const Graph &g){
+        std::stringstream ss;
+        ss<<"Nodes: "<<g.nodeNum()<<" Edges: "<<g.edgeNum()<<" maxNodeId: "<<g.maxNodeId()<<" maxEdgeId: "<<g.maxEdgeId();
+        return ss.str();
+    }
+
+
+    static NumpyAnyArray uIds(const Graph & g, NumpyArray<1,UInt32> out =(NumpyArray<1,UInt32>()) ){
+        typedef GraphItemHelper<Graph,Edge> ItemHelper;
+        out.reshapeIfEmpty(typename NumpyArray<1,UInt32>::difference_type(  ItemHelper::itemNum(g)  ));
+        size_t  counter=0;
+        for(EdgeIt i(g);i!=lemon::INVALID;++i){
+            out(counter)=g.id(g.u(*i));
+            ++counter;
+        }
+        return out;
+    }
+    static NumpyAnyArray vIds(const Graph & g, NumpyArray<1,UInt32> out =(NumpyArray<1,UInt32>()) ){
+        typedef GraphItemHelper<Graph,Edge> ItemHelper;
+        out.reshapeIfEmpty(typename NumpyArray<1,UInt32>::difference_type(  ItemHelper::itemNum(g)  ));
+        size_t  counter=0;
+        for(EdgeIt i(g);i!=lemon::INVALID;++i){
+            out(counter)=g.id(g.v(*i));
+            ++counter;
+        }
+        return out;
+    }
+
+    static NumpyAnyArray uvIds(const Graph & g, NumpyArray<2,UInt32> out =(NumpyArray<2,UInt32>()) ){
+        typedef GraphItemHelper<Graph,Edge> ItemHelper;
+        out.reshapeIfEmpty(typename NumpyArray<2,UInt32>::difference_type(  ItemHelper::itemNum(g) ,2 ));
+        size_t  counter=0;
+        for(EdgeIt i(g);i!=lemon::INVALID;++i){
+            out(counter,0)=g.id(g.u(*i));
+            out(counter,1)=g.id(g.v(*i));
+            ++counter;
+        }
+        return out;
+    }
+
+    static NumpyAnyArray uIdsSubset(
+        const Graph & g, 
+        NumpyArray<1,UInt32> edgeIds,
+        NumpyArray<1,UInt32> out =(NumpyArray<1,UInt32>())
+    ){
+        out.reshapeIfEmpty(typename NumpyArray<1,UInt32>::difference_type(  edgeIds.shape(0)));
+        for(MultiArrayIndex i=0; i<edgeIds.shape(0); ++i){
+            const index_type edgeId=edgeIds(i);
+            const Edge edge  = g.edgeFromId(edgeId);
+            if(edge!=lemon::INVALID){
+                out(i)=g.id(g.u(edge));
+            }
+        }
+        return out;
+    }
+    static NumpyAnyArray vIdsSubset(
+        const Graph & g, 
+        NumpyArray<1,UInt32> edgeIds,
+        NumpyArray<1,UInt32> out =(NumpyArray<1,UInt32>())
+    ){
+        out.reshapeIfEmpty(typename NumpyArray<1,UInt32>::difference_type(  edgeIds.shape(0)));
+        for(MultiArrayIndex i=0; i<edgeIds.shape(0); ++i){
+            const index_type edgeId=edgeIds(i);
+            const Edge edge  = g.edgeFromId(edgeId);
+            if(edge!=lemon::INVALID){
+                out(i)=g.id(g.v(edge));
+            }
+        }
+        return out;
+    }
+
+    static NumpyAnyArray uvIdsSubset(
+        const Graph & g, 
+        NumpyArray<1,UInt32> edgeIds,
+        NumpyArray<2,UInt32> out =(NumpyArray<2,UInt32>())
+    ){
+        out.reshapeIfEmpty(typename NumpyArray<2,UInt32>::difference_type(  edgeIds.shape(0) ,2 ));
+        for(MultiArrayIndex i=0; i<edgeIds.shape(0); ++i){
+            const index_type edgeId=edgeIds(i);
+            const Edge edge  = g.edgeFromId(edgeId);
+            if(edge!=lemon::INVALID){
+                out(i,0)=g.id(g.u(edge));
+                out(i,1)=g.id(g.v(edge));
+            }
+        }
+        return out;
+    }
+
+    template<class ITEM,class ITEM_IT>
+    static NumpyAnyArray validIds(const Graph & g, NumpyArray<1,bool> out =(NumpyArray<1,bool>()) ){
+        typedef GraphItemHelper<Graph,ITEM> ItemHelper;
+        out.reshapeIfEmpty(typename NumpyArray<1,UInt32>::difference_type(  ItemHelper::maxItemId(g)  ));
+        std::fill(out.begin(),out.end(),false);
+        size_t  counter=0;
+        for(ITEM_IT i(g);i!=lemon::INVALID;++i){
+            out(g.id(*i))=true;
+            ++counter;
+        }
+        return out;
+    }
+
+    template<class ITEM,class ITEM_IT>
+    static NumpyAnyArray itemIds(const Graph & g, NumpyArray<1,UInt32> out =(NumpyArray<1,UInt32>()) ){
+        typedef GraphItemHelper<Graph,ITEM> ItemHelper;
+        out.reshapeIfEmpty(typename NumpyArray<1,UInt32>::difference_type(  ItemHelper::itemNum(g)  ));
+        size_t  counter=0;
+        for(ITEM_IT i(g);i!=lemon::INVALID;++i){
+            out(counter)=g.id(*i);
+            ++counter;
+        }
+        return out;
+    }
+
+
+    static  python::tuple uvId(const Graph & self,const PyEdge & e){
+        return  python::make_tuple(self.id(self.u(e)),self.id(self.u(e)) );
+    }
+
+    static  python::tuple uvIdFromId(const Graph & self,const index_type i){
+        const Edge e = self.edgeFromId(i);
+        return  python::make_tuple(self.id(self.u(e)),self.id(self.u(e)) );
+    }
+
+    static  index_type uId(const Graph & self,const PyEdge & e){
+        return self.id(self.u(e));
+    }
+    static  index_type vId(const Graph & self,const PyEdge & e){
+        return self.id(self.v(e));
+    }
+    static  PyNode u(const Graph & self,const PyEdge & e){
+        return PyNode(self,self.u(e));
+    }
+    static  PyNode v(const Graph & self,const PyEdge & e){
+        return PyNode(self,self.v(e));
+    }
+    static  PyNode source(const Graph & self,const PyArc & a){
+        return PyNode(self,self.source(a));
+    }
+    static  PyNode target(const Graph & self,const PyArc & a){
+        return PyNode(self,self.target(a));
+    }
+
+    template<class ITEM>
+    static bool eqToInvalid(const ITEM &  item,const lemon::Invalid iv){
+        return item.graph_==NULL || item==lemon::INVALID;
+    }
+
+    template<class ITEM>
+    static bool neqToInvalid(const ITEM &  item,const lemon::Invalid iv){
+        return item.graph_!=NULL && item!=lemon::INVALID;
+    }
+    
+    static PyNode nodeFromId(const Graph & self,const index_type id){
+        return PyNode(self,self.nodeFromId(id));
+    }
+    static PyEdge edgeFromId(const Graph & self,const index_type id){
+        return PyEdge(self,self.edgeFromId(id));
+    }
+    static PyArc   arcFromId(const Graph & self,const index_type id){
+        return PyArc(self,self.arcFromId(id));
+    }
+
+
+    static PyEdge findEdge( const Graph & self ,const PyNode & u , const PyNode & v){
+        return PyEdge(self,self.findEdge(u,v));
+    }
+
+    static PyEdge findEdgeFromIds( const Graph & self ,const index_type u , const index_type v){
+        return PyEdge(self,self.findEdge(self.nodeFromId(u),self.nodeFromId(v)));
+    }
+
+    static index_type nodeId( const Graph & self,const PyNode & node ){return  self.id(node);}
+    static index_type edgeId( const Graph & self,const PyEdge & edge ){return  self.id(edge);}
+    static index_type arcId(  const Graph & self,const PyArc & arc ){return  self.id(arc);}
+
+
+
+    static NumpyAnyArray nodeIdMap(
+        const Graph & graph,
+        typename PyNodeMapTraits<Graph,   UInt32>::Array  idArray
+    ){  
+        //reshape output
+        idArray.reshapeIfEmpty(IntrinsicGraphShape<Graph>::intrinsicNodeMapShape(graph));
+
+        // array to lemon map
+        typename PyNodeMapTraits<Graph,   UInt32>::Map idArrayMap(graph, idArray);
+
+        for(NodeIt iter(graph);iter!=lemon::INVALID;++iter){
+            idArrayMap[*iter]=graph.id(*iter);
+        }
+
+        return idArray;
+    }
+
+};
+
+
+template<class GRAPH>
+class LemonUndirectedGraphAddItemsVisitor 
+:   public boost::python::def_visitor<LemonUndirectedGraphAddItemsVisitor<GRAPH> >
+{
+public:
+
+    friend class def_visitor_access;
+
+    typedef GRAPH Graph;
+
+    typedef LemonUndirectedGraphAddItemsVisitor<GRAPH> VisitorType;
+    // Lemon Graph Typedefs
+    
+    typedef typename Graph::index_type       index_type;
+    typedef typename Graph::Edge             Edge;
+    typedef typename Graph::Node             Node;
+    typedef typename Graph::Arc              Arc;
+
+    typedef typename Graph::NodeIt              NodeIt;
+    typedef typename Graph::EdgeIt              EdgeIt;
+    typedef typename Graph::ArcIt               ArcIt;
+    //typedef typename Graph::NeighborNodeIt      NeighborNodeIt;
+
+
+
+    typedef EdgeHolder<Graph> PyEdge;
+    typedef NodeHolder<Graph> PyNode;
+    typedef  ArcHolder<Graph> PyArc;
+
+    LemonUndirectedGraphAddItemsVisitor(const std::string clsName)
+    :clsName_(clsName){
+
+    }
+    std::string clsName_;
+    template <class classT>
+    void visit(classT& c) const
+    {
+        
+        //import_vigranumpy();
+
+
+        c
+            // add node
+            .def("addNode",&addNode)
+            .def("addNode",&addNodeFromId)
+            .def("addEdge",&addEdge)
+            .def("addEdges",registerConverters(&addEdges),
+                (
+                    python::arg("edges"),
+                    python::arg("out")=python::object()
+                )
+            )
+        ;
+    }
+
+    static PyNode addNode(Graph & self){
+        return PyNode(self,self.addNode());
+    }
+    static PyNode addNodeFromId(Graph & self,const index_type id){
+        return PyNode(self,self.addNode(id));
+    }
+
+    static PyEdge addEdge(Graph & self ,const PyNode & u , const PyNode & v){
+        return PyEdge(self,self.addEdge(u,v));
+    }
+
+    static NumpyAnyArray addEdges(Graph & self,
+        NumpyArray<2,UInt32> edges,
+        NumpyArray<1,UInt32> edgeIds  =(NumpyArray<1,UInt32>())
+    ){
+        edgeIds.reshapeIfEmpty(typename NumpyArray<1,index_type>::difference_type(edges.shape(0)));
+        for(MultiArrayIndex i=0; i<edges.shape(0); ++i){
+            const Edge e = self.addEdge(edges(i,0),edges(i,1));
+            edgeIds(i)=self.id(e);
+        }
+        return edgeIds;
+    }
+};
+
+} // end namespace vigra
+
+#endif // EXPORT_GRAPH_VISITOR_HXX
diff --git a/vigranumpy/src/core/filters.cxx b/vigranumpy/src/core/filters.cxx
index 489eeac..e51b99d 100644
--- a/vigranumpy/src/core/filters.cxx
+++ b/vigranumpy/src/core/filters.cxx
@@ -40,46 +40,118 @@
 #include <vigra/numpy_array_converters.hxx>
 #include <vigra/nonlineardiffusion.hxx>
 #include <vigra/symmetry.hxx>
+#include <vigra/tv_filter.hxx>
+#include <vigra/shockfilter.hxx>
 
 namespace python = boost::python;
 
 namespace vigra
 {
 
+
 template <class InValue, class OutValue>
-NumpyAnyArray 
-pythonNonlinearDiffusion2D(NumpyArray<3, Multiband<InValue> > image, 
+NumpyAnyArray
+pythonShockFilter(NumpyArray<3, Multiband<InValue> > image,
+                  float sigma, 
+                  float rho,
+                  float upwind_factor_h,
+                  unsigned int iterations,
+                  NumpyArray<3, Multiband<OutValue> > res=NumpyArray<3, Multiband<float> >())
+{
+    res.reshapeIfEmpty(image.taggedShape(),
+        "nonlinearDiffusion2D(): Output array has wrong shape.");
+
+    {
+        PyAllowThreads _pythread;
+        for(int k=0; k<image.shape(2); ++k)
+        {
+            MultiArrayView<2, OutValue, StridedArrayTag> bres   = res.bindOuter(k);
+            MultiArrayView<2, InValue,  StridedArrayTag> bimage = image.bindOuter(k);
+
+
+            shockFilter(bimage,bres, sigma, 
+                rho, upwind_factor_h, iterations);
+        }
+    }
+    return res;
+}
+
+
+template <class InValue, class OutValue>
+NumpyAnyArray
+pythonNonlinearDiffusion2D(NumpyArray<3, Multiband<InValue> > image,
                            double edgeThreshold, double scale,
                            NumpyArray<3, Multiband<OutValue> > res=NumpyArray<3, Multiband<float> >())
 {
-    res.reshapeIfEmpty(image.taggedShape(), 
+    res.reshapeIfEmpty(image.taggedShape(),
         "nonlinearDiffusion2D(): Output array has wrong shape.");
-        
+
     {
         PyAllowThreads _pythread;
         for(int k=0; k<image.shape(2); ++k)
         {
             MultiArrayView<2, OutValue, StridedArrayTag> bres = res.bindOuter(k);
-            nonlinearDiffusion(srcImageRange(image.bindOuter(k)), 
-                               destImage(bres), 
+            nonlinearDiffusion(srcImageRange(image.bindOuter(k)),
+                               destImage(bres),
                                DiffusivityFunctor< double >(edgeThreshold), scale);
         }
     }
     return res;
 }
 
+
+template <class InValue, class OutValue>
+NumpyAnyArray
+pythonTotalVariationFilter2D(NumpyArray<2, Singleband<InValue> > image,
+                           double alpha, int steps, double eps = 0,
+                           NumpyArray<2, Singleband<OutValue> > res = python::object())
+{
+    std::string description("totalVariationFilter, alpha, steps, eps=");
+    description += asString(eps);
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
+            "totalVariationFilter(): Output array has wrong shape.");
+
+    {
+        PyAllowThreads _pythread;
+        totalVariationFilter(image, res, alpha, steps, eps);
+    }
+    return res;
+}
+
+template <class InValue, class InValue2, class OutValue>
+NumpyAnyArray
+pythonTotalVariationFilter2D(NumpyArray<2, Singleband<InValue> > image,
+                             NumpyArray<2, Singleband<InValue2> > weight,
+                           double alpha, int steps, double eps = 0,
+                           NumpyArray<2, Singleband<OutValue> > res = python::object())
+{
+    std::string description("totalVariationFilter, weight, alpha, steps, eps=");
+    description += asString(eps);
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
+            "totalVariationFilter(): Output array has wrong shape.");
+
+    {
+        PyAllowThreads _pythread;
+        totalVariationFilter(image, weight, res, alpha, steps, eps);
+    }
+    return res;
+}
+
+
 template < class SrcPixelType >
-NumpyAnyArray 
+NumpyAnyArray
 pythonRadialSymmetryTransform2D(NumpyArray<2, Singleband<SrcPixelType> > image,
                                 double scale = 1.0,
                                 NumpyArray<2, Singleband<SrcPixelType> > res = python::object())
 {
     std::string description("radial symmetry transform, scale=");
     description += asString(scale);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
-            "radialSymmetryTransform2D(): Output array has wrong shape.");    
-        
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
+            "radialSymmetryTransform2D(): Output array has wrong shape.");
+
     {
         PyAllowThreads _pythread;
         radialSymmetryTransform(srcImageRange(image), destImage(res), scale);
@@ -91,16 +163,49 @@ pythonRadialSymmetryTransform2D(NumpyArray<2, Singleband<SrcPixelType> > image,
 void defineFilters2D()
 {
     using namespace python;
-    
+
     docstring_options doc_options(true, true, false);
-    
-    def("nonlinearDiffusion", 
+
+    def("nonlinearDiffusion",
         registerConverters(&pythonNonlinearDiffusion2D<float, float>),
         (arg("image"), arg("edgeThreshold"), arg("scale"), arg("out")=python::object()),
         "Perform edge-preserving smoothing at the given scale."
         "\n\n"
         "For details see nonlinearDiffusion_ in the vigra C++ documentation.\n");
 
+    def("shockFilter",
+        registerConverters(&pythonShockFilter<float, float>),
+        (
+            arg("image"), 
+            arg("sigma"), 
+            arg("rho"),
+            arg("updwindFactorH") ,
+            arg("iterations"),
+            arg("out")=python::object()
+        ),
+        "Perform edge-preserving smoothing at the given scale."
+        "\n\n"
+        "For details see shockFilter_ in the vigra C++ documentation.\n");
+
+
+    
+    
+
+
+    def("totalVariationFilter",
+        registerConverters(&pythonTotalVariationFilter2D<double,double>),
+        (arg("image"), arg("alpha"), arg("steps"), arg("eps"), arg("out")=python::object()),
+        "Perform total variation filter on 2D single band images."
+        "\n\n"
+        "For details see totalVariationFilter in the vigra C++ documentation.\n");
+
+    def("totalVariationFilter",
+        registerConverters(&pythonTotalVariationFilter2D<double,double,double>),
+        (arg("image"), arg("weight"), arg("alpha"), arg("steps"), arg("eps"), arg("out")=python::object()),
+        "Perform weighted total variation filter on 2D single band images."
+        "\n\n"
+        "For details see totalVariationFilter in the vigra C++ documentation.\n");
+
     def("radialSymmetryTransform2D",
         registerConverters(&pythonRadialSymmetryTransform2D<float>),
         (arg("image"), arg("scale"),arg("out")=python::object()),
@@ -115,6 +220,7 @@ void defineKernels();
 void defineConvolutionFunctions();
 void defineMorphology();
 void defineTensor();
+void defineNonLocalMean();
 
 } // namespace vigra
 
@@ -129,4 +235,5 @@ BOOST_PYTHON_MODULE_INIT(filters)
     defineConvolutionFunctions();
     defineMorphology();
     defineTensor();
+    defineNonLocalMean();
 }
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/vigranumpy/src/core/graphs.cxx
similarity index 65%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to vigranumpy/src/core/graphs.cxx
index 37a8c81..78c895a 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/vigranumpy/src/core/graphs.cxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*                 Copyright 2011 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,69 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpygraphs_PyArray_API
+//#define NO_IMPORT_ARRAY
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
 #include <vigra/numpy_array.hxx>
 #include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
+#include <vigra/graphs.hxx>
+#include <vigra/metrics.hxx>
 
 namespace python = boost::python;
 
-namespace vigra {
+namespace vigra{
+
+
+
 
-UInt32 pychecksum(python::str const & s)
-{
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+	void defineInvalid(){
+        python::class_<lemon::Invalid>("Invalid",python::init<>());
+    }
 
+	void defineAdjacencyListGraph();
+	void defineGridGraph2d();
+    void defineGridGraph3d();
+    void defineGridGraphImplicitEdgeMap();
+    template<unsigned int DIM>
+    void defineGridRag();
+
+
+    //void defineEccentricity();
 } // namespace vigra
 
-using namespace boost::python;
 using namespace vigra;
+using namespace boost::python;
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
+
+
+BOOST_PYTHON_MODULE_INIT(graphs)
 {
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
+    import_vigranumpy();
+
+    python::docstring_options doc_options(true, true, false);
+
+    // all exporters needed for graph exporters (like lemon::INVALID)
+    defineInvalid();
+
+    enum_<metrics::MetricType>("MetricType")
+        .value("chiSquared", metrics::ChiSquaredMetric)
+        .value("hellinger", metrics::HellingerMetric)
+        .value("squaredNorm", metrics::SquaredNormMetric)
+        .value("norm", metrics::NormMetric)
+        .value("manhattan", metrics::ManhattanMetric)
+        .value("symetricKl", metrics::SymetricKlMetric)
+        .value("bhattacharya", metrics::BhattacharyaMetric)
+        ;
     
-    def("checksum", &pychecksum, args("data"));
+
+
+    // all graph classes itself (GridGraph , AdjacencyListGraph)
+    defineAdjacencyListGraph();
+    defineGridGraph2d();
+    defineGridGraph3d();
+
+    // implicit edge maps
+    defineGridGraphImplicitEdgeMap();
+
 }
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/vigranumpy/src/core/gridGraph2d.cxx
similarity index 51%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to vigranumpy/src/core/gridGraph2d.cxx
index 37a8c81..48e3e52 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/vigranumpy/src/core/gridGraph2d.cxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*                 Copyright 2011 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,87 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpygraphs_PyArray_API
+#define NO_IMPORT_ARRAY
+
+#define WITH_BOOST_GRAPH
+
+/*vigra*/
+#include "export_graph_visitor.hxx"
+#include "export_graph_rag_visitor.hxx"
+#include "export_graph_algorithm_visitor.hxx"
+#include "export_graph_shortest_path_visitor.hxx"
+#include "export_graph_hierarchical_clustering_visitor.hxx"
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
 #include <vigra/numpy_array.hxx>
 #include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/adjacency_list_graph.hxx>
+#include <vigra/graph_algorithms.hxx>
+#include <vigra/python_graph.hxx>
+
 
 namespace python = boost::python;
 
-namespace vigra {
+namespace vigra{
+
+
+
+
+
+
+    template<unsigned int DIM,class DTAG>
+    NodeHolder< GridGraph<DIM,boost::undirected_tag> > pyCoordinateToNode2d(
+        const GridGraph<DIM,boost::undirected_tag> & g,
+        const typename MultiArray<DIM,int>::difference_type & coordinate
+    ){
+        typename GridGraph<DIM,boost::undirected_tag>::Node node(coordinate);
+        return NodeHolder<  GridGraph<DIM,boost::undirected_tag> >(g,node);
+    }
+
+    template<unsigned int DIM,class DTAG>
+    GridGraph<DIM,DTAG>  * pyGridGraphFactory2d(
+        typename MultiArray<DIM,int>::difference_type shape,
+        const bool directNeighborhood
+    ){
+        return new GridGraph<DIM,DTAG>(shape,directNeighborhood?DirectNeighborhood:IndirectNeighborhood);
+    }
+
+
+
+    template<unsigned int DIM>
+    void defineGridGraphRagSerialization();
+
+
+
+    template<unsigned int DIM>
+    void defineGridGraphT2d(const std::string & clsName){
+
+        typedef GridGraph<DIM,boost::undirected_tag> Graph;
+        typedef typename MultiArray<DIM,int>::difference_type ShapeType;
+
+        
+        python::class_<Graph>(clsName.c_str(),python::init< ShapeType >())
+        .def("__init__",python::make_constructor(&pyGridGraphFactory2d<DIM,boost::undirected_tag>))
+        .def(LemonUndirectedGraphCoreVisitor<Graph>(clsName))
+        .def(LemonGraphAlgorithmVisitor<Graph>(clsName))
+        .def(LemonGridGraphAlgorithmAddonVisitor<Graph>(clsName))
+        .def(LemonGraphShortestPathVisitor<Graph>(clsName))
+        .def(LemonGraphRagVisitor<Graph>(clsName))
+        .def(LemonGraphHierachicalClusteringVisitor<Graph>(clsName))
+        .def("coordinateToNode",pyCoordinateToNode2d<DIM,boost::undirected_tag>)
+        ;
+
+       
+    }
 
-UInt32 pychecksum(python::str const & s)
-{
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
+    void defineGridGraph2d(){
+        defineGridGraphT2d<2>("GridGraphUndirected2d");
+        defineGridGraphRagSerialization<2>();
+        //defineGridGraphT<3>("GridGraphUndirected3d");
+    }
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
 
-} // namespace vigra
+} 
 
-using namespace boost::python;
-using namespace vigra;
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
-{
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
-}
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/vigranumpy/src/core/gridGraph3d.cxx
similarity index 51%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to vigranumpy/src/core/gridGraph3d.cxx
index 37a8c81..984720f 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/vigranumpy/src/core/gridGraph3d.cxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*                 Copyright 2011 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,88 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpygraphs_PyArray_API
+#define NO_IMPORT_ARRAY
+
+#define WITH_BOOST_GRAPH
+
+/*vigra*/
+#include "export_graph_visitor.hxx"
+#include "export_graph_rag_visitor.hxx"
+#include "export_graph_algorithm_visitor.hxx"
+#include "export_graph_shortest_path_visitor.hxx"
+#include "export_graph_hierarchical_clustering_visitor.hxx"
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
 #include <vigra/numpy_array.hxx>
 #include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/adjacency_list_graph.hxx>
+#include <vigra/graph_algorithms.hxx>
+#include <vigra/python_graph.hxx>
+
 
 namespace python = boost::python;
 
-namespace vigra {
+namespace vigra{
+
+
 
-UInt32 pychecksum(python::str const & s)
-{
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
+    template<unsigned int DIM,class DTAG>
+    NodeHolder< GridGraph<DIM,boost::undirected_tag> > pyCoordinateToNode3d(
+        const GridGraph<DIM,boost::undirected_tag> & g,
+        const typename MultiArray<DIM,int>::difference_type & coordinate
+    ){
+        typename GridGraph<DIM,boost::undirected_tag>::Node node(coordinate);
+        return NodeHolder<  GridGraph<DIM,boost::undirected_tag> >(g,node);
+    }
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+    template<unsigned int DIM,class DTAG>
+    GridGraph<DIM,DTAG>  * pyGridGraphFactory3d(
+        typename MultiArray<DIM,int>::difference_type shape,
+        const bool directNeighborhood
+    ){
+        return new GridGraph<DIM,DTAG>(shape,directNeighborhood?DirectNeighborhood:IndirectNeighborhood);
+    }
 
-} // namespace vigra
 
-using namespace boost::python;
-using namespace vigra;
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
-{
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
     
-    def("checksum", &pychecksum, args("data"));
-}
+    template<unsigned int DIM>
+    void defineGridGraphRagSerialization();
+
+
+
+    template<unsigned int DIM>
+    void defineGridGraphT3d(const std::string & clsName){
+
+        typedef GridGraph<DIM,boost::undirected_tag> Graph;
+        typedef typename MultiArray<DIM,int>::difference_type ShapeType;
+
+        
+        python::class_<Graph>(clsName.c_str(),python::init< ShapeType >())
+        .def("__init__",python::make_constructor(&pyGridGraphFactory3d<DIM,boost::undirected_tag>))
+        .def(LemonUndirectedGraphCoreVisitor<Graph>(clsName))
+        .def(LemonGraphAlgorithmVisitor<Graph>(clsName))
+        .def(LemonGridGraphAlgorithmAddonVisitor<Graph>(clsName))
+        .def(LemonGraphShortestPathVisitor<Graph>(clsName))
+        .def(LemonGraphRagVisitor<Graph>(clsName))
+        .def(LemonGraphHierachicalClusteringVisitor<Graph>(clsName))
+        .def("coordinateToNode",pyCoordinateToNode3d<DIM,boost::undirected_tag>)
+        ;
+
+       
+    }
+
+    void defineGridGraph3d(){
+        //defineGridGraphT<2>("GridGraphUndirected2d");
+        defineGridGraphT3d<3>("GridGraphUndirected3d");
+
+        defineGridGraphRagSerialization<3>();
+
+    }
+
+
+
+} 
+
+
diff --git a/vigranumpy/src/core/gridGraphNd.cxx b/vigranumpy/src/core/gridGraphNd.cxx
new file mode 100644
index 0000000..4568fd4
--- /dev/null
+++ b/vigranumpy/src/core/gridGraphNd.cxx
@@ -0,0 +1,131 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2011 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpygraphs_PyArray_API
+#define NO_IMPORT_ARRAY
+
+#define WITH_BOOST_GRAPH
+
+/*vigra*/
+#include "export_graph_visitor.hxx"
+#include "export_graph_rag_visitor.hxx"
+#include "export_graph_algorithm_visitor.hxx"
+#include "export_graph_shortest_path_visitor.hxx"
+#include "export_graph_hierarchical_clustering_visitor.hxx"
+
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/adjacency_list_graph.hxx>
+#include <vigra/graph_algorithms.hxx>
+#include <vigra/python_graph.hxx>
+
+
+namespace python = boost::python;
+
+namespace vigra{
+
+
+
+
+
+    template<unsigned int DIM>
+    NumpyAnyArray pySerializeAffiliatedEdges(
+        const GridGraph<DIM, boost::undirected_tag> & gridGraph,
+        const AdjacencyListGraph & rag,
+        const typename AdjacencyListGraph:: template EdgeMap< std::vector<  typename GridGraph<DIM, boost::undirected_tag >::Edge   > > & affiliatedEdges,
+        NumpyArray<1,UInt32> out
+    ){
+        // reshape
+        const size_t sSize = affiliatedEdgesSerializationSize(gridGraph, rag, affiliatedEdges);
+        out.reshapeIfEmpty( typename NumpyArray<1,UInt32>::difference_type(sSize) );
+
+        // do serialization
+        serializeAffiliatedEdges(gridGraph, rag, affiliatedEdges, out.begin());
+
+        // return 
+        return out;
+
+    }
+
+
+    template<unsigned int DIM>
+    AdjacencyListGraph:: template EdgeMap< std::vector<  typename GridGraph<DIM, boost::undirected_tag >::Edge   > > * 
+    pyDeserializeAffiliatedEdges(
+        const GridGraph<DIM, boost::undirected_tag> & gridGraph,
+        const AdjacencyListGraph & rag,
+        NumpyArray<1,UInt32> serialization
+    ){
+
+        AdjacencyListGraph:: template EdgeMap< std::vector<  typename GridGraph<DIM, boost::undirected_tag >::Edge   > > * affEdges_
+        = new AdjacencyListGraph:: template EdgeMap< std::vector<  typename GridGraph<DIM, boost::undirected_tag >::Edge   > > () ; 
+
+        // do serialization
+        deserializeAffiliatedEdges(gridGraph, rag, *affEdges_, serialization.begin(), serialization.end());
+
+        // return 
+        return affEdges_;
+    }
+
+
+
+
+    template<unsigned int DIM>
+    void defineGridGraphRagSerialization(){
+        python::def("_serialzieGridGraphAffiliatedEdges",registerConverters(&pySerializeAffiliatedEdges<DIM>),
+            (
+                python::arg("gridGraph"),
+                python::arg("rag"),
+                python::arg("affiliatedEdges"),
+                python::arg("out") = python::object()
+            )
+        );
+
+        python::def("_deserialzieGridGraphAffiliatedEdges",registerConverters(&pyDeserializeAffiliatedEdges<DIM>),
+            (
+                python::arg("gridGraph"),
+                python::arg("rag"),
+                python::arg("serialization")
+            ),
+            python::return_value_policy<python::manage_new_object>()
+        );
+    };
+
+    template void defineGridGraphRagSerialization< 2 >();
+    template void defineGridGraphRagSerialization< 3  >();
+
+} 
+
+
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/vigranumpy/src/core/gridGraphNd.hxx
similarity index 52%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to vigranumpy/src/core/gridGraphNd.hxx
index 37a8c81..d4a96b7 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/vigranumpy/src/core/gridGraphNd.hxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*                 Copyright 2011 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,84 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpygraphs_PyArray_API
+#define NO_IMPORT_ARRAY
+
+#define WITH_BOOST_GRAPH
+
+/*vigra*/
+#include "export_graph_visitor.hxx"
+#include "export_graph_rag_visitor.hxx"
+#include "export_graph_algorithm_visitor.hxx"
+#include "export_graph_shortest_path_visitor.hxx"
+#include "export_graph_hierarchical_clustering_visitor.hxx"
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
 #include <vigra/numpy_array.hxx>
 #include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/adjacency_list_graph.hxx>
+#include <vigra/graph_algorithms.hxx>
+#include <vigra/python_graph.hxx>
+
 
 namespace python = boost::python;
 
-namespace vigra {
+namespace vigra{
+
+
+
+
+
+
+    template<unsigned int DIM,class DTAG>
+    NodeHolder< GridGraph<DIM,boost::undirected_tag> > pyCoordinateToNode3d(
+        const GridGraph<DIM,boost::undirected_tag> & g,
+        const typename MultiArray<DIM,int>::difference_type & coordinate
+    ){
+        typename GridGraph<DIM,boost::undirected_tag>::Node node(coordinate);
+        return NodeHolder<  GridGraph<DIM,boost::undirected_tag> >(g,node);
+    }
+
+    template<unsigned int DIM,class DTAG>
+    GridGraph<DIM,DTAG>  * pyGridGraphFactory3d(
+        typename MultiArray<DIM,int>::difference_type shape,
+        const bool directNeighborhood
+    ){
+        return new GridGraph<DIM,DTAG>(shape,directNeighborhood?DirectNeighborhood:IndirectNeighborhood);
+    }
+
+
+
+
+
+    template<unsigned int DIM>
+    void defineGridGraphT3d(const std::string & clsName){
+
+        typedef GridGraph<DIM,boost::undirected_tag> Graph;
+        typedef typename MultiArray<DIM,int>::difference_type ShapeType;
+
+        
+        python::class_<Graph>(clsName.c_str(),python::init< ShapeType >())
+        .def("__init__",python::make_constructor(&pyGridGraphFactory3d<DIM,boost::undirected_tag>))
+        .def(LemonUndirectedGraphCoreVisitor<Graph>(clsName))
+        .def(LemonGraphAlgorithmVisitor<Graph>(clsName))
+        .def(LemonGridGraphAlgorithmAddonVisitor<Graph>(clsName))
+        .def(LemonGraphShortestPathVisitor<Graph>(clsName))
+        .def(LemonGraphRagVisitor<Graph>(clsName))
+        .def(LemonGraphHierachicalClusteringVisitor<Graph>(clsName))
+        .def("coordinateToNode",pyCoordinateToNode3d<DIM,boost::undirected_tag>)
+        ;
+
+       
+    }
+
+    void defineGridGraph3d(){
+        //defineGridGraphT<2>("GridGraphUndirected2d");
+        defineGridGraphT3d<3>("GridGraphUndirected3d");
+    }
 
-UInt32 pychecksum(python::str const & s)
-{
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
 
-} // namespace vigra
+} 
 
-using namespace boost::python;
-using namespace vigra;
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
-{
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
-}
diff --git a/vigranumpy/src/core/grid_graph_implicit_edge_maps.cxx b/vigranumpy/src/core/grid_graph_implicit_edge_maps.cxx
new file mode 100644
index 0000000..b80fc31
--- /dev/null
+++ b/vigranumpy/src/core/grid_graph_implicit_edge_maps.cxx
@@ -0,0 +1,136 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2011 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpygraphs_PyArray_API
+#define NO_IMPORT_ARRAY
+
+#define WITH_BOOST_GRAPH
+
+/*vigra*/
+#include "export_graph_visitor.hxx"
+#include "export_graph_rag_visitor.hxx"
+#include "export_graph_algorithm_visitor.hxx"
+#include "export_graph_shortest_path_visitor.hxx"
+#include "export_graph_hierarchical_clustering_visitor.hxx"
+
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/multi_gridgraph.hxx>
+#include <vigra/adjacency_list_graph.hxx>
+#include <vigra/graph_algorithms.hxx>
+#include <vigra/graph_maps.hxx>
+#include <vigra/python_graph.hxx>
+
+
+namespace python = boost::python;
+
+namespace vigra{
+
+
+
+
+    template<class GRAPH, class T_NODE,class FUNCTOR , class OTF_EDGE_MAP>
+    OTF_EDGE_MAP * makeImplicitEdgeMap(
+        const GRAPH & graph,
+        const typename PyNodeMapTraits<GRAPH, T_NODE>::Array & nodeArray
+    ){
+        // generate lemon compatible map to node array (cheap view)
+        typename PyNodeMapTraits<GRAPH,   T_NODE>::Map nodeArrayMap(graph, nodeArray);
+        FUNCTOR f;
+        OTF_EDGE_MAP * res = new OTF_EDGE_MAP(graph, nodeArrayMap, f);
+        return res;
+
+    }
+
+
+
+    template<class GRAPH, class T_NODE,class NODE_MAP, class FUNCTOR, class RESULT>
+    void defineImplicitEdgeMapT(const std::string & clsName, const std::string & factoryName){
+
+        
+        typedef OnTheFlyEdgeMap2<GRAPH, NODE_MAP, FUNCTOR, RESULT> EdgeMap;
+
+        python::class_<EdgeMap>(clsName.c_str(),python::no_init)
+        ;
+
+
+
+        python::def(factoryName.c_str(),registerConverters(&makeImplicitEdgeMap<GRAPH, T_NODE,FUNCTOR, EdgeMap>),
+            python::with_custodian_and_ward_postcall< 0,1 ,
+                python::with_custodian_and_ward_postcall< 0 ,2,
+                    python::return_value_policy<   python::manage_new_object      
+                >   >   >()  
+        );
+       
+    }
+
+    template<int DIM, class T_NODE, class T_RES, class FUNCTOR>
+    void defineGridGraphImplicitEdgeMapT(const std::string & clsName, const std::string & factoryName){
+            
+
+
+        typedef GridGraph<DIM, boost::undirected_tag> Graph;
+        typedef typename PyNodeMapTraits<Graph, T_NODE>::Map NodeMap;
+       
+        //typedef OnTheFlyEdgeMap2<Graph, NodeMap, FUNCTOR, T_RES> EdgeMap;
+        defineImplicitEdgeMapT<Graph,T_NODE, NodeMap, FUNCTOR,  T_RES>(clsName,factoryName);
+
+
+
+
+
+    }
+
+
+    void defineGridGraphImplicitEdgeMap(){
+
+        {
+            typedef float NodeValue;
+            typedef float EdgeValue;
+            typedef MeanFunctor<EdgeValue> Functor;
+            defineGridGraphImplicitEdgeMapT<3, NodeValue, EdgeValue,Functor>(
+                std::string("ImplicitMEanEdgeMap_3d_float_float"),
+                std::string("implicitMeanEdgeMap")
+            );
+            defineGridGraphImplicitEdgeMapT<2, NodeValue, EdgeValue,Functor>(
+                std::string("ImplicitMEanEdgeMap_2d_float_float"),
+                std::string("implicitMeanEdgeMap")
+            );
+        }
+    }
+
+} 
+
+
diff --git a/vigranumpy/src/core/histogram.cxx b/vigranumpy/src/core/histogram.cxx
new file mode 100644
index 0000000..0261055
--- /dev/null
+++ b/vigranumpy/src/core/histogram.cxx
@@ -0,0 +1,210 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2011 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpyhistogram_PyArray_API
+//#define NO_IMPORT_ARRAY
+
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/multi_histogram.hxx>
+namespace python = boost::python;
+
+namespace vigra{
+
+
+    template<unsigned int DIM,unsigned int CHANNELS>
+    NumpyAnyArray pyMultiGaussianHistogram(
+        NumpyArray<DIM,TinyVector<float,CHANNELS> > image,
+        const TinyVector<float,CHANNELS> minVals,
+        const TinyVector<float,CHANNELS> maxVals,
+        const size_t bins,
+        const float  sigma,
+        const float sigmaBin,
+        NumpyArray<DIM+2,float> histogram = NumpyArray<DIM+2,float>()
+    ){
+        typename NumpyArray<DIM+2,float>::difference_type  outShape;
+        for(size_t d=0;d<DIM;++d){
+            outShape[d]=image.shape(d);
+        }
+        outShape[DIM]=bins;
+        outShape[DIM+1]=CHANNELS;
+        histogram.reshapeIfEmpty(outShape);
+        {
+            PyAllowThreads _pythread;
+            multiGaussianHistogram<DIM,float,CHANNELS,float>(image,minVals,maxVals,bins,
+                sigma,sigmaBin,histogram);
+        }
+        return histogram;
+    }
+
+
+    template<unsigned int DIM>
+    NumpyAnyArray pyMultiGaussianCoHistogram(
+        NumpyArray<DIM,float > imageA,
+        NumpyArray<DIM,float > imageB,
+        const TinyVector<float,2> minVals,
+        const TinyVector<float,2> maxVals,
+        const TinyVector<int,2> bins,
+        const TinyVector<float,3> sigma,
+        NumpyArray<DIM+2,float> histogram = NumpyArray<DIM+2,float>()
+    ){
+        typename NumpyArray<DIM+2,float>::difference_type  outShape;
+        for(size_t d=0;d<DIM;++d){
+           outShape[d]=imageA.shape(d);
+        }
+        outShape[DIM]=bins[0];
+        outShape[DIM+1]=bins[1];
+        histogram.reshapeIfEmpty(outShape);
+        {
+            PyAllowThreads _pythread;
+            multiGaussianCoHistogram<DIM,float,float>(imageA,imageB,minVals,maxVals,bins,
+            sigma,histogram);
+        }
+        return histogram;
+    }
+
+
+
+
+    template<unsigned int DIM>
+    NumpyAnyArray pyMultiGaussianRankOrder(
+        const NumpyArray<DIM, float>      & image,
+        const float                         minVal,
+        const float                         maxVal,
+        const size_t                        bins,
+        const NumpyArray<1, float>        & sigmas,  
+        const NumpyArray<1, float>        & ranks,
+        NumpyArray<DIM+1, float>            out
+    ){
+        // reshape 
+        typename NumpyArray<DIM+1,float>::difference_type  outShape;
+        for(size_t d=0;d<DIM;++d){
+           outShape[d]=image.shape(d);
+        }
+        outShape[DIM]=ranks.size();
+        out.reshapeIfEmpty(outShape);
+
+        // FIXME: check the length of sigmas and ranks
+
+        {
+            PyAllowThreads _pythread;
+            TinyVector<double, DIM+1> sigmaVec;
+            std::copy(sigmas.begin(),sigmas.end(),sigmaVec.begin());
+
+            multiGaussianRankOrder<DIM, float, float, float>(image, minVal, maxVal,
+                                   bins, sigmaVec, ranks, out);
+        }
+        return out;
+    }
+
+
+
+    template<unsigned int DIM,unsigned int CHANNELS>
+    void defineMultiGaussianHistogram(){
+
+        python::def("gaussianHistogram_",registerConverters(&pyMultiGaussianHistogram<DIM,CHANNELS>),
+            (
+                python::arg("image"),
+                python::arg("minVals"),
+                python::arg("maxVals"),
+                python::arg("bins")=30,
+                python::arg("sigma")=3.0,
+                python::arg("sigmaBin")=2.0,
+                python::arg("out")=python::object()
+            )
+        );
+    }
+
+
+    template<unsigned int DIM>
+    void defineMultiGaussianCoHistogram(){
+
+        python::def("gaussianCoHistogram",registerConverters(&pyMultiGaussianCoHistogram<DIM>),
+            (
+                python::arg("imageA"),
+                python::arg("imageB"),
+                python::arg("minVals"),
+                python::arg("maxVals"),
+                python::arg("bins"),
+                python::arg("sigma"),
+                python::arg("out")=python::object()
+            )
+        );
+    }
+
+
+    template<unsigned int DIM>
+    void defineMultiGaussianRank(){
+
+        python::def("_gaussianRankOrder",registerConverters(&pyMultiGaussianRankOrder<DIM>),
+            (
+                python::arg("image"),
+                python::arg("minVal"),
+                python::arg("maxVal"),
+                python::arg("bins"),
+                python::arg("sigmas"),
+                python::arg("ranks"),
+                python::arg("out")=python::object()
+            )
+        );
+    }
+    
+
+
+} // namespace vigra
+
+using namespace vigra;
+using namespace boost::python;
+
+
+
+
+BOOST_PYTHON_MODULE_INIT(histogram)
+{
+    import_vigranumpy();
+
+    // all exporters needed for graph exporters (like lemon::INVALID)
+    defineMultiGaussianHistogram<2,1>();
+    defineMultiGaussianHistogram<2,3>();
+    defineMultiGaussianHistogram<3,1>();
+    defineMultiGaussianHistogram<3,3>();
+    defineMultiGaussianHistogram<3,10>();
+
+    defineMultiGaussianCoHistogram<2>();
+    defineMultiGaussianCoHistogram<3>();
+
+    defineMultiGaussianRank<2>();
+    defineMultiGaussianRank<3>();
+}
diff --git a/vigranumpy/src/core/impex.cxx b/vigranumpy/src/core/impex.cxx
index 91db647..46b48a2 100644
--- a/vigranumpy/src/core/impex.cxx
+++ b/vigranumpy/src/core/impex.cxx
@@ -536,8 +536,9 @@ void defineImpexFunctions()
         "   SUN:\n"
         "       SUN Rasterfile (pixel types: UINT8 as gray and RGB).\n"
         "   TIFF:\n"
-        "       Tagged Image File Format (pixel types: UINT8, INT16, INT32, FLOAT, DOUBLE\n"
-        "       with up to 4 channels). Only available if libtiff is installed.\n"
+        "       Tagged Image File Format (pixel types: INT8, UINT8, INT16, UINT16,\n"
+        "       INT32, UINT32, FLOAT, DOUBLE with up to 4 channels). Only available\n"
+        "       if libtiff is installed.\n"
         "   VIFF:\n"
         "       Khoros Visualization image file (pixel types: UINT8, INT16\n"
         "       INT32, FLOAT, DOUBLE with arbitrary many channels).\n\n");
diff --git a/vigranumpy/src/core/learning.cxx b/vigranumpy/src/core/learning.cxx
index eb0d6a7..a4f8c62 100644
--- a/vigranumpy/src/core/learning.cxx
+++ b/vigranumpy/src/core/learning.cxx
@@ -53,22 +53,22 @@ python::tuple
 pythonPCA(NumpyArray<2,U> features, int nComponents)
 {
     vigra_precondition(!features.axistags(),
-                       "principleComponents(): feature matrix must not have axistags\n"
+                       "principalComponents(): feature matrix must not have axistags\n"
                        "(use 'array.view(numpy.ndarray)' to remove them).");
-    
-    NumpyArray<2, U> fz(Shape2(features.shape(0), nComponents)); 
-    NumpyArray<2, U> zv(Shape2(nComponents, features.shape(1))); 
+
+    NumpyArray<2, U> fz(Shape2(features.shape(0), nComponents));
+    NumpyArray<2, U> zv(Shape2(nComponents, features.shape(1)));
 
     {
         PyAllowThreads _pythread;
-        principleComponents(features, fz, zv);
+        principalComponents(features, fz, zv);
     }
     return python::make_tuple(fz, zv);
 }
 
 template<class U>
 python::tuple
-pythonPLSA(NumpyArray<2,U> features, 
+pythonPLSA(NumpyArray<2,U> features,
            int nComponents,
            int nIterations,
            double minGain,
@@ -77,14 +77,14 @@ pythonPLSA(NumpyArray<2,U> features,
     vigra_precondition(!features.axistags(),
                        "pLSA(): feature matrix must not have axistags\n"
                        "(use 'array.view(numpy.ndarray)' to remove them).");
-    
-    NumpyArray<2, U> fz(Shape2(features.shape(0), nComponents)); 
-    NumpyArray<2, U> zv(Shape2(nComponents, features.shape(1))); 
+
+    NumpyArray<2, U> fz(Shape2(features.shape(0), nComponents));
+    NumpyArray<2, U> zv(Shape2(nComponents, features.shape(1)));
 
     {
         PyAllowThreads _pythread;
         pLSA(features, fz, zv,
-             RandomNumberGenerator<>(), 
+             RandomNumberGenerator<>(),
              PLSAOptions().maximumNumberOfIterations(nIterations)
                           .minimumRelativeGain(minGain)
                           .normalizedComponentWeights(normalize));
@@ -96,21 +96,21 @@ pythonPLSA(NumpyArray<2,U> features,
 void defineUnsupervised()
 {
     using namespace python;
-    
+
     docstring_options doc_options(true, true, false);
 
-    def("principleComponents", registerConverters(&pythonPCA<double>),
+    def("principalComponents", registerConverters(&pythonPCA<double>),
         (arg("features"), arg("nComponents")),
-        "\nPerform principle component analysis. \n\n"
+        "\nPerform principal component analysis. \n\n"
         "The imput matrix 'features' must have shape (nFeatures*nSamples). PCA will\n"
         "reduce it to a smaller matrix 'C' with shape (nComponents*nSamples) that \n"
         "preserves as much variance as possible. Specifically, the call::\n\n"
-        "    P, C = principleComponents(features, 3)\n\n"
+        "    P, C = principalComponents(features, 3)\n\n"
         "returns a projection matrix 'P' with shape (nComponents*nFeatures)\n"
         "such that ``C = numpy.dot(numpy.transpose(P), features)``. Conversely, the\n"
         "matrix  ``f = numpy.dot(P, C)`` is the best possible rank-nComponents\n"
         "approximation to the matrix 'features' under the least-squares criterion.\n\n"
-        "See principleComponents_ in the C++ documentation for more detailed\ninformation.\n\n");
+        "See principalComponents_ in the C++ documentation for more detailed\ninformation.\n\n");
 
     PLSAOptions options;
 
diff --git a/vigranumpy/src/core/accumulator-region-singleband.cxx b/vigranumpy/src/core/minindexedpq.cxx
similarity index 68%
copy from vigranumpy/src/core/accumulator-region-singleband.cxx
copy to vigranumpy/src/core/minindexedpq.cxx
index c2d0a8c..1898a64 100644
--- a/vigranumpy/src/core/accumulator-region-singleband.cxx
+++ b/vigranumpy/src/core/minindexedpq.cxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*            Copyright 2011-2012 by Ullrich Koethe                     */
+/*                 Copyright 2011 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,33 +33,65 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpyanalysis_PyArray_API
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpyclustering_PyArray_API
 #define NO_IMPORT_ARRAY
 
-#include "pythonaccumulator.hxx"
-
+#include <boost/python.hpp>
+#include <vigra/merge_graph/min_indexed_pq.hxx>
 namespace python = boost::python;
 
 namespace vigra
 {
 
-void defineSinglebandRegionAccumulators()
-{
-    using namespace python;
-    using namespace vigra::acc;
 
+
+template<class T>
+void defineMinIndexedPqT(const std::string name){
+    using namespace python;
     docstring_options doc_options(true, true, false);
-    typedef Select<Count, Mean, Variance, Skewness, Kurtosis, 
-                   Minimum, Maximum, StandardQuantiles<GlobalRangeHistogram<0> >,
-                   RegionCenter, RegionRadii, RegionAxes,
-                   Weighted<RegionCenter>, Weighted<RegionRadii>, Weighted<RegionAxes>,
-                   Select<Coord<Minimum>, Coord<Maximum>, Coord<ArgMinWeight>, Coord<ArgMaxWeight>, 
-                          Principal<Coord<Skewness> >, Principal<Coord<Kurtosis> >, 
-                          Principal<Weighted<Coord<Skewness> > >, Principal<Weighted<Coord<Kurtosis> > > >,
-                   DataArg<1>, WeightArg<1>, LabelArg<2>
-                   > ScalarRegionAccumulators;
-    definePythonAccumulatorArraySingleband<2, float, ScalarRegionAccumulators>();
-    definePythonAccumulatorArraySingleband<3, float, ScalarRegionAccumulators>();
+
+    typedef MinIndexedPQ<T>  MinIndexedPQType;
+
+    class_<MinIndexedPQType>(name.c_str(),init<const size_t >())
+	    .def("insert",&MinIndexedPQType::insert,
+		    (
+		    	arg("index"),
+		    	arg("value")
+		    ),
+		    "insert a index with an value"
+    	)
+    	.def("changeValue",&MinIndexedPQType::changeValue,
+		    (
+		    	arg("index"),
+		    	arg("value")
+		    ),
+		    "insert a index with an value"
+    	)
+    	.def("decreaseValue",&MinIndexedPQType::decreaseValue,
+		    (
+		    	arg("index"),
+		    	arg("value")
+		    ),
+		    "insert a index with an value"
+    	)
+    	.def("increaseValue",&MinIndexedPQType::increaseValue,
+		    (
+		    	arg("index"),
+		    	arg("value")
+		    ),
+		    "insert a index with an value"
+    	)
+    	.def("__len__",&MinIndexedPQType::size,"number of elements in PQ")
+    	.def("isEmpty",&MinIndexedPQType::isEmpty,"check if pq is empty")
+
+    ;
+}
+
+
+void defineMinIndexedPq(){
+	defineMinIndexedPqT<float>("MinIndexedPQFloat");
 }
 
+
 } // namespace vigra
+
diff --git a/vigranumpy/src/core/morphology.cxx b/vigranumpy/src/core/morphology.cxx
index 115d4b5..a197a4e 100644
--- a/vigranumpy/src/core/morphology.cxx
+++ b/vigranumpy/src/core/morphology.cxx
@@ -42,6 +42,9 @@
 #include <vigra/multi_morphology.hxx>
 #include <vigra/distancetransform.hxx>
 #include <vigra/multi_distance.hxx>
+#include <vigra/eccentricitytransform.hxx>
+#include <vigra/skeleton.hxx>
+#include <vigra/vector_distance.hxx>
 
 namespace python = boost::python;
 
@@ -420,19 +423,19 @@ pythonDistanceTransform2D(NumpyArray<2, Singleband<PixelType> > image,
     return res;
 }
 
-template < class VoxelType >
+template < unsigned int N, class VoxelType >
 NumpyAnyArray 
-pythonDistanceTransform3D(NumpyArray<3, Singleband<VoxelType> > volume, 
+pythonDistanceTransformND(NumpyArray<N, Singleband<VoxelType> > volume, 
                           bool background, 
                           ArrayVector<double> pixelPitch = ArrayVector<double>(),
-                          NumpyArray<3, Singleband<VoxelType> > res=python::object())
+                          NumpyArray<N, Singleband<VoxelType> > res=python::object())
 {
     res.reshapeIfEmpty(volume.taggedShape(), 
             "distanceTransform3D(): Output array has wrong shape.");
     
     if (pixelPitch.size() == 0)
     {
-        pixelPitch = ArrayVector<double>(3, 1.0);
+        pixelPitch = ArrayVector<double>(N, 1.0);
     }
     else
     {
@@ -446,6 +449,212 @@ pythonDistanceTransform3D(NumpyArray<3, Singleband<VoxelType> > volume,
     return res;
 }
 
+template < unsigned int N, class VoxelType >
+NumpyAnyArray 
+pythonVectorDistanceTransformND(NumpyArray<N, Singleband<VoxelType> > volume, 
+                                bool background, 
+                                ArrayVector<double> pyPixelPitch = ArrayVector<double>(),
+                                NumpyArray<N, TinyVector<float, N> > res=python::object())
+{
+    vigra_precondition(pyPixelPitch.size() == 0 || pyPixelPitch.size() == N,
+        "vectorDistanceTransform(): pixel_pitch has wrong shape.");
+    
+    res.reshapeIfEmpty(volume.taggedShape(), 
+            "vectorDistanceTransform(): Output array has wrong shape.");
+            
+    TinyVector<double, N> pixelPitch(1.0);
+    if (pyPixelPitch.size() > 0)
+    {
+        pixelPitch.init(pyPixelPitch.begin(), pyPixelPitch.end());
+        pixelPitch = volume.permuteLikewise(pixelPitch);
+    }
+    
+    {
+        PyAllowThreads _pythread;
+        separableVectorDistance(volume, res, background, pixelPitch);
+    }
+    return res;
+}
+
+template < unsigned int N, class VoxelType >
+NumpyAnyArray
+pythonboundaryDistanceTransform(NumpyArray<N, Singleband<VoxelType> > volume,
+                                bool array_border_is_active,
+                                std::string boundary,
+                                NumpyArray<N, Singleband<float> > res)
+{
+    res.reshapeIfEmpty(volume.taggedShape(),
+            "boundaryDistanceTransform(): Output array has wrong shape.");
+            
+    boundary = tolower(boundary);
+    BoundaryDistanceTag boundary_tag = InterpixelBoundary;
+    if(boundary == "outerboundary")
+        boundary_tag = OuterBoundary;
+    else if(boundary == "interpixelboundary" || boundary == "")
+        boundary_tag = InterpixelBoundary;
+    else if(boundary == "innerboundary")
+        boundary_tag = InnerBoundary;
+    else
+        vigra_precondition(false, 
+                           "boundaryDistanceTransform(): invalid 'boundary' specification.");
+    {
+        PyAllowThreads _pythread;
+        boundaryMultiDistance(volume, res, array_border_is_active, boundary_tag);
+    }
+    return res;
+}
+
+template < unsigned int N, class VoxelType >
+NumpyAnyArray
+pythonboundaryVectorDistanceTransform(NumpyArray<N, Singleband<VoxelType> > volume,
+                                bool array_border_is_active,
+                                std::string boundary,
+                                NumpyArray<N, TinyVector<float, N> > res)
+{
+    res.reshapeIfEmpty(volume.taggedShape(),
+            "boundaryVectorDistanceTransform(): Output array has wrong shape.");
+            
+    boundary = tolower(boundary);
+    BoundaryDistanceTag boundary_tag = InterpixelBoundary;
+    if(boundary == "outerboundary")
+        boundary_tag = OuterBoundary;
+    else if(boundary == "interpixelboundary" || boundary == "")
+        boundary_tag = InterpixelBoundary;
+    else if(boundary == "innerboundary")
+        boundary_tag = InnerBoundary;
+    else
+        vigra_precondition(false, 
+                           "boundaryVectorDistanceTransform(): invalid 'boundary' specification.");
+    {
+        PyAllowThreads _pythread;
+        boundaryVectorDistance(volume, res, array_border_is_active, boundary_tag);
+    }
+    return res;
+}
+
+template < unsigned int N, class T, class S >
+NumpyAnyArray
+pythonEccentricityTransform(const NumpyArray<N, T> & image,
+                            NumpyArray<N, S> res)
+{
+    res.reshapeIfEmpty(image.taggedShape(),
+                       "eccentricityTransform(): Output array has wrong shape.");
+    eccentricityTransformOnLabels(image, res);
+    return res;
+}
+
+template < unsigned int N, class T >
+python::list
+pythonEccentricityCenters(const NumpyArray<N, T> & image)
+{
+    typedef typename MultiArrayShape<N>::type Point;
+    ArrayVector<Point> centers;
+    eccentricityCenters(image, centers);
+
+    python::list centerlist = python::list();
+    for (int i=0; i<centers.size(); ++i) {
+        centerlist.append(centers[i]);
+    }
+    return centerlist;
+}
+
+template < unsigned int N, class T, class S >
+python::tuple
+pythonEccentricityTransformWithCenters(const NumpyArray<N, T> & image,
+                                       NumpyArray<N, S> res)
+{
+    typedef typename MultiArrayShape<N>::type Point;
+    res.reshapeIfEmpty(image.taggedShape(),
+                       "eccentricityTransformWithCenters(): Output array has wrong shape.");
+    ArrayVector<Point> centers;
+    eccentricityTransformOnLabels(image, res, centers);
+
+    python::list centerlist = python::list();
+    for (int i=0; i<centers.size(); ++i) {
+        centerlist.append(centers[i]);
+    }
+    return python::make_tuple(res, centerlist);
+}
+
+template <unsigned int N, class T>
+NumpyAnyArray
+pySkeletonizeImage(NumpyArray<N, Singleband<T> > const & labels,
+              std::string mode,
+              double pruning_threshold)
+{
+    mode = tolower(mode);
+    SkeletonOptions options;
+    bool returnFloat = false;
+    
+    if(mode == "dontprune")
+    {
+        options.dontPrune();
+    }
+    else if(mode == "returnlength")
+    {
+        options.returnLength();
+        returnFloat = true;
+    }
+    else if(mode == "prunelength")
+    {
+        options.pruneLength(pruning_threshold);
+    }
+    else if(mode == "prunelengthrelative")
+    {
+        options.pruneLengthRelative(pruning_threshold);
+    }
+    else if(mode == "returnsalience")
+    {
+        options.returnSalience();
+        returnFloat = true;
+    }
+    else if(mode == "pruneasalience")
+    {
+        options.pruneSalience(pruning_threshold);
+    }
+    else if(mode == "prunesaliencerelative" || mode == "")
+    {
+        options.pruneSalienceRelative(pruning_threshold);
+    }
+    else if(mode == "prunetopology")
+    {
+        options.pruneTopology();
+    }
+    else if(mode == "pruneaggressive")
+    {
+        options.pruneTopology(false);
+    }
+    else
+    {
+        vigra_precondition(false, "skeletonizeImage(): invalid mode.");
+    }
+    
+    if(returnFloat)
+    {
+        NumpyArray<N, Singleband<float> > res(labels.taggedShape());
+        
+        {
+            PyAllowThreads _pythread;
+            
+            skeletonizeImage(labels, res, options);
+        }
+        
+        return res;
+    }
+    else
+    {
+        NumpyArray<N, Singleband<T> > res(labels.taggedShape());
+        
+        {
+            PyAllowThreads _pythread;
+            
+            skeletonizeImage(labels, res, options);
+        }
+        
+        return res;
+    }
+}
+
 void defineMorphology()
 {
     using namespace python;
@@ -744,7 +953,7 @@ void defineMorphology()
         "\n"
         "For details see distanceTransform_ in the vigra C++ documentation.\n");
 
-        def("distanceTransform2D",
+    def("distanceTransform2D",
         registerConverters(&pythonDistanceTransform2D<UInt8,float>),
         (arg("image"), 
          arg("background")=true, 
@@ -754,7 +963,7 @@ void defineMorphology()
         "Likewise for a 2D uint8 input array.\n");
 
     def("distanceTransform3D",
-        registerConverters(&pythonDistanceTransform3D<float>),
+        registerConverters(&pythonDistanceTransformND<3, float>),
         (arg("array"), 
          arg("background") = true, 
          arg("pixel_pitch") = ArrayVector<double>(), 
@@ -773,6 +982,235 @@ void defineMorphology()
         "given, the data is treated isotropically with unit distance between pixels.\n"
         "\n"
         "For more details see separableMultiDistance_ in the vigra C++ documentation.\n");
+        
+    def("vectorDistanceTransform",
+        registerConverters(&pythonVectorDistanceTransformND<2, float>),
+        (arg("array"), 
+         arg("background") = true, 
+         arg("pixel_pitch") = ArrayVector<double>(), 
+         arg("out")=python::object()),
+        "Perform a Euclidean distance transform and return, for each background pixel, the\n"
+        "difference vector to the nearest foreground pixel (when 'background=True', the\n"
+        "default), or the other way around (when 'background=False').\n"
+        "Otherwise, this function behaves like :func:`distanceTransform2D` (which just\n"
+        "returns the magnitude of the difference vectors).\n"
+        "\n"
+        "For more detailed documentation, see :func:`distanceTransform2D` and\n" "separableVectorDistance_ in the vigra C++ documentation.\n");
+        
+    def("vectorDistanceTransform",
+        registerConverters(&pythonVectorDistanceTransformND<2, npy_uint32>),
+        (arg("array"), 
+         arg("background") = true, 
+         arg("pixel_pitch") = ArrayVector<double>(), 
+         arg("out")=python::object()),
+        "Likewise for uint32 images.\n");
+        
+    def("vectorDistanceTransform",
+        registerConverters(&pythonVectorDistanceTransformND<3, float>),
+        (arg("array"), 
+         arg("background") = true, 
+         arg("pixel_pitch") = ArrayVector<double>(), 
+         arg("out")=python::object()),
+        "Likewise for 3D arrays.\n");
+        
+    def("vectorDistanceTransform",
+        registerConverters(&pythonVectorDistanceTransformND<3, npy_uint32>),
+        (arg("array"), 
+         arg("background") = true, 
+         arg("pixel_pitch") = ArrayVector<double>(), 
+         arg("out")=python::object()),
+        "Likewise for 3D uint32 arrays.\n");
+        
+    def("boundaryDistanceTransform",
+       registerConverters(&pythonboundaryDistanceTransform<2, npy_uint32>),
+       (arg("image"),
+        arg("array_border_is_active") = false,
+        arg("boundary") = "InterpixelBoundary",
+        arg("out")=python::object()),
+        "Compute the Euclidean distance transform of all regions in a 2D or 3D label\n"
+        "array with respect to the region boundaries. The 'boundary' parameter must be\n"
+        "one of the following strings:\n\n"
+        "   - 'OuterBoundary':  compute distance relative to outer regin boundaries\n\n"
+        "   - 'InterpixelBoundary':  compute distance relative to interpixel boundaries (default)\n\n"
+        "   - 'InnerBoundary':  compute distance relative to inner region boundaries\n\n"
+        "where the outer boundary consists of the pixels touching a given region from the\n"
+        "outside and the inner boundary are the pixels adjacent to the region's complement.\n"
+        "If 'array_border_is_active=True', the external border of the array (i.e. the border\n"
+        "between the image and the infinite region) is also used. Otherwise (default), regions\n"
+        "touching the array border are treated as if they extended to infinity.\n"
+        "\n"
+        "For more details see boundaryMultiDistance_ in the vigra C++ documentation.\n");
+
+    def("boundaryDistanceTransform",
+       registerConverters(&pythonboundaryDistanceTransform<3, npy_uint32>),
+       (arg("volume"),
+        arg("array_border_is_active") = false,
+        arg("boundary") = "InterpixelBoundary",
+        arg("out")=python::object()),
+         "Likewise for a 3D uint32 input array.\n");
+
+    def("boundaryDistanceTransform",
+       registerConverters(&pythonboundaryDistanceTransform<2, float>),
+       (arg("image"),
+        arg("array_border_is_active") = false,
+        arg("boundary") = "InterpixelBoundary",
+        arg("out")=python::object()),
+         "Likewise for a 2D float32 input array.\n");
+
+    def("boundaryDistanceTransform",
+       registerConverters(&pythonboundaryDistanceTransform<3, float>),
+       (arg("volume"),
+        arg("array_border_is_active") = false,
+        arg("boundary") = "InterpixelBoundary",
+        arg("out")=python::object()),
+         "Likewise for a 3D float32 input array.\n");
+
+    def("boundaryVectorDistanceTransform",
+       registerConverters(&pythonboundaryVectorDistanceTransform<2, npy_uint32>),
+       (arg("image"),
+        arg("array_border_is_active") = false,
+        arg("boundary") = "InterpixelBoundary",
+        arg("out")=python::object()),
+        "Compute the Euclidean distance transform of all regions in a 2D or 3D label\n"
+        "array with respect to the region boundaries and return, in each pixel,\n"
+        "the difference vector to the nearest boundary point.\n"
+        "The 'boundary' parameter must be one of the following strings:\n\n"
+        "   - 'OuterBoundary':  compute distance relative to outer regin boundaries\n\n"
+        "   - 'InterpixelBoundary':  compute distance relative to interpixel boundaries (default)\n\n"
+        "   - 'InnerBoundary':  compute distance relative to inner region boundaries\n\n"
+        "where the outer boundary consists of the pixels touching a given region from the\n"
+        "outside and the inner boundary are the pixels adjacent to the region's complement.\n"
+        "If 'array_border_is_active=True', the external border of the array (i.e. the border\n"
+        "between the image and the infinite region) is also used. Otherwise (default), regions\n"
+        "touching the array border are treated as if they extended to infinity.\n"
+        "\n"
+        "For more details see :func:`boundaryDistanceTransform` and boundaryVectorDistance_ in\n"
+        "the vigra C++ documentation.\n");
+
+    def("boundaryVectorDistanceTransform",
+       registerConverters(&pythonboundaryVectorDistanceTransform<3, npy_uint32>),
+       (arg("volume"),
+        arg("array_border_is_active") = false,
+        arg("boundary") = "InterpixelBoundary",
+        arg("out")=python::object()),
+         "Likewise for a 3D uint32 input array.\n");
+
+    def("boundaryVectorDistanceTransform",
+       registerConverters(&pythonboundaryVectorDistanceTransform<2, float>),
+       (arg("image"),
+        arg("array_border_is_active") = false,
+        arg("boundary") = "InterpixelBoundary",
+        arg("out")=python::object()),
+         "Likewise for a 2D float32 input array.\n");
+
+    def("boundaryVectorDistanceTransform",
+       registerConverters(&pythonboundaryVectorDistanceTransform<3, float>),
+       (arg("volume"),
+        arg("array_border_is_active") = false,
+        arg("boundary") = "InterpixelBoundary",
+        arg("out")=python::object()),
+         "Likewise for a 3D float32 input array.\n");
+
+    def("eccentricityTransform",
+        registerConverters(&pythonEccentricityTransform<2, UInt32, float>),
+        (arg("image"),
+         arg("out")=python::object()),
+        "Compute the eccentricity transform of a 2D uint32 label array.\n\n"
+        "For more details see eccentricityTransformOnLabels_ in the vigra C++ documentation.\n");
+
+    def("eccentricityTransform",
+        registerConverters(&pythonEccentricityTransform<2, UInt8, float>),
+        (arg("image"),
+         arg("out")=python::object()),
+         "Likewise for a 2D uint8 input array.\n");
+
+    def("eccentricityTransform",
+        registerConverters(&pythonEccentricityTransform<3, UInt32, float>),
+        (arg("image"),
+         arg("out")=python::object()),
+         "Likewise for a 3D uint32 label array.\n");
+
+    def("eccentricityTransform",
+        registerConverters(&pythonEccentricityTransform<3, UInt8, float>),
+        (arg("image"),
+         arg("out")=python::object()),
+         "Likewise for a 3D uint8 input array.\n");
+
+    def("eccentricityCenters",
+        registerConverters(&pythonEccentricityCenters<2, UInt32>),
+        (arg("image")),
+         "Compute a list holding the eccentricity center of each region in\n"
+         "a 2D uint32 label array.\n\n"
+         "For more details see eccentricityCenters_ in the vigra C++ documentation.\n");
+
+    def("eccentricityCenters",
+        registerConverters(&pythonEccentricityCenters<2, UInt8>),
+        (arg("image")),
+         "Likewise for a 2D uint8 input array.\n");
+
+    def("eccentricityCenters",
+        registerConverters(&pythonEccentricityCenters<3, UInt32>),
+        (arg("image")),
+         "Likewise for a 3D uint32 label array.\n");
+
+    def("eccentricityCenters",
+        registerConverters(&pythonEccentricityCenters<3, UInt8>),
+        (arg("image")),
+         "Likewise for a 3D uint8 array.\n");
+
+    def("eccentricityTransformWithCenters",
+        registerConverters(&pythonEccentricityTransformWithCenters<2, UInt32, float>),
+        (arg("image"),
+         arg("out")=python::object()),
+         "Compute the eccentricity transform and eccentricity centers of a 2D uint32 label array.\n"
+         "\n"
+         "Returns the tuple (ecc_image, centers).\n");
+
+    def("eccentricityTransformWithCenters",
+        registerConverters(&pythonEccentricityTransformWithCenters<2, UInt8, float>),
+        (arg("image"),
+         arg("out")=python::object()),
+         "Likewise for a 2D uint8 input array.\n");
+
+    def("eccentricityTransformWithCenters",
+        registerConverters(&pythonEccentricityTransformWithCenters<3, UInt32, float>),
+        (arg("image"),
+         arg("out")=python::object()),
+         "Likewise for a 3D uint32 label array.\n");
+
+    def("eccentricityTransformWithCenters",
+        registerConverters(&pythonEccentricityTransformWithCenters<3, UInt8, float>),
+        (arg("image"),
+         arg("out")=python::object()),
+         "Likewise for a 2D uint8 input array.\n");
+
+    def("skeletonizeImage",
+        registerConverters(&pySkeletonizeImage<2, UInt32>),
+        (arg("labels"),
+         arg("mode")="PruneSalienceRelative",
+         arg("pruning_threshold")=0.2),
+         "Skeletonize all regions in the given label image. Each skeleton receives\n"
+         "the label of the corresponding region, unless 'length' or 'salience' are\n"
+         "requested, in which case the skeleton points hold real numbers. Non-skeleton\n"
+         "points always have the value zero. When the input image contains label zero,\n"
+         "it is always considered background and therefore ignored.\n"
+         "The 'mode' must be one of the following strings:\n\n"
+            "   - 'DontPrune':  don't remove any branches\n\n"
+            "   - 'ReturnLength':  mark each pixel with the length of the longest branch\n"
+            "                      it belongs to\n\n"
+            "   - 'PruneLength':  remove all branches that are shorter than the given\n" "                     'pruning_threshold'\n\n"
+            "   - 'PruneLengthRelative':  remove all branches that are shorter than the\n" "                             fraction specified in 'pruning_threshold' of the\n"
+            "                             longest branch in the present region\n\n"
+            "   - 'ReturnSalience':  mark each pixel with the salience of the longest branch\n"
+            "                        it belongs to\n\n"
+            "   - 'PruneSalience':  remove all branches whose salience is less than the given\n" "                       'pruning_threshold'\n\n"
+            "   - 'PruneSalienceRelative':  remove all branches whose salience is less than the\n" "                               fraction specified in 'pruning_threshold' of the\n"
+            "                               most salient branch in the present region\n"
+            "                               (default with pruning_threshold=0.2)\n\n"
+            "   - 'PruneTopology':  prune all branches that are not essential for the topology,\n"
+            "                       but keep the skeleton center\n\n"
+            "   - 'PruneAggressive':  like 'PruneTopology', but don't necessarily preserve the center\n\n"
+            "For details see skeletonizeImage_ in the vigra C++ documentation.\n");
 }
 
 } // namespace vigra
diff --git a/vigranumpy/src/core/multi_array_chunked.cxx b/vigranumpy/src/core/multi_array_chunked.cxx
new file mode 100644
index 0000000..00ab168
--- /dev/null
+++ b/vigranumpy/src/core/multi_array_chunked.cxx
@@ -0,0 +1,804 @@
+/************************************************************************/
+/*                                                                      */
+/*               Copyright 2013-2014 by Ullrich Koethe                  */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#define NO_IMPORT_ARRAY
+
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/axistags.hxx>
+#include <vigra/multi_array_chunked.hxx>
+#ifdef HasHDF5
+#include <vigra/multi_array_chunked_hdf5.hxx>
+#endif
+#include <vigra/compression.hxx>
+#include <boost/python.hpp>
+#include <boost/python/slice.hpp>
+
+#include <sstream>
+
+namespace python = boost::python;
+
+namespace vigra {
+
+template <unsigned int N, class T>
+TinyVector<MultiArrayIndex, N>
+ChunkedArray_shape(ChunkedArray<N, T> const & array)
+{
+    return array.shape();
+}
+
+template <unsigned int N, class T>
+TinyVector<MultiArrayIndex, N>
+ChunkedArray_chunkShape(ChunkedArray<N, T> const & array)
+{
+    return array.chunkShape();
+}
+
+template <unsigned int N, class T>
+TinyVector<MultiArrayIndex, N>
+ChunkedArray_chunkArrayShape(ChunkedArray<N, T> const & array)
+{
+    return array.chunkArrayShape();
+}
+
+template <unsigned int N, class T>
+std::string ChunkedArray_repr(ChunkedArray<N, T> const & array)
+{
+    std::stringstream s;
+    s << array.backend() << "( shape=" << array.shape() <<
+           ", dtype=" << NumpyArrayValuetypeTraits<T>::typeName() << ")";
+    return s.str();
+}
+
+template <unsigned int N, class T>
+std::string ChunkedArray_str(ChunkedArray<N, T> const & array)
+{
+    return ChunkedArray_repr(array);
+}
+
+template <unsigned int N, class T>
+PyObject * ChunkedArray_dtype(ChunkedArray<N, T> const &)
+{
+    return NumpyArrayValuetypeTraits<T>::typeObject();
+}
+
+template <unsigned int N, class T>
+unsigned int ChunkedArray_ndim(ChunkedArray<N, T> const &)
+{
+    return N;
+}
+
+template <unsigned int N, class T>
+NumpyAnyArray
+ChunkedArray_checkoutSubarray(python::object array,
+                              TinyVector<MultiArrayIndex, N> const & start,
+                              TinyVector<MultiArrayIndex, N> const & stop,
+                              NumpyArray<N, T> res = NumpyArray<N, T>())
+{
+    ChunkedArray<N, T> const & self = python::extract<ChunkedArray<N, T> const &>(array)();
+
+    python_ptr pytags;
+    if(PyObject_HasAttrString(array.ptr(), "axistags"))
+    {
+        pytags = python_ptr(PyObject_GetAttrString(array.ptr(), "axistags"), python_ptr::keep_count);
+    }
+    PyAxisTags tags(pytags, true);
+    TaggedShape shape(stop-start, tags);
+    res.reshapeIfEmpty(shape,
+        "ChunkedArray::checkoutSubarray(): Output array has wrong shape.");
+
+    {
+        PyAllowThreads _pythread;
+        self.checkoutSubarray(start, res);
+    }
+    return res;
+}
+
+template <unsigned int N, class T>
+void
+ChunkedArray_commitSubarray(ChunkedArray<N, T> & self,
+                            TinyVector<MultiArrayIndex, N> const & start,
+                            NumpyArray<N, T> array)
+{
+    PyAllowThreads _pythread;
+    self.commitSubarray(start, array);
+}
+
+template <class Shape>
+python::object
+bindNumpyArray(NumpyAnyArray self, Shape const & stop)
+{
+    if(stop == Shape())
+        return python::object(self);
+
+    python_ptr func(PyString_FromString("__getitem__"), python_ptr::keep_count);
+    pythonToCppException(func);
+    python_ptr index(PyTuple_New(stop.size()), python_ptr::keep_count);
+    pythonToCppException(index);
+    for(unsigned int k=0; k<stop.size(); ++k)
+    {
+        PyObject * item = stop[k] == 0
+                            ? PyInt_FromLong(0)
+                            : PySlice_New(0,0,0);
+        pythonToCppException(item);
+        PyTuple_SET_ITEM((PyTupleObject *)index.ptr(), k, item);
+    }
+
+    return python::object(python::detail::new_non_null_reference(PyObject_CallMethodObjArgs(self.pyObject(), func.ptr(), index.ptr(), NULL)));
+}
+
+template <unsigned int N, class T>
+python::object
+ChunkedArray_getitem(python::object array, python::object index)
+{
+    typedef typename ChunkedArray<N, T>::shape_type Shape;
+
+    ChunkedArray<N, T> const & self = python::extract<ChunkedArray<N, T> const &>(array)();
+    Shape start, stop;
+    numpyParseSlicing(self.shape(), index.ptr(), start, stop);
+    if(start == stop)
+    {
+        // return a single point
+        return python::object(self.getItem(start));
+    }
+    else if(allLessEqual(start, stop))
+    {
+        // return a slice
+        NumpyAnyArray subarray = ChunkedArray_checkoutSubarray<N,T>(array, start, max(start + Shape(1), stop));
+        return python::object(subarray.getitem(Shape(), stop-start));
+    }
+    else
+    {
+        vigra_precondition(false,
+            "ChunkedArray.__getitem__(): index out of bounds.");
+        return python::object();
+    }
+}
+
+template <unsigned int N, class T>
+void
+ChunkedArray_setitem(ChunkedArray<N, T> & self, python::object index, T value)
+{
+    typedef typename ChunkedArray<N, T>::shape_type Shape;
+    Shape start, stop;
+    numpyParseSlicing(self.shape(), index.ptr(), start, stop);
+    if(start == stop)
+    {
+        self.setItem(start, value);
+    }
+    else
+    {
+        PyAllowThreads _pythread;
+        stop = max(start + Shape(1), stop);
+        typename ChunkedArray<N, T>::iterator i(self.begin().restrictToSubarray(start, stop)),
+                                              end(i.getEndIterator());
+        for(; i != end; ++i)
+            *i = value;
+    }
+}
+
+template <unsigned int N, class T>
+void
+ChunkedArray_setitem2(ChunkedArray<N, T> & self, python::object index, NumpyArray<N, T> array)
+{
+    typedef typename ChunkedArray<N, T>::shape_type Shape;
+    Shape start, stop;
+    numpyParseSlicing(self.shape(), index.ptr(), start, stop);
+    stop = max(start + Shape(1), stop);
+    vigra_precondition(array.shape() == stop - start,
+        "ChunkedArray.__setitem__(): shape mismatch");
+
+    PyAllowThreads _pythread;
+    self.commitSubarray(start, array);
+}
+
+python::object defaultDtype()
+{
+    PyObject * dtype = NumpyArrayValuetypeTraits<npy_float32>::typeObject();
+    return python::object(python::detail::new_reference(dtype));
+}
+
+int numpyScalarTypeNumber(python::object obj)
+{
+    PyArray_Descr* dtype;
+    if(!PyArray_DescrConverter(obj.ptr(), &dtype))
+        return NPY_NOTYPE;
+    int typeNum = dtype->type_num;
+    Py_DECREF(dtype);
+    return typeNum;
+}
+
+template <class Array>
+PyObject *
+ptr_to_python(Array * array, python::object axistags)
+{
+    python_ptr py_array(python::to_python_indirect<Array*,
+                                      python::detail::make_owning_holder>()(array),
+                        python_ptr::new_nonzero_reference);
+    if(axistags != python::object())
+    {
+        AxisTags at;
+        if(PyString_Check(axistags.ptr()))
+            at = AxisTags(python::extract<std::string>(axistags)());
+        else
+            at = AxisTags(python::extract<AxisTags const &>(axistags)());
+        int N = Array::shape_type::static_size;
+        vigra_precondition(at.size() == 0 || at.size() == N,
+            "ChunkedArray(): axistags have invalid length.");
+        if(at.size() == N)
+        {
+            int res = PyObject_SetAttrString(py_array, "axistags", python::object(at).ptr());
+            pythonToCppException(res != 0);
+        }
+    }
+    return py_array.release();
+}
+
+template <class T, int N>
+ChunkedArray<N, T> *
+construct_ChunkedArrayFullImpl(TinyVector<MultiArrayIndex, N> const & shape,
+                               double fill_value)
+{
+    return new ChunkedArrayFull<N, T>(shape,
+                                      ChunkedArrayOptions().fillValue(fill_value));
+}
+
+template <unsigned int N>
+PyObject *
+construct_ChunkedArrayFull(TinyVector<MultiArrayIndex, N> const & shape,
+                           python::object dtype, double fill_value,
+                           python::object axistags)
+{
+    switch(numpyScalarTypeNumber(dtype))
+    {
+      case NPY_UINT8:
+        return ptr_to_python(construct_ChunkedArrayFullImpl<npy_uint8>(shape, fill_value), axistags);
+      case NPY_UINT32:
+        return ptr_to_python(construct_ChunkedArrayFullImpl<npy_uint32>(shape, fill_value), axistags);
+      case NPY_FLOAT32:
+        return ptr_to_python(construct_ChunkedArrayFullImpl<npy_float32>(shape, fill_value), axistags);
+      default:
+        vigra_precondition(false, "ChunkedArrayFull(): unsupported dtype.");
+    }
+    return 0;
+}
+
+template <class T, int N>
+ChunkedArray<N, T> *
+construct_ChunkedArrayLazyImpl(TinyVector<MultiArrayIndex, N> const & shape,
+                               TinyVector<MultiArrayIndex, N> const & chunk_shape,
+                               double fill_value)
+{
+    return new ChunkedArrayLazy<N, T>(shape, chunk_shape,
+                                      ChunkedArrayOptions().fillValue(fill_value));
+}
+
+template <unsigned int N>
+PyObject *
+construct_ChunkedArrayLazy(TinyVector<MultiArrayIndex, N> const & shape,
+                           python::object dtype,
+                           TinyVector<MultiArrayIndex, N> const & chunk_shape,
+                           double fill_value,
+                           python::object axistags)
+{
+    switch(numpyScalarTypeNumber(dtype))
+    {
+      case NPY_UINT8:
+        return ptr_to_python(construct_ChunkedArrayLazyImpl<npy_uint8>(shape, chunk_shape, fill_value), axistags);
+      case NPY_UINT32:
+        return ptr_to_python(construct_ChunkedArrayLazyImpl<npy_uint32>(shape, chunk_shape, fill_value), axistags);
+      case NPY_FLOAT32:
+        return ptr_to_python(construct_ChunkedArrayLazyImpl<npy_float32>(shape, chunk_shape, fill_value), axistags);
+      default:
+        vigra_precondition(false, "ChunkedArrayLazy(): unsupported dtype.");
+    }
+    return 0;
+}
+
+template <class T, int N>
+ChunkedArray<N, T> *
+construct_ChunkedArrayCompressedImpl(TinyVector<MultiArrayIndex, N> const & shape,
+                                     CompressionMethod method,
+                                     TinyVector<MultiArrayIndex, N> const & chunk_shape,
+                                     int cache_max,
+                                     double fill_value)
+{
+    return new ChunkedArrayCompressed<N, T>(shape, chunk_shape,
+            ChunkedArrayOptions().compression(method).cacheMax(cache_max).fillValue(fill_value));
+}
+
+template <unsigned int N>
+PyObject *
+construct_ChunkedArrayCompressed(TinyVector<MultiArrayIndex, N> const & shape,
+                                 CompressionMethod method,
+                                 python::object dtype,
+                                 TinyVector<MultiArrayIndex, N> const & chunk_shape,
+                                 int cache_max,
+                                 double fill_value,
+                                 python::object axistags)
+{
+    switch(numpyScalarTypeNumber(dtype))
+    {
+      case NPY_UINT8:
+        return ptr_to_python(construct_ChunkedArrayCompressedImpl<npy_uint8>(shape, method, chunk_shape,
+                             cache_max, fill_value), axistags);
+      case NPY_UINT32:
+        return ptr_to_python(construct_ChunkedArrayCompressedImpl<npy_uint32>(shape, method, chunk_shape,
+                             cache_max, fill_value), axistags);
+      case NPY_FLOAT32:
+        return ptr_to_python(construct_ChunkedArrayCompressedImpl<npy_float32>(shape, method, chunk_shape,
+                             cache_max, fill_value), axistags);
+      default:
+        vigra_precondition(false, "ChunkedArrayCompressed(): unsupported dtype.");
+    }
+    return 0;
+}
+
+template <class T, int N>
+ChunkedArray<N, T> *
+construct_ChunkedArrayTmpFileImpl(TinyVector<MultiArrayIndex, N> const & shape,
+                                  TinyVector<MultiArrayIndex, N> const & chunk_shape,
+                                  int cache_max,
+                                  std::string path,
+                                  double fill_value)
+{
+    return new ChunkedArrayTmpFile<N, T>(shape, chunk_shape,
+                                ChunkedArrayOptions().cacheMax(cache_max).fillValue(fill_value), path);
+}
+
+template <unsigned int N>
+PyObject *
+construct_ChunkedArrayTmpFile(TinyVector<MultiArrayIndex, N> const & shape,
+                              python::object dtype,
+                              TinyVector<MultiArrayIndex, N> const & chunk_shape,
+                              int cache_max,
+                              std::string path,
+                              double fill_value,
+                              python::object axistags)
+{
+    switch(numpyScalarTypeNumber(dtype))
+    {
+      case NPY_UINT8:
+        return ptr_to_python(construct_ChunkedArrayTmpFileImpl<npy_uint8>(shape, chunk_shape, cache_max,
+                             path, fill_value), axistags);
+      case NPY_UINT32:
+        return ptr_to_python(construct_ChunkedArrayTmpFileImpl<npy_uint32>(shape, chunk_shape, cache_max,
+                             path, fill_value), axistags);
+      case NPY_FLOAT32:
+        return ptr_to_python(construct_ChunkedArrayTmpFileImpl<npy_float32>(shape, chunk_shape, cache_max,
+                             path, fill_value), axistags);
+      default:
+        vigra_precondition(false, "ChunkedArrayTmpFile(): unsupported dtype.");
+    }
+    return 0;
+}
+
+#ifdef HasHDF5
+
+template <class T, int N>
+ChunkedArrayHDF5<N, T> *
+construct_ChunkedArrayHDF5Impl(HDF5File const & file,
+                               std::string datasetName,
+                               TinyVector<MultiArrayIndex, N> const & shape,
+                               HDF5File::OpenMode mode,
+                               CompressionMethod method,
+                               TinyVector<MultiArrayIndex, N> const & chunk_shape,
+                               int cache_max,
+                               double fill_value)
+{
+    return new ChunkedArrayHDF5<N, T>(file, datasetName, mode,
+                                      shape, chunk_shape,
+                                      ChunkedArrayOptions().compression(method).cacheMax(cache_max).fillValue(fill_value));
+}
+
+template <unsigned int N>
+PyObject *
+construct_ChunkedArrayHDF5Impl(HDF5File const & file,
+                               std::string datasetName,
+                               TinyVector<MultiArrayIndex, N> const & shape,
+                               python::object dtype,
+                               HDF5File::OpenMode mode,
+                               CompressionMethod compression,
+                               TinyVector<MultiArrayIndex, N> const & chunk_shape,
+                               int cache_max,
+                               double fill_value,
+                               python::object axistags)
+{
+    int dtype_code = NPY_FLOAT32;
+
+    if(dtype != python::object())
+    {
+        dtype_code = numpyScalarTypeNumber(dtype);
+    }
+    else if(file.existsDataset(datasetName))
+    {
+        std::string type = file.getDatasetType(datasetName);
+        if(type == "UINT8")
+            dtype_code = NPY_UINT8;
+        else if(type == "UINT32")
+            dtype_code = NPY_UINT32;
+    }
+    switch(dtype_code)
+    {
+      case NPY_UINT8:
+        return ptr_to_python(construct_ChunkedArrayHDF5Impl<npy_uint8>(file, datasetName, shape,
+                             mode, compression, chunk_shape, cache_max, fill_value), axistags);
+      case NPY_UINT32:
+        return ptr_to_python(construct_ChunkedArrayHDF5Impl<npy_uint32>(file, datasetName, shape,
+                             mode, compression, chunk_shape, cache_max, fill_value), axistags);
+      case NPY_FLOAT32:
+        return ptr_to_python(construct_ChunkedArrayHDF5Impl<npy_float32>(file, datasetName, shape,
+                             mode, compression, chunk_shape, cache_max, fill_value), axistags);
+      default:
+        vigra_precondition(false, "ChunkedArrayHDF5(): unsupported dtype.");
+    }
+    return 0;
+}
+
+PyObject *
+construct_ChunkedArrayHDF5Impl(HDF5File const & file,
+                               std::string datasetName,
+                               python::object py_shape,
+                               python::object dtype,
+                               HDF5File::OpenMode mode,
+                               CompressionMethod compression,
+                               python::object py_chunk_shape,
+                               int cache_max,
+                               double fill_value,
+                               python::object axistags)
+{
+    int ndim = 0;
+    bool has_shape = PySequence_Check(py_shape.ptr());
+    bool use_existing_dataset = file.existsDataset(datasetName) &&
+                                mode != HDF5File::New;
+    if(use_existing_dataset)
+    {
+        ndim = file.getDatasetDimensions(datasetName);
+        vigra_precondition(!has_shape || ndim == python::len(py_shape),
+            "ChunkedArrayHDF5(): dimension mismatch between dataset and requested shape.");
+    }
+    else
+    {
+        vigra_precondition(has_shape,
+            "ChunkedArrayHDF5(): cannot create dataset because no shape is given.");
+        ndim = python::len(py_shape);
+    }
+
+    bool has_chunk_shape = false;
+    if(PySequence_Check(py_chunk_shape.ptr()))
+    {
+        vigra_precondition(python::len(py_chunk_shape) == ndim,
+            "ChunkedArrayHDF5(): chunk_shape has wrong dimension.");
+        has_chunk_shape = true;
+    }
+
+    switch(ndim)
+    {
+      case 1:
+      {
+        typedef Shape1 shape_type;
+
+        shape_type shape = has_shape
+                                ? python::extract<shape_type>(py_shape)()
+                                : shape_type(),
+                   chunk_shape = has_chunk_shape
+                                ? python::extract<shape_type>(py_chunk_shape)()
+                                : shape_type();
+        return construct_ChunkedArrayHDF5Impl<1>(file, datasetName, shape, dtype,
+                             mode, compression, chunk_shape, cache_max, fill_value, axistags);
+      }
+      case 2:
+      {
+        typedef Shape2 shape_type;
+
+        shape_type shape = has_shape
+                                ? python::extract<shape_type>(py_shape)()
+                                : shape_type(),
+                   chunk_shape = has_chunk_shape
+                                ? python::extract<shape_type>(py_chunk_shape)()
+                                : shape_type();
+        return construct_ChunkedArrayHDF5Impl<2>(file, datasetName, shape, dtype,
+                             mode, compression, chunk_shape, cache_max, fill_value, axistags);
+      }
+      case 3:
+      {
+        typedef Shape3 shape_type;
+
+        shape_type shape = has_shape
+                                ? python::extract<shape_type>(py_shape)()
+                                : shape_type(),
+                   chunk_shape = has_chunk_shape
+                                ? python::extract<shape_type>(py_chunk_shape)()
+                                : shape_type();
+        return construct_ChunkedArrayHDF5Impl<3>(file, datasetName, shape, dtype,
+                             mode, compression, chunk_shape, cache_max, fill_value, axistags);
+      }
+      case 4:
+      {
+        typedef Shape4 shape_type;
+
+        shape_type shape = has_shape
+                                ? python::extract<shape_type>(py_shape)()
+                                : shape_type(),
+                   chunk_shape = has_chunk_shape
+                                ? python::extract<shape_type>(py_chunk_shape)()
+                                : shape_type();
+        return construct_ChunkedArrayHDF5Impl<4>(file, datasetName, shape, dtype,
+                             mode, compression, chunk_shape, cache_max, fill_value, axistags);
+      }
+      case 5:
+      {
+        typedef Shape5 shape_type;
+
+        shape_type shape = has_shape
+                                ? python::extract<shape_type>(py_shape)()
+                                : shape_type(),
+                   chunk_shape = has_chunk_shape
+                                ? python::extract<shape_type>(py_chunk_shape)()
+                                : shape_type();
+        return construct_ChunkedArrayHDF5Impl<5>(file, datasetName, shape, dtype,
+                             mode, compression, chunk_shape, cache_max, fill_value, axistags);
+      }
+      default:
+        vigra_precondition(false, "ChunkedArrayHDF5(): unsupported array dimension (1 <= ndim <= 5 required).");
+    }
+    return 0;
+}
+
+PyObject *
+construct_ChunkedArrayHDF5(std::string filename,
+                           std::string datasetName,
+                           python::object shape,
+                           python::object dtype,
+                           HDF5File::OpenMode mode,
+                           CompressionMethod compression,
+                           python::object chunk_shape,
+                           int cache_max,
+                           double fill_value,
+                           python::object axistags)
+{
+    bool file_exists = isHDF5(filename.c_str());
+    if(mode == HDF5File::Default)
+    {
+        if(!file_exists)
+            mode = HDF5File::New;
+        else if(HDF5File(filename, HDF5File::ReadOnly).existsDataset(datasetName))
+            mode = HDF5File::ReadOnly;
+        else
+            mode = HDF5File::Replace;
+    }
+    HDF5File::OpenMode filemode = mode;
+    if(mode == HDF5File::Replace)
+    {
+        mode = HDF5File::New;
+        if(file_exists)
+            filemode = HDF5File::ReadWrite;
+        else
+            filemode = HDF5File::New;
+    }
+    HDF5File file(filename, filemode);
+    return construct_ChunkedArrayHDF5Impl(file, datasetName, shape, dtype, mode, compression,
+                               chunk_shape, cache_max, fill_value, axistags);
+}
+
+PyObject *
+construct_ChunkedArrayHDF5id(hid_t file_id,
+                             std::string datasetName,
+                             python::object shape,
+                             python::object dtype,
+                             HDF5File::OpenMode mode,
+                             CompressionMethod compression,
+                             python::object chunk_shape,
+                             int cache_max,
+                             double fill_value,
+                             python::object axistags)
+{
+    HDF5HandleShared handle(file_id, 0, "");
+    HDF5File file(handle);
+    return construct_ChunkedArrayHDF5Impl(file, datasetName, shape, dtype, mode, compression,
+                               chunk_shape, cache_max, fill_value, axistags);
+}
+
+#endif
+
+template <unsigned int N, class T>
+void defineChunkedArrayImpl()
+{
+    using namespace boost::python;
+
+    docstring_options doc_options(true, false, false);
+
+    typedef ChunkedArray<N, T> Array;
+    class_<Array, boost::noncopyable>("ChunkedArray",
+         "\n"
+         "Base class for chunked arrays.\n\n",
+         no_init)
+        .add_property("shape", &ChunkedArray_shape<N, T>,
+             "\nshape of the array.\n")
+        .add_property("chunk_shape", &ChunkedArray_chunkShape<N, T>,
+             "\nshape of (interior) chunks.\n")
+        .add_property("chunk_array_shape", &ChunkedArray_chunkArrayShape<N, T>,
+             "\nshape of internal array of chunks.\n")
+        .add_property("size", &Array::size,
+             "\nnumber of elements of the array.\n")
+        .add_property("overhead_bytes", &Array::overheadBytes,
+             "\nsize of the overhead caused by chunked storage.\n")
+        .add_property("data_bytes", (std::size_t (Array::*)() const)&Array::dataBytes,
+             "\nsize of the currently allocated part of the data.\n")
+        .add_property("overhead_bytes_per_chunk", &Array::overheadBytesPerChunk,
+             "\nsize of the overhead caused by chunked storage for a single chunk.\n")
+        .add_property("data_bytes_per_chunk", &Array::dataBytesPerChunk,
+             "\nsize of the data of a single chunk.\n")
+        .add_property("backend", &Array::backend,
+             "\nthe backend driver of this array.\n")
+        .add_property("read_only", &Array::isReadOnly,
+             "\n'True' if array values cannot be changed.\n")
+        .add_property("cache_max_size",
+             &Array::cacheMaxSize, &Array::setCacheMaxSize,
+             "\nget/set the size of the chunk cache.\n")
+        .add_property("dtype", &ChunkedArray_dtype<N, T>,
+             "\nthe array's value type\n")
+        .add_property("ndim", &ChunkedArray_ndim<N, T>,
+             "\nthe array's dimension\n")
+        .def("__repr__", &ChunkedArray_repr<N, T>)
+        .def("__str__", &ChunkedArray_str<N, T>)
+        .def("checkoutSubarray",
+             registerConverters(&ChunkedArray_checkoutSubarray<N, T>),
+             (arg("start"), arg("stop"), arg("out")=python::object()),
+             "\nobtain a copy of the specified subarray.\n")
+        .def("commitSubarray",
+             registerConverters(&ChunkedArray_commitSubarray<N, T>),
+             (arg("start"), arg("array")),
+             "\nwrite the given array at offset 'start'.\n")
+        .def("releaseChunks",
+             &Array::releaseChunks,
+             (arg("start"), arg("stop"),arg("destroy")=false),
+             "\nrelease or destroy all chunks that are completely contained in [start, stop).\n")
+        .def("__getitem__", &ChunkedArray_getitem<N, T>)
+        .def("__setitem__", &ChunkedArray_setitem<N, T>)
+        .def("__setitem__", &ChunkedArray_setitem2<N, T>)
+        ;
+
+#ifdef HasHDF5
+    typedef ChunkedArrayHDF5<N, T> ArrayHDF5;
+    class_<ChunkedArrayHDF5<N, T>, bases<Array>, boost::noncopyable>("ChunkedArrayHDF5", no_init)
+        .def("close", &ArrayHDF5::close)
+        .def("flush", &ArrayHDF5::flushToDisk)
+        .add_property("filename", &ArrayHDF5::fileName,
+             "\nname of the file backend of this array.\n")
+        .add_property("dataset_name", &ArrayHDF5::datasetName,
+             "\nname of the dataset backend of this array.\n")
+        .add_property("readonly", &ArrayHDF5::isReadOnly,
+             "\nTrue if this array is read-only.\n")
+    ;
+#endif
+}
+
+template <unsigned int N>
+void defineChunkedArrayFactories()
+{
+    using namespace boost::python;
+    typedef typename MultiArrayShape<N>::type shape_type;
+
+    docstring_options doc_options(true, false, false);
+
+    def("ChunkedArrayFull", &construct_ChunkedArrayFull<N>,
+        (arg("shape"), arg("dtype")=defaultDtype(), arg("fill_value")=0.0, arg("axistags")=python::object()));
+    def("ChunkedArrayLazy", &construct_ChunkedArrayLazy<N>,
+        (arg("shape"), arg("dtype")=defaultDtype(),
+         arg("chunk_shape")=shape_type(), arg("fill_value")=0.0, arg("axistags")=python::object()));
+    def("ChunkedArrayCompressed", &construct_ChunkedArrayCompressed<N>,
+        (arg("shape"), arg("compression")=LZ4, arg("dtype")=defaultDtype(), arg("chunk_shape")=shape_type(),
+         arg("cache_max")=-1, arg("fill_value")=0.0, arg("axistags")=python::object()));
+    def("ChunkedArrayTmpFile", &construct_ChunkedArrayTmpFile<N>,
+        (arg("shape"), arg("dtype")=defaultDtype(), arg("chunk_shape")=shape_type(),
+         arg("cache_max")=-1, arg("path")="", arg("fill_value")=0.0, arg("axistags")=python::object()));
+}
+
+void defineChunkedArray()
+{
+    using namespace boost::python;
+
+    docstring_options doc_options(true, false, false);
+
+    enum_<CompressionMethod>("Compression",
+         "\nEnum to encode the type of compression for\n"
+         "ChunkedArrayCompressed and ChunkedArrayHDF5:\n\n"
+         "   ``Compression.ZLIB:``\n      ZLIB default compression\n"
+         "   ``Compression.ZLIB_NONE:``\n      ZLIB no compression (level = 0)\n"
+         "   ``Compression.ZLIB_FAST:``\n      ZLIB fast compression (level = 1)\n"
+         "   ``Compression.ZLIB_BEST:``\n      ZLIB best compression (level = 9)\n"
+         "   ``Compression.LZ4:``\n      LZ4 compression (very fast)\n\n")
+        .value("ZLIB", vigra::ZLIB)
+        .value("ZLIB_NONE", vigra::ZLIB_NONE)
+        .value("ZLIB_FAST", vigra::ZLIB_FAST)
+        .value("ZLIB_BEST", vigra::ZLIB_BEST)
+        .value("LZ4", vigra::LZ4)
+    ;
+
+#ifdef HasHDF5
+    enum_<HDF5File::OpenMode>("HDF5Mode",
+         "\nEnum to encode open mode for ChunkedArrayHDF5:\n\n"
+         "   ``HDF5Mode.Default:``\n  Use the default strategy (ReadOnly when file and dataset exist, New otherwise)\n"
+         "   ``HDF5Mode.New:``\n      Create new file (existing file will be deleted)\n"
+         "   ``HDF5Mode.ReadWrite:``\n      Open file (create when not existing) and allow creation of new datasets.\n"
+         "                                  Contents of existing datasets may be changed, but not their shape.\n"
+         "   ``HDF5Mode.ReadOnly:``\n     Open files and datasets read-only, fail when not existing.\n"
+         "   ``HDF5Mode.Replace:``\n      Like ReadWrite, but always replace exising datasets.\n\n")
+        .value("New", HDF5File::New)
+        .value("ReadWrite", HDF5File::ReadWrite)
+        .value("ReadOnly", HDF5File::ReadOnly)
+        .value("Replace", HDF5File::Replace)
+        .value("Default", HDF5File::Default)
+    ;
+#endif
+
+    defineChunkedArrayImpl<2, npy_uint8>();
+    defineChunkedArrayImpl<3, npy_uint8>();
+    defineChunkedArrayImpl<4, npy_uint8>();
+    defineChunkedArrayImpl<5, npy_uint8>();
+
+    defineChunkedArrayImpl<2, npy_uint32>();
+    defineChunkedArrayImpl<3, npy_uint32>();
+    defineChunkedArrayImpl<4, npy_uint32>();
+    defineChunkedArrayImpl<5, npy_uint32>();
+
+    defineChunkedArrayImpl<2, npy_float32>();
+    defineChunkedArrayImpl<3, npy_float32>();
+    defineChunkedArrayImpl<4, npy_float32>();
+    defineChunkedArrayImpl<5, npy_float32>();
+
+    defineChunkedArrayFactories<2>();
+    defineChunkedArrayFactories<3>();
+    defineChunkedArrayFactories<4>();
+    defineChunkedArrayFactories<5>();
+
+#ifdef HasHDF5
+    def("ChunkedArrayHDF5", &construct_ChunkedArrayHDF5id,
+        (arg("file_id"), arg("dataset_name"), arg("shape")=python::object(),
+         arg("dtype")=python::object(), arg("mode")=HDF5File::ReadOnly, arg("compression")=ZLIB_FAST,
+         arg("chunk_shape")=python::object(), arg("cache_max")=-1, arg("fill_value")=0.0,
+         arg("axistags")=python::object()));
+    def("ChunkedArrayHDF5", &construct_ChunkedArrayHDF5,
+        (arg("file_name"), arg("dataset_name"), arg("shape")=python::object(),
+         arg("dtype")=python::object(), arg("mode")=HDF5File::Default, arg("compression")=ZLIB_FAST,
+         arg("chunk_shape")=python::object(), arg("cache_max")=-1, arg("fill_value")=0.0,
+         arg("axistags")=python::object()));
+#endif
+}
+
+} // namespace vigra
+
diff --git a/vigranumpy/src/core/non_local_mean.cxx b/vigranumpy/src/core/non_local_mean.cxx
new file mode 100644
index 0000000..fadde4c
--- /dev/null
+++ b/vigranumpy/src/core/non_local_mean.cxx
@@ -0,0 +1,182 @@
+/************************************************************************/
+/*                                                                      */
+/*                 Copyright 2009 by Ullrich Koethe                     */
+/*                                                                      */
+/*    This file is part of the VIGRA computer vision library.           */
+/*    The VIGRA Website is                                              */
+/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
+/*    Please direct questions, bug reports, and contributions to        */
+/*        ullrich.koethe at iwr.uni-heidelberg.de    or                    */
+/*        vigra at informatik.uni-hamburg.de                               */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    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 AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpyfilters_PyArray_API
+#define NO_IMPORT_ARRAY
+
+#include <vigra/numpy_array.hxx>
+#include <vigra/numpy_array_converters.hxx>
+#include <vigra/non_local_mean.hxx>
+
+namespace python = boost::python;
+
+namespace vigra
+{
+
+
+
+
+
+
+template<int DIM,class PIXEL_TYPE,class SMOOTH_POLICY>
+NumpyAnyArray  pyNonLocalMean(
+    NumpyArray<DIM,PIXEL_TYPE> image,
+    const typename SMOOTH_POLICY::ParameterType & policyParam,
+    const double sigmaSpatial,
+    const int searchRadius,
+    const int patchRadius,
+    const double sigmaMean,
+    const int stepSize,
+    const int iterations,
+    const int nThreads,
+    const bool verbose,
+    NumpyArray<DIM,PIXEL_TYPE> out = NumpyArray<DIM,PIXEL_TYPE>()
+){
+
+    SMOOTH_POLICY smoothPolicy(policyParam);
+    NonLocalMeanParameter param;
+    param.sigmaSpatial_=sigmaSpatial;
+    param.searchRadius_=searchRadius;
+    param.patchRadius_=patchRadius;
+    param.sigmaMean_=sigmaMean;
+    param.stepSize_=stepSize;
+    param.iterations_=iterations;
+    param.nThreads_ = nThreads;
+    param.verbose_=verbose;
+    out.reshapeIfEmpty(image.shape());
+    nonLocalMean<DIM,PIXEL_TYPE>(image,smoothPolicy,param,out);
+    return out;
+}
+
+
+void exportNonLocalMeanPolicyParameterObjects(){
+
+    {
+        typedef RatioPolicyParameter ParamType;
+
+        python::class_<ParamType>(
+            "RatioPolicy",
+            python::init<const double,const double,const double,const double>(
+                (
+                    python::arg("sigma"),
+                    python::arg("meanRatio")=0.95,
+                    python::arg("varRatio")=0.5,
+                    python::arg("epsilon")=0.00001
+                )
+            )
+        )
+        .def_readwrite("sigma", &ParamType::sigma_)
+        .def_readwrite("meanRatio", &ParamType::meanRatio_)
+        .def_readwrite("varRatio", &ParamType::varRatio_)
+        .def_readwrite("epsilon", &ParamType::epsilon_)
+        ;
+            
+    }
+
+    {
+        typedef NormPolicyParameter ParamType;
+
+        python::class_<ParamType>(
+            "NormPolicy",
+            python::init<const double,const double,const double>(
+                (
+                    python::arg("sigma"),
+                    python::arg("meanDist"),
+                    python::arg("varRatio")
+                )
+            )
+        )
+        .def_readwrite("sigma", &ParamType::sigma_)
+        .def_readwrite("meanDist", &ParamType::meanDist_)
+        .def_readwrite("varRatio", &ParamType::varRatio_)
+        ;
+            
+    }
+
+
+}
+
+
+
+
+template<int DIM,class PIXEL_TYPE, class POLICY>
+void exportNonLocalMean(const std::string name){
+
+    typedef POLICY SmoothPolicyType;
+    // export the function to python
+    python::def(name.c_str(), registerConverters(&pyNonLocalMean<DIM,PIXEL_TYPE,SmoothPolicyType>) ,
+        (
+            python::arg("image"),
+            python::arg("policy"),
+            python::arg("sigmaSpatial")=2.0,
+            python::arg("searchRadius")=3,
+            python::arg("patchRadius")=1,
+            python::arg("sigmaMean")=1.0,
+            python::arg("stepSize")=2,
+            python::arg("iterations")=1,
+            python::arg("nThreads")=8,
+            python::arg("verbose")=true,
+            python::arg("out") = boost::python::object()
+        ),
+        "loop over an image and do something with each pixels\n\n"
+        "Args:\n\n"
+        "   image : input image\n\n"
+        "returns an an image with the same shape as the input image"
+    );
+}
+
+void defineNonLocalMean(){
+    using namespace python;
+    docstring_options doc_options(true, true, false);
+
+    // export different parameter objects
+    exportNonLocalMeanPolicyParameterObjects();
+
+    {
+        exportNonLocalMean<2,TinyVector<float,3>, RatioPolicy<TinyVector<float,3> > >("nonLocalMean2d");
+        exportNonLocalMean<2,float, RatioPolicy<float> >("nonLocalMean2d");
+        exportNonLocalMean<3,float, RatioPolicy<float> >("nonLocalMean3d");
+        exportNonLocalMean<4,float, RatioPolicy<float> >("nonLocalMean4d");
+    }
+    {
+        exportNonLocalMean<2,TinyVector<float,3>, NormPolicy<TinyVector<float,3> > >("nonLocalMean2d");
+        exportNonLocalMean<2,float, NormPolicy<float> >("nonLocalMean2d");
+        exportNonLocalMean<3,float, NormPolicy<float> >("nonLocalMean3d");
+        exportNonLocalMean<4,float, NormPolicy<float> >("nonLocalMean4d");
+    }
+}
+
+
+} // namespace vigra
diff --git a/vigranumpy/src/core/pythonaccumulator.hxx b/vigranumpy/src/core/pythonaccumulator.hxx
index 558a84b..175f66b 100644
--- a/vigranumpy/src/core/pythonaccumulator.hxx
+++ b/vigranumpy/src/core/pythonaccumulator.hxx
@@ -290,6 +290,7 @@ struct PythonFeatureAccumulator
     virtual python::object get(std::string const & tag) { throw std::runtime_error("abstract function called."); return python::object(); }
     virtual void merge(PythonFeatureAccumulator const & o) { throw std::runtime_error("abstract function called."); }
     virtual PythonFeatureAccumulator * create() const { throw std::runtime_error("abstract function called."); return 0; }
+    virtual ~PythonFeatureAccumulator() {}
     
     static void definePythonClass()
     {
diff --git a/vigranumpy/src/core/random_forest.cxx b/vigranumpy/src/core/random_forest.cxx
index 085d75a..e34f89d 100644
--- a/vigranumpy/src/core/random_forest.cxx
+++ b/vigranumpy/src/core/random_forest.cxx
@@ -48,6 +48,7 @@
 #include <cmath>
 #include <memory>
 #include <boost/python.hpp>
+#include<vigra/random_forest/rf_earlystopping.hxx>
 
 namespace python = boost::python;
 namespace vigra
@@ -117,6 +118,19 @@ pythonImportRandomForestFromHDF5(std::string filename,
            
     return rf.release();
 }                   
+
+template<class LabelType>
+RandomForest<LabelType> *
+pythonImportRandomForestFromHDF5id(hid_t inf_id,
+                                 std::string pathname = "")
+{
+    VIGRA_UNIQUE_PTR<RandomForest<LabelType> > rf(new RandomForest<LabelType>);
+
+    vigra_precondition(rf_import_HDF5(*rf, inf_id, pathname),
+           "RandomForest(): Unable to load from HDF5 file.");
+
+    return rf.release();
+}
 #endif // HasHDF5
 
 template<class LabelType, class FeatureType>
@@ -155,7 +169,9 @@ double
 pythonLearnRandomForest(RandomForest<LabelType> & rf, 
                         NumpyArray<2,FeatureType> trainData, 
                         NumpyArray<2,LabelType> trainLabels,
-                        UInt32 randomSeed=0)
+                        UInt32 randomSeed=0,
+                        int maxdepth=-1,
+                        int minsize=0)
 {
     vigra_precondition(!trainData.axistags() && !trainLabels.axistags(),
                        "RandomForest.learnRF(): training data and labels must not\n"
@@ -164,11 +180,13 @@ pythonLearnRandomForest(RandomForest<LabelType> & rf,
     using namespace rf;
     visitors::OOB_Error oob_v;
 
+
+    vigra::DepthAndSizeStopping earlystop(maxdepth,minsize);
     {
         PyAllowThreads _pythread;
         RandomNumberGenerator<> rnd(randomSeed, randomSeed == 0);
         rf.learn(trainData, trainLabels, visitors::create_visitor(oob_v),
-                vigra::rf_default(), vigra::rf_default(),
+                vigra::rf_default(), earlystop,
                 rnd);
     }
     double oob = oob_v.oob_breiman;
@@ -320,7 +338,23 @@ void defineRandomForest()
     class_<RandomForest<LabelType> > rfclass_new("RandomForest",python::no_init);
 
     rfclass_new
-        .def("__init__",python::make_constructor(registerConverters(&pythonConstructRandomForest<LabelType,float>),
+#ifdef HasHDF5
+        .def("__init__",python::make_constructor(&pythonImportRandomForestFromHDF5id<LabelType>,
+                                                 boost::python::default_call_policies(),
+                                                 ( arg("file_id"),
+                                                   arg("pathInFile")="")),
+             "\nLoad from an open HDF5 file id (note that the keyword 'file_id' must\n"
+             "be specified explicitly, otherwise the argument will be interpreted as\n"
+             "the number of trees to be used)::\n\n"
+             "  RandomForest(file_id=id, pathInFile='/path/to/dataset')\n\n")
+         .def("__init__",python::make_constructor(&pythonImportRandomForestFromHDF5<LabelType>,
+                                                 boost::python::default_call_policies(),
+                                                 ( arg("filename"),
+                                                   arg("pathInFile")="")),
+             "\nLoad from HDF5 file::\n\n"
+             "  RandomForest(filename, pathInFile)\n\n")
+#endif // HasHDF5
+       .def("__init__",python::make_constructor(registerConverters(&pythonConstructRandomForest<LabelType,float>),
                                                  boost::python::default_call_policies(),
                                                  ( arg("treeCount")=255,
                                                    arg("mtry")= -1,
@@ -331,26 +365,20 @@ void defineRandomForest()
                                                    arg("sample_classes_individually")=false,
                                                    arg("prepare_online_learning")=false,
                                                    arg("labels")=python::list())),
-             "Constructor::\n\n"
+             "\nConstruct a new random forest::\n\n"
              "  RandomForest(treeCount = 255, mtry=RF_SQRT, min_split_node_size=1,\n"
              "               training_set_size=0, training_set_proportions=1.0,\n"
              "               sample_with_replacement=True, sample_classes_individually=False,\n"
              "               prepare_online_learning=False)\n\n"
-             "'treeCount' controls the number of trees that are created.\n"
-             "'labels' is a list specifying the permitted labels.\n"
-             "         If empty (default), the labels are automatically determined\n"
-             "         from the training data. A non-empty list is useful when some\n"
-             "         labels lack training examples.\n\n"
+             "treeCount:\n"
+             "     controls the number of trees that are created.\n"
+             "labels:\n"
+             "     is a list specifying the permitted labels.\n"
+             "     If empty (default), the labels are automatically determined\n"
+             "     from the training data. A non-empty list is useful when some\n"
+             "     labels lack training examples.\n\n"
              "See RandomForest_ and RandomForestOptions_ in the C++ documentation "
              "for the meaning of the other parameters.\n")
-#ifdef HasHDF5
-        .def("__init__",python::make_constructor(&pythonImportRandomForestFromHDF5<LabelType>,
-                                                 boost::python::default_call_policies(),
-                                                 ( arg("filename"),
-                                                   arg("pathInFile")="")),
-             "Load from HDF5 file::\n\n"
-             "  RandomForest(filename, pathInFile)\n\n")
-#endif // HasHDF5
         .def("featureCount",
             &RandomForest<LabelType>::column_count,
              "Returns the number of features the RandomForest works with.\n")
@@ -379,7 +407,8 @@ void defineRandomForest()
              "The output is an array containing a probability for every test sample and class.\n")
         .def("learnRF",
              registerConverters(&pythonLearnRandomForest<LabelType,float>),
-             (arg("trainData"), arg("trainLabels"), arg("randomSeed")=0),
+             (arg("trainData"), arg("trainLabels"), arg("randomSeed")=0,
+              arg("maxDepth")=-1, arg("minSize")=0),
              "Trains a random Forest using 'trainData' and 'trainLabels'.\n\n"
              "and returns the OOB. See the vigra documentation for the meaning af the rest of the parameters.\n")
         .def("reLearnTree",
@@ -406,6 +435,10 @@ void defineRandomForest()
              (arg("filename"), arg("pathInFile")=""),
              "Store the random forest in the given HDF5 file 'filename' under the internal\n"
              "path 'pathInFile'.\n")
+        .def("writeHDF5", (void (*)(const RandomForest<LabelType, ClassificationTag> &, hid_t, std::string const &))&rf_export_HDF5,
+             (arg("file_id"), arg("pathInFile")=""),
+             "Store the random forest in the HDF5 file with given 'file_id' \n"
+             "under the internal path 'pathInFile'.\n")
 #endif // HasHDF5
         ;
 }
diff --git a/vigranumpy/src/core/sampling.cxx b/vigranumpy/src/core/sampling.cxx
index b8ec1f7..842de17 100644
--- a/vigranumpy/src/core/sampling.cxx
+++ b/vigranumpy/src/core/sampling.cxx
@@ -51,11 +51,11 @@ namespace python = boost::python;
 
 namespace vigra
 {
-    
+
 template < class PixelType >
-NumpyAnyArray 
-pythonResampleImage(NumpyArray<3, Multiband<PixelType> > image, 
-                    double factor, 
+NumpyAnyArray
+pythonResampleImage(NumpyArray<3, Multiband<PixelType> > image,
+                    double factor,
                     NumpyArray<3, Multiband<PixelType> > res)
 {
     vigra_precondition((image.shape(0) > 1) && (image.shape(1) > 1),
@@ -84,7 +84,7 @@ pythonResampleImage(NumpyArray<3, Multiband<PixelType> > image,
             resampleImage(srcImageRange(bimage), destImage(bres), factor);
         }
     }
-    
+
     return res;
 }
 
@@ -96,9 +96,9 @@ enum RotationDirection
 };
 
 template < class PixelType>
-NumpyAnyArray 
-pythonFixedRotateImage(NumpyArray<3, Multiband<PixelType> > image, 
-                       RotationDirection dir, 
+NumpyAnyArray
+pythonFixedRotateImage(NumpyArray<3, Multiband<PixelType> > image,
+                       RotationDirection dir,
                        NumpyArray<3,Multiband<PixelType> > res)
 {
     int degree=0;
@@ -114,7 +114,7 @@ pythonFixedRotateImage(NumpyArray<3, Multiband<PixelType> > image,
         degree=180;
         break;
     }
-    
+
     TaggedShape newShape(image.taggedShape());
     if(degree % 180 == 0)
     {
@@ -126,9 +126,9 @@ pythonFixedRotateImage(NumpyArray<3, Multiband<PixelType> > image,
         res.reshapeIfEmpty(image.taggedShape().transposeShape(permute),
                      "rotateImage(): Output image has wrong dimensions");
     }
-    
+
     {
-        PyAllowThreads _pythread;    
+        PyAllowThreads _pythread;
         for(int k=0;k<image.shape(2);++k)
         {
             MultiArrayView<2, PixelType, StridedArrayTag> bimage = image.bindOuter(k);
@@ -140,8 +140,8 @@ pythonFixedRotateImage(NumpyArray<3, Multiband<PixelType> > image,
 }
 
 template < class PixelType>
-NumpyAnyArray 
-pythonFreeRotateImageDegree(NumpyArray<3, Multiband<PixelType> > image, 
+NumpyAnyArray
+pythonFreeRotateImageDegree(NumpyArray<3, Multiband<PixelType> > image,
                             double degree,RotationDirection dir, int splineOrder,
                             NumpyArray<3,Multiband<PixelType> > res)
 {
@@ -149,8 +149,8 @@ pythonFreeRotateImageDegree(NumpyArray<3, Multiband<PixelType> > image,
 }
 
 template < class PixelType>
-NumpyAnyArray 
-pythonFreeRotateImageRadiant(NumpyArray<3, Multiband<PixelType> > image, 
+NumpyAnyArray
+pythonFreeRotateImageRadiant(NumpyArray<3, Multiband<PixelType> > image,
                              double radiant, RotationDirection dir, int splineOrder,
                              NumpyArray<3,Multiband<PixelType> > res)
 {
@@ -203,7 +203,7 @@ pythonFreeRotateImageRadiant(NumpyArray<3, Multiband<PixelType> > image,
                     break;
                 }
                 case 3:
-                { 
+                {
                     SplineImageView< 3, PixelType > spline(srcImageRange(bimage));
                     affineWarpImage(spline,destImageRange(bres),transform);
                     break;
@@ -227,23 +227,23 @@ pythonFreeRotateImageRadiant(NumpyArray<3, Multiband<PixelType> > image,
 }
 
 template <class PixelType, unsigned int dim>
-void pythonResizeImagePrepareOutput(NumpyArray<dim, Multiband<PixelType> > const & image, 
+void pythonResizeImagePrepareOutput(NumpyArray<dim, Multiband<PixelType> > const & image,
                                     python::object destSize,
                                     NumpyArray<dim, Multiband<PixelType> > & res)
 {
     for(unsigned int k=0; k<dim-1; ++k)
-        vigra_precondition(image.shape(k),
+        vigra_precondition(image.shape(k) > 1,
             "resizeImage(): Each input axis must have length > 1.");
-        
+
     typedef typename MultiArrayShape<dim-1>::type Shape;
     if(destSize != python::object())
     {
         vigra_precondition(!res.hasData(),
                "resizeImage(): you cannot provide both 'shape' and 'out'.");
-                       
+
         Shape shape = image.permuteLikewise(python::extract<Shape>(destSize)());
-              
-        res.reshapeIfEmpty(image.taggedShape().resize(shape), 
+
+        res.reshapeIfEmpty(image.taggedShape().resize(shape),
                            "resizeImage(): Output image has wrong dimensions");
     }
     else
@@ -253,15 +253,19 @@ void pythonResizeImagePrepareOutput(NumpyArray<dim, Multiband<PixelType> > const
         vigra_precondition(res.shape(dim-1) == image.shape(dim-1),
                "resizeImage(): number of channels of image and result must be equal.");
     }
+
+    for(unsigned int k=0; k<dim-1; ++k)
+        vigra_precondition(res.shape(k) > 1,
+            "resizeImage(): Each output axis must have length > 1.");
 }
 
 template < class PixelType>
-NumpyAnyArray pythonResizeImageNoInterpolation(NumpyArray<3, Multiband<PixelType> > image, 
+NumpyAnyArray pythonResizeImageNoInterpolation(NumpyArray<3, Multiband<PixelType> > image,
                                                python::object destSize,
                                                NumpyArray<3, Multiband<PixelType> > res)
 {
     pythonResizeImagePrepareOutput(image, destSize, res);
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0;k<image.shape(2);++k)
@@ -280,7 +284,7 @@ NumpyAnyArray pythonResizeImageLinearInterpolation(NumpyArray<3, Multiband<Pixel
                                                    NumpyArray<3, Multiband<PixelType> > res)
 {
     pythonResizeImagePrepareOutput(image, destSize, res);
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0;k<image.shape(2);++k)
@@ -294,10 +298,10 @@ NumpyAnyArray pythonResizeImageLinearInterpolation(NumpyArray<3, Multiband<Pixel
 }
 
 template < class PixelType, int dim >
-NumpyAnyArray 
+NumpyAnyArray
 pythonResizeImageSplineInterpolation(NumpyArray<dim, Multiband<PixelType> > image,
                                      python::object destSize,
-                                     int splineOrder=3, 
+                                     int splineOrder=3,
                                      NumpyArray<dim, Multiband<PixelType> > res=python::object())
 {
     if(splineOrder < 0 || splineOrder > 5)
@@ -305,14 +309,14 @@ pythonResizeImageSplineInterpolation(NumpyArray<dim, Multiband<PixelType> > imag
         PyErr_SetString(PyExc_ValueError, "resize(): Spline order not supported.");
         python::throw_error_already_set();
     }
-    
+
     pythonResizeImagePrepareOutput(image, destSize, res);
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0;k<image.shape(dim-1);++k)
         {
-            
+
             MultiArrayView<dim-1, PixelType, StridedArrayTag> bimage = image.bindOuter(k);
             MultiArrayView<dim-1, PixelType, StridedArrayTag> bres = res.bindOuter(k);
             switch (splineOrder)
@@ -371,12 +375,12 @@ NumpyAnyArray pythonResizeImageCatmullRomInterpolation(NumpyArray<3, Multiband<P
                                                        NumpyArray<3, Multiband<PixelType> > res)
 {
     pythonResizeImagePrepareOutput(image, destSize, res);
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0;k<image.shape(2);++k)
         {
-            
+
             MultiArrayView<2, PixelType, StridedArrayTag> bimage = image.bindOuter(k);
             MultiArrayView<2, PixelType, StridedArrayTag> bres = res.bindOuter(k);
 
@@ -392,12 +396,12 @@ NumpyAnyArray pythonResizeImageCoscotInterpolation(NumpyArray<3, Multiband<Pixel
                                                    NumpyArray<3, Multiband<PixelType> > res)
 {
     pythonResizeImagePrepareOutput(image, destSize, res);
-    
+
     {
         PyAllowThreads _pythread;
         for(int k=0;k<image.shape(2);++k)
         {
-            
+
             MultiArrayView<2, PixelType, StridedArrayTag> bimage = image.bindOuter(k);
             MultiArrayView<2, PixelType, StridedArrayTag> bres = res.bindOuter(k);
             resizeImageCoscotInterpolation(srcImageRange(bimage),destImageRange(bres));
@@ -407,17 +411,17 @@ NumpyAnyArray pythonResizeImageCoscotInterpolation(NumpyArray<3, Multiband<Pixel
 }
 
 template <class PixelType>
-NumpyAnyArray 
-resamplingGaussian2D(NumpyArray<3, Multiband<PixelType> > image, 
+NumpyAnyArray
+resamplingGaussian2D(NumpyArray<3, Multiband<PixelType> > image,
     double sigmax, unsigned int derivativeOrderX, double samplingRatioX, double offsetX,
-    double sigmay, unsigned int derivativeOrderY, double samplingRatioY, double offsetY, 
+    double sigmay, unsigned int derivativeOrderY, double samplingRatioY, double offsetY,
     NumpyArray<3, Multiband<PixelType> > res = python::object())
 {
     vigra_precondition(samplingRatioX > 0 ,
        "resamplingGaussian(): samplingRatioX must be > 0.");
     vigra_precondition(samplingRatioY > 0 ,
        "resamplingGaussian(): samplingRatioY must be > 0.");
-       
+
     Rational<int> xratio(samplingRatioX), yratio(samplingRatioY),
                   xoffset(offsetX), yoffset(offsetY);
     Gaussian< double > smoothx(sigmax, derivativeOrderX);
@@ -425,7 +429,7 @@ resamplingGaussian2D(NumpyArray<3, Multiband<PixelType> > image,
 
     int width = rational_cast< int >(image.shape(0)*xratio);
     int height = rational_cast< int >(image.shape(1)*yratio);
-    res.reshapeIfEmpty(image.taggedShape().resize(width, height), 
+    res.reshapeIfEmpty(image.taggedShape().resize(width, height),
              "resamplingGaussian2D(): Output array has wrong shape.");
 
     {
@@ -483,10 +487,10 @@ SplineView_interpolatedImage(SplineView const & self, double xfactor, double yfa
 {
     vigra_precondition(xfactor > 0.0 && yfactor > 0.0,
         "SplineImageView.interpolatedImage(xfactor, yfactor): factors must be positive.");
-        
+
     int wn = int((self.width() - 1.0) * xfactor + 1.5);
     int hn = int((self.height() - 1.0) * yfactor + 1.5);
-    
+
     typedef typename BindSplineConstructor<typename SplineView::value_type>::type ResType;
     NumpyArray<2, ResType> res(Shape2(wn, hn));
 
@@ -585,11 +589,11 @@ defSplineView(char const * name)
     using namespace python;
 
     docstring_options doc_options(true, true, false);
-    
+
     typedef typename SplineView::value_type Value;
     typedef typename SplineView::SquaredNormType SNormValue;
     typedef typename SplineView::difference_type Shape;
-    
+
     Value (SplineView::*callfct)(double, double) const = &SplineView::operator();
     Value (SplineView::*callfct2)(double, double, unsigned int, unsigned int) const = &SplineView::operator();
 
@@ -610,10 +614,10 @@ defSplineView(char const * name)
         .def("shape", &SplineView::shape, "The shape of the underlying image.\n\n")
         .def("width", &SplineView::width, "The width of the underlying image.\n\n")
         .def("height", &SplineView::height, "The height of the underlying image.\n\n")
-        .def("isInside", &SplineView::isInside, 
+        .def("isInside", &SplineView::isInside,
              "Check if a coordinate is inside the underlying image.\n\n"
              "SplineImageView.isInside(x, y) -> bool\n\n")
-        .def("isValid", &SplineView::isValid, 
+        .def("isValid", &SplineView::isValid,
              "Check if a coordinate is within the valid range of the SplineImageView.\n\n"
              "SplineImageView.isValid(x, y) -> bool\n\n"
              "Thanks to reflective boundary conditions, the valid range is three times "
@@ -753,7 +757,7 @@ defSplineView(char const * name)
 void defineSampling()
 {
     using namespace python;
-    
+
     docstring_options doc_options(true, true, false);
 
     enum_<RotationDirection>("RotationDirection")
@@ -769,7 +773,7 @@ void defineSampling()
         "The parameter 'splineOrder' indicates the order of the splines used for interpolation.\n"
         "If the 'out' parameter is given, the image is cropped for it's dimensions. If the 'out'\n"
         "parameter is not given, an output image with the same dimensions as the input image is created.\n\n"
-        "For more details, see GeometricTransformations.rotationMatrix2DRadians_ in the vigra C++ documentation.\n" 
+        "For more details, see GeometricTransformations.rotationMatrix2DRadians_ in the vigra C++ documentation.\n"
         );
     def("rotateImageDegree",
         registerConverters(&pythonFreeRotateImageDegree<float>),
@@ -780,7 +784,7 @@ void defineSampling()
         "The parameter 'splineOrder' indicates the order of the splines used for interpolation.\n"
         "If the 'out' parameter is given, the image is cropped for it's dimensions. If the 'out'\n"
         "parameter is not given, an output image with the same dimensions as the input image is created.\n\n"
-        "For more details, see GeometricTransformations.rotationMatrix2DDegrees_ in the vigra C++ documentation.\n"  
+        "For more details, see GeometricTransformations.rotationMatrix2DDegrees_ in the vigra C++ documentation.\n"
         );
     def("rotateImageSimple",
         registerConverters(&pythonFixedRotateImage<float>),
@@ -790,7 +794,7 @@ void defineSampling()
         "The 'orientation' parameter (which must be one of CLOCKWISE, COUNTER_CLOCKWISE and UPSIDE_DOWN\n"
         "indicates the rotation direction. The 'out' parameter must, if given, have the according dimensions.\n"
         "This function also works for multiband images, it is then executed on every band.\n\n"
-        "For more details, see rotateImage_ in the vigra C++ documentation.\n" 
+        "For more details, see rotateImage_ in the vigra C++ documentation.\n"
         );
 
 //    def("rotateImageAboutCenter",
@@ -804,13 +808,13 @@ void defineSampling()
         "\n"
         "The 'out' parameter must have, if given, the according dimensions.\n"
         "This function also works for multiband images, it is then executed on every band.\n\n"
-        "For more details, see resampleImage_ in the vigra C++ documentation.\n" 
+        "For more details, see resampleImage_ in the vigra C++ documentation.\n"
         );
 
     def("resamplingGaussian", registerConverters(&resamplingGaussian2D<float>),
-          (arg("image"), 
-           arg("sigmaX")=1.0, arg("derivativeOrderX")=0, arg("samplingRatioX")=2.0, arg("offsetX")=0.0, 
-           arg("sigmaY")=1.0, arg("derivativeOrderY")=0, arg("samplingRatioY")=2.0, arg("offsetY")=0.0, 
+          (arg("image"),
+           arg("sigmaX")=1.0, arg("derivativeOrderX")=0, arg("samplingRatioX")=2.0, arg("offsetX")=0.0,
+           arg("sigmaY")=1.0, arg("derivativeOrderY")=0, arg("samplingRatioY")=2.0, arg("offsetY")=0.0,
            arg("out") = python::object()),
           "Resample image using a gaussian filter::\n\n"
           "   resamplingGaussian(image,\n"
@@ -838,7 +842,7 @@ void defineSampling()
         (arg("image"), arg("shape")=object(), arg("out")=object()),
         "Resize image using linear interpolation.\n"
         "The function uses the standard separable bilinear interpolation algorithm to obtain a good compromise between quality and speed.\n"
-        "\n" 
+        "\n"
         "The desired shape of the output image is taken either from 'shape' or 'out'.\n"
         "If both are given, they must agree.\n"
         "This function also works for multiband images, it is then executed on every band.\n\n"
@@ -861,7 +865,7 @@ void defineSampling()
         registerConverters(&pythonResizeImageCatmullRomInterpolation<float>),               // also multiband
         (arg("image"), arg("shape")=object(), arg("out")=object()),
         "Resize image using the Catmull/Rom interpolation function.\n"
-        "\n" 
+        "\n"
         "The desired shape of the output image is taken either from 'shape' or 'out'.\n"
         "If both are given, they must agree.\n"
         "This function also works for multiband images, it is then executed on every band.\n\n"
@@ -871,8 +875,8 @@ void defineSampling()
     def("resizeImageCoscotInterpolation",
         registerConverters(&pythonResizeImageCoscotInterpolation<float>),               // also multiband
         (arg("image"), arg("shape")=object(), arg("out")=object()),
-        "Resize image using the Coscot interpolation function.\n" 
-        "\n" 
+        "Resize image using the Coscot interpolation function.\n"
+        "\n"
         "The desired shape of the output image is taken either from 'shape' or 'out'.\n"
         "If both are given, they must agree.\n"
         "This function also works for multiband images, it is then executed on every band.\n\n"
diff --git a/vigranumpy/src/core/segmentation.cxx b/vigranumpy/src/core/segmentation.cxx
index 0fd1d38..685778a 100644
--- a/vigranumpy/src/core/segmentation.cxx
+++ b/vigranumpy/src/core/segmentation.cxx
@@ -41,6 +41,7 @@
 #include <vigra/localminmax.hxx>
 #include <vigra/labelimage.hxx>
 #include <vigra/watersheds.hxx>
+#include <vigra/blockwise_watersheds.hxx>
 #include <vigra/seededregiongrowing.hxx>
 #include <vigra/labelvolume.hxx>
 #include <vigra/watersheds3d.hxx>
@@ -49,6 +50,8 @@
 #include <vigra/convolution.hxx>
 #include <vigra/multi_convolution.hxx>
 #include <vigra/slic.hxx>
+#include <vigra/seg_to_seeds.hxx>
+
 
 #include <string>
 #include <cmath>
@@ -60,10 +63,11 @@ namespace python = boost::python;
 namespace vigra
 {
 
+
 template < class PixelType >
-NumpyAnyArray 
+NumpyAnyArray
 pythonLabelImage(NumpyArray<2, Singleband<PixelType> > image,
-                 int neighborhood = 4, 
+                 int neighborhood = 4,
                  NumpyArray<2, Singleband<npy_uint32> > res = NumpyArray<2, Singleband<npy_uint32> >())
 {
     vigra_precondition(neighborhood == 4 || neighborhood == 8,
@@ -71,8 +75,8 @@ pythonLabelImage(NumpyArray<2, Singleband<PixelType> > image,
 
     std::string description("connected components, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
             "labelImage(): Output array has wrong shape.");
 
     {
@@ -91,14 +95,14 @@ pythonLabelImage(NumpyArray<2, Singleband<PixelType> > image,
             }
         }
     }
-    
+
     return res;
 }
 
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pyLabelImage, pythonLabelImage)
 
 template < class PixelType >
-NumpyAnyArray 
+NumpyAnyArray
 pythonLabelImageWithBackground(NumpyArray<2, Singleband<PixelType> > image,
                                int neighborhood = 4,
                                PixelType background_value = 0,
@@ -109,8 +113,8 @@ pythonLabelImageWithBackground(NumpyArray<2, Singleband<PixelType> > image,
 
     std::string description("connected components with background, neighborhood=");
     description += asString(neighborhood)+ ", bglabel=" + asString(background_value);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
         "labelImageWithBackground(): Output array has wrong shape.");
 
     {
@@ -137,18 +141,18 @@ pythonLabelImageWithBackground(NumpyArray<2, Singleband<PixelType> > image,
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pyLabelImageWithBackground, pythonLabelImageWithBackground)
 
 template < class VoxelType >
-NumpyAnyArray 
-pythonLabelVolume(NumpyArray<3, Singleband<VoxelType> > volume, 
+NumpyAnyArray
+pythonLabelVolume(NumpyArray<3, Singleband<VoxelType> > volume,
                   int neighborhood=6,
                   NumpyArray<3, Singleband<npy_uint32> > res = NumpyArray<3, Singleband<npy_uint32> >())
 {
     vigra_precondition(neighborhood == 6 || neighborhood == 26,
         "labelVolume(): neighborhood must be 6 or 26.");
-    
+
     std::string description("connected components, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description),
             "labelVolume(): Output array has wrong shape.");
 
     {
@@ -175,19 +179,19 @@ pythonLabelVolume(NumpyArray<3, Singleband<VoxelType> > volume,
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pyLabelVolume, pythonLabelVolume)
 
 template < class VoxelType >
-NumpyAnyArray 
-pythonLabelVolumeWithBackground(NumpyArray<3, Singleband<VoxelType> > volume, 
+NumpyAnyArray
+pythonLabelVolumeWithBackground(NumpyArray<3, Singleband<VoxelType> > volume,
                                 int neighborhood=6,
                                 VoxelType background_value = 0,
                                 NumpyArray<3, Singleband<npy_uint32> > res = NumpyArray<3, Singleband<npy_uint32> >())
 {
     vigra_precondition(neighborhood == 6 || neighborhood == 26,
         "labelVolumeWithBackground(): neighborhood must be 6 or 26.");
-    
+
     std::string description("connected components with background, neighborhood=");
     description += asString(neighborhood)+ ", bglabel=" + asString(background_value);
-    
-    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description),
         "labelVolumeWithBackground(): Output array has wrong shape.");
 
     {
@@ -215,15 +219,139 @@ pythonLabelVolumeWithBackground(NumpyArray<3, Singleband<VoxelType> > volume,
 
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pyLabelVolumeWithBackground, pythonLabelVolumeWithBackground)
 
+template < class VoxelType, unsigned int ndim >
+NumpyAnyArray
+pythonLabelMultiArray(NumpyArray<ndim, Singleband<VoxelType> > volume,
+                      // std::string neighborhood="",
+                      python::object neighborspec=python::object(),
+                      NumpyArray<ndim, Singleband<npy_uint32> > res = NumpyArray<ndim, Singleband<npy_uint32> >())
+{
+    std::string neighborhood;
+    if(neighborspec == python::object())
+    {
+        neighborhood = "direct";
+    }
+    else if(python::extract<int>(neighborspec).check())
+    {
+        int n = python::extract<int>(neighborspec)();
+        if(n == 2*ndim || n == 0)
+        {
+            neighborhood = "direct";
+        }
+        else if(n == std::pow(3, ndim) - 1)
+        {
+            neighborhood = "indirect";
+        }
+    }
+    else if(python::extract<std::string>(neighborspec).check())
+    {
+        neighborhood = tolower(python::extract<std::string>(neighborspec)());
+        if (neighborhood == "")
+        {
+            neighborhood = "direct";
+        }
+    }
+
+    vigra_precondition(neighborhood == "direct" || neighborhood == "indirect",
+        "labelMultiArray(): neighborhood must be 'direct' or 'indirect' or '' (defaulting "
+        "to 'direct') or the appropriate number of neighbors (4 or 8 in 2D, 6 or 26 in 3D).");
+
+    std::string description("connected components, neighborhood=" + neighborhood);
+
+    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description),
+        "labelMultiArray(): Output array has wrong shape.");
+
+    {
+        PyAllowThreads _pythread;
+        if (neighborhood == "direct")
+        {
+            labelMultiArray(volume, res, DirectNeighborhood);
+        }
+        else
+        {
+            labelMultiArray(volume, res, IndirectNeighborhood);
+        }
+    }
+    return res;
+}
+
+VIGRA_PYTHON_MULTITYPE_FUNCTOR_NDIM(pyLabelMultiArray, pythonLabelMultiArray)
+
+template < class VoxelType, unsigned int ndim >
+NumpyAnyArray
+pythonLabelMultiArrayWithBackground(NumpyArray<ndim, Singleband<VoxelType> > volume,
+                                // std::string neighborhood="",
+                                python::object neighborspec=python::object(),
+                                VoxelType background_value = 0,
+                                NumpyArray<ndim, Singleband<npy_uint32> > res = NumpyArray<ndim, Singleband<npy_uint32> >())
+{
+    std::string neighborhood;
+    if(neighborspec == python::object())
+    {
+        neighborhood = "direct";
+    }
+    else if(python::extract<int>(neighborspec).check())
+    {
+        int n = python::extract<int>(neighborspec)();
+        if(n == 2*ndim || n == 0)
+        {
+            neighborhood = "direct";
+        }
+        else if(n == std::pow(3, ndim) - 1)
+        {
+            neighborhood = "indirect";
+        }
+    }
+    else if(python::extract<std::string>(neighborspec).check())
+    {
+        neighborhood = tolower(python::extract<std::string>(neighborspec)());
+        if (neighborhood == "")
+        {
+            neighborhood = "direct";
+        }
+    }
+
+    vigra_precondition(neighborhood == "direct" || neighborhood == "indirect",
+        "labelMultiArrayWithBackground(): neighborhood must be 'direct' or 'indirect' or '' (defaulting "
+        "to 'direct') or the appropriate number of neighbors (4 or 8 in 2D, 6 or 26 in 3D).");
+
+    std::string description("connected components with background, neighborhood=");
+    description += neighborhood + ", bglabel=" + asString(background_value);
+
+    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description),
+        "labelMultiArrayWithBackground(): Output array has wrong shape.");
+
+    {
+        PyAllowThreads _pythread;
+        if (neighborhood == "direct")
+        {
+            labelMultiArrayWithBackground(volume,
+                res, DirectNeighborhood,
+                background_value);
+        }
+        else
+        {
+            labelMultiArrayWithBackground(volume,
+                res, IndirectNeighborhood,
+                background_value);
+        }
+    }
+    return res;
+}
+
+VIGRA_PYTHON_MULTITYPE_FUNCTOR_NDIM(pyLabelMultiArrayWithBackground, pythonLabelMultiArrayWithBackground)
+
 /*********************************************************************************/
 
 // FIXME: support output of label images from localMinim/Maxima functions
 
 template < class PixelType >
-NumpyAnyArray 
+NumpyAnyArray
 pythonLocalMinima2D(NumpyArray<2, Singleband<PixelType> > image,
                     PixelType marker = NumericTraits<PixelType>::one(),
                     int neighborhood = 8,
+                    bool allowAtBorder = false,
+                    bool allowPlateaus = false,
                     NumpyArray<2, Singleband<PixelType> > res = NumpyArray<2, Singleband<PixelType> >())
 {
     vigra_precondition(neighborhood == 4 || neighborhood == 8,
@@ -231,37 +359,30 @@ pythonLocalMinima2D(NumpyArray<2, Singleband<PixelType> > image,
 
     std::string description("local minima, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
             "localMinima(): Output array has wrong shape.");
 
     {
-            PyAllowThreads _pythread;
-        switch (neighborhood)
-        {
-            case 4:
-            {
-                localMinima(srcImageRange(image), destImage(res), marker,
-                    FourNeighborCode());
-                break;
-            }
-            case 8:
-            {
-                localMinima(srcImageRange(image), destImage(res), marker,
-                    EightNeighborCode());
-                break;
-            }
-        }
+        PyAllowThreads _pythread;
+        localMinima(image, res,
+            LocalMinmaxOptions()
+                .neighborhood(neighborhood)
+                .allowAtBorder(allowAtBorder)
+                .markWith(marker)
+                .allowPlateaus(allowPlateaus));
     }
-    
+
     return res;
 }
 
 template<class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonLocalMinima3D(NumpyArray<3, Singleband<PixelType> > volume,
-                    PixelType marker = NumericTraits<PixelType>::one(), 
-                    int neighborhood = 6, 
+                    PixelType marker = NumericTraits<PixelType>::one(),
+                    int neighborhood = 6,
+                    bool allowAtBorder = false,
+                    bool allowPlateaus = false,
                     NumpyArray<3, Singleband<PixelType> > res = NumpyArray<3, Singleband<PixelType> >())
 {
     vigra_precondition(neighborhood == 6 || neighborhood == 26,
@@ -269,31 +390,25 @@ pythonLocalMinima3D(NumpyArray<3, Singleband<PixelType> > volume,
 
     std::string description("local minima, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description),
             "localMinima(): Output array has wrong shape.");
-            
-    switch (neighborhood)
+
     {
-        case 6:
-        {
-            localMinima3D(srcMultiArrayRange(volume), destMultiArray(res), marker,
-                    NeighborCode3DSix());
-            break;
-        }
-        case 26:
-        {
-            localMinima3D(srcMultiArrayRange(volume), destMultiArray(res), marker,
-                    NeighborCode3DTwentySix());
-            break;
-        }
+        PyAllowThreads _pythread;
+        localMinima(volume, res,
+            LocalMinmaxOptions()
+                .neighborhood(neighborhood)
+                .allowAtBorder(allowAtBorder)
+                .markWith(marker)
+                .allowPlateaus(allowPlateaus));
     }
 
     return res;
 }
 
 template < class PixelType >
-NumpyAnyArray 
+NumpyAnyArray
 pythonExtendedLocalMinima2D(NumpyArray<2, Singleband<PixelType> > image,
                             PixelType marker = NumericTraits<PixelType>::one(),
                             int neighborhood = 8,
@@ -304,8 +419,8 @@ pythonExtendedLocalMinima2D(NumpyArray<2, Singleband<PixelType> > image,
 
     std::string description("extended local minima, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
         "extendedLocalMinima(): Output array has wrong shape.");
 
     {
@@ -332,9 +447,9 @@ pythonExtendedLocalMinima2D(NumpyArray<2, Singleband<PixelType> > image,
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pyExtendedLocalMinima2D, pythonExtendedLocalMinima2D)
 
 template<class PixelType>
-NumpyAnyArray 
-pythonExtendedLocalMinima3D(NumpyArray<3, Singleband<PixelType> > volume, 
-                            PixelType marker = NumericTraits<PixelType>::one(), 
+NumpyAnyArray
+pythonExtendedLocalMinima3D(NumpyArray<3, Singleband<PixelType> > volume,
+                            PixelType marker = NumericTraits<PixelType>::one(),
                             int neighborhood = 6,
                             NumpyArray<3, Singleband<PixelType> > res = NumpyArray<3, Singleband<PixelType> >())
 {
@@ -343,8 +458,8 @@ pythonExtendedLocalMinima3D(NumpyArray<3, Singleband<PixelType> > volume,
 
     std::string description("extended local minima, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description),
             "extendedLocalMinima(): Output array has wrong shape.");
     switch (neighborhood)
     {
@@ -368,10 +483,12 @@ pythonExtendedLocalMinima3D(NumpyArray<3, Singleband<PixelType> > volume,
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pyExtendedLocalMinima3D, pythonExtendedLocalMinima3D)
 
 template < class PixelType >
-NumpyAnyArray 
+NumpyAnyArray
 pythonLocalMaxima2D(NumpyArray<2, Singleband<PixelType> > image,
                     PixelType marker = NumericTraits<PixelType>::one(),
                     int neighborhood = 8,
+                    bool allowAtBorder = false,
+                    bool allowPlateaus = false,
                     NumpyArray<2, Singleband<PixelType> > res = NumpyArray<2, Singleband<PixelType> >())
 {
     vigra_precondition(neighborhood == 4 || neighborhood == 8,
@@ -379,37 +496,30 @@ pythonLocalMaxima2D(NumpyArray<2, Singleband<PixelType> > image,
 
     std::string description("local maxima, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
             "localMaxima(): Output array has wrong shape.");
 
     {
         PyAllowThreads _pythread;
-        switch (neighborhood)
-        {
-            case 4:
-            {
-                localMaxima(srcImageRange(image), destImage(res), marker,
-                    FourNeighborCode());
-                break;
-            }
-            case 8:
-            {
-                localMaxima(srcImageRange(image), destImage(res), marker,
-                    EightNeighborCode());
-                break;
-            }
-        }
+        localMaxima(image, res,
+            LocalMinmaxOptions()
+                .neighborhood(neighborhood)
+                .allowAtBorder(allowAtBorder)
+                .markWith(marker)
+                .allowPlateaus(allowPlateaus));
     }
-    
+
     return res;
 }
 
 template<class PixelType>
-NumpyAnyArray 
+NumpyAnyArray
 pythonLocalMaxima3D(NumpyArray<3, Singleband<PixelType> > volume,
-                    PixelType marker = NumericTraits<PixelType>::one(), 
-                    int neighborhood = 6, 
+                    PixelType marker = NumericTraits<PixelType>::one(),
+                    int neighborhood = 6,
+                    bool allowAtBorder = false,
+                    bool allowPlateaus = false,
                     NumpyArray<3, Singleband<PixelType> > res = NumpyArray<3, Singleband<PixelType> >())
 {
     vigra_precondition(neighborhood == 6 || neighborhood == 26,
@@ -417,30 +527,25 @@ pythonLocalMaxima3D(NumpyArray<3, Singleband<PixelType> > volume,
 
     std::string description("local maxima, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description),
             "localMaxima(): Output array has wrong shape.");
-    switch (neighborhood)
+
     {
-        case 6:
-        {
-            localMaxima3D(srcMultiArrayRange(volume), destMultiArray(res), marker,
-                NeighborCode3DSix());
-            break;
-        }
-        case 26:
-        {
-            localMaxima3D(srcMultiArrayRange(volume), destMultiArray(res), marker,
-                NeighborCode3DTwentySix());
-            break;
-        }
+        PyAllowThreads _pythread;
+        localMaxima(volume, res,
+            LocalMinmaxOptions()
+                .neighborhood(neighborhood)
+                .allowAtBorder(allowAtBorder)
+                .markWith(marker)
+                .allowPlateaus(allowPlateaus));
     }
 
     return res;
 }
 
 template < class PixelType >
-NumpyAnyArray 
+NumpyAnyArray
 pythonExtendedLocalMaxima2D(NumpyArray<2, Singleband<PixelType> > image,
                             PixelType marker = NumericTraits<PixelType>::one(),
                             int neighborhood = 8,
@@ -451,8 +556,8 @@ pythonExtendedLocalMaxima2D(NumpyArray<2, Singleband<PixelType> > image,
 
     std::string description("extended local maxima, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
             "extendedLocalMaxima(): Output array has wrong shape.");
 
     {
@@ -477,9 +582,9 @@ pythonExtendedLocalMaxima2D(NumpyArray<2, Singleband<PixelType> > image,
 }
 
 template<class PixelType>
-NumpyAnyArray 
-pythonExtendedLocalMaxima3D(NumpyArray<3, Singleband<PixelType> > volume, 
-                            PixelType marker = NumericTraits<PixelType>::one(), 
+NumpyAnyArray
+pythonExtendedLocalMaxima3D(NumpyArray<3, Singleband<PixelType> > volume,
+                            PixelType marker = NumericTraits<PixelType>::one(),
                             int neighborhood = 6,
                             NumpyArray<3, Singleband<PixelType> > res = NumpyArray<3, Singleband<PixelType> >())
 {
@@ -488,8 +593,8 @@ pythonExtendedLocalMaxima3D(NumpyArray<3, Singleband<PixelType> > volume,
 
     std::string description("extended local maxima, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(volume.taggedShape().setChannelDescription(description),
             "extendedLocalMaxima(): Output array has wrong shape.");
     switch (neighborhood)
     {
@@ -514,31 +619,31 @@ pythonExtendedLocalMaxima3D(NumpyArray<3, Singleband<PixelType> > volume,
 
 #if 0
 template < class PixelType >
-python::tuple 
+python::tuple
 pythonWatersheds2DOld(NumpyArray<2, Singleband<PixelType> > image,
                    int neighborhood = 4,
                    NumpyArray<2, Singleband<npy_uint32> > seeds = python::object(),
-                   std::string method = "RegionGrowing", 
-                   SRGType srgType = CompleteGrow, 
-                   PixelType max_cost = 0.0, 
+                   std::string method = "RegionGrowing",
+                   SRGType srgType = CompleteGrow,
+                   PixelType max_cost = 0.0,
                    NumpyArray<2, Singleband<npy_uint32> > res = NumpyArray<2, Singleband<npy_uint32> >())
 {
     vigra_precondition(neighborhood == 4 || neighborhood == 8,
            "watersheds2D(): neighborhood must be 4 or 8.");
 
     method = tolower(method);
-    
+
     bool haveSeeds = seeds.hasData();
     unsigned int maxRegionLabel = 0;
-    
+
     if(method == "")
         method = "regiongrowing";
-    
+
     if(method == "regiongrowing")
     {
-        seeds.reshapeIfEmpty(image.shape(), 
+        seeds.reshapeIfEmpty(image.shape(),
                 "watersheds(): Seed array has wrong shape.");
-        
+
         if(!haveSeeds)
         {
             MultiArray<2, UInt8> minima(image.shape());
@@ -551,18 +656,18 @@ pythonWatersheds2DOld(NumpyArray<2, Singleband<PixelType> > image,
             inspectImage(srcImageRange(seeds), minmax);
             maxRegionLabel = minmax.max;
         }
-           
+
         res.reshapeIfEmpty(image.shape(), "watersheds(): Output array has wrong shape.");
 
         ArrayOfRegionStatistics< SeedRgDirectValueFunctor< PixelType > > stats(maxRegionLabel);
         if(neighborhood == 4)
         {
-            seededRegionGrowing(srcImageRange(image), srcImage(seeds), destImage(res), 
+            seededRegionGrowing(srcImageRange(image), srcImage(seeds), destImage(res),
                                 stats, srgType, FourNeighborCode(), max_cost);
         }
         else
         {
-            seededRegionGrowing(srcImageRange(image), srcImage(seeds), destImage(res), 
+            seededRegionGrowing(srcImageRange(image), srcImage(seeds), destImage(res),
                                 stats, srgType, EightNeighborCode(), max_cost);
         }
     }
@@ -572,9 +677,9 @@ pythonWatersheds2DOld(NumpyArray<2, Singleband<PixelType> > image,
            "watersheds(): UnionFind does not support seed images.");
         vigra_precondition(srgType == CompleteGrow,
            "watersheds(): UnionFind only supports 'CompleteGrow' mode.");
-           
+
         res.reshapeIfEmpty(image.shape(), "watersheds(): Output array has wrong shape.");
-        
+
         if(neighborhood == 4)
         {
             maxRegionLabel = watershedsUnionFind(srcImageRange(image), destImage(res),
@@ -596,13 +701,13 @@ pythonWatersheds2DOld(NumpyArray<2, Singleband<PixelType> > image,
 #endif
 
 template < class PixelType >
-python::tuple 
+python::tuple
 pythonWatersheds2D(NumpyArray<2, Singleband<PixelType> > image,
                    int neighborhood = 4,
                    NumpyArray<2, Singleband<npy_uint32> > seeds = NumpyArray<2, Singleband<npy_uint32> >(),
-                   std::string method = "", 
-                   SRGType srgType = CompleteGrow, 
-                   PixelType max_cost = 0.0, 
+                   std::string method = "",
+                   SRGType srgType = CompleteGrow,
+                   PixelType max_cost = 0.0,
                    NumpyArray<2, Singleband<npy_uint32> > res = NumpyArray<2, Singleband<npy_uint32> >())
 {
     vigra_precondition(neighborhood == 4 || neighborhood == 8,
@@ -616,23 +721,23 @@ pythonWatersheds2D(NumpyArray<2, Singleband<PixelType> > image,
         else
             method = "regiongrowing";
     }
-    
+
     std::string description("watershed labeling, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
             "watersheds(): Output array has wrong shape.");
-    
+
     WatershedOptions options;
     options.srgType(srgType);
-    
+
     if(max_cost > 0.0)
     {
         vigra_precondition(method != "unionfind",
            "watersheds(): UnionFind does not support a cost threshold.");
         options.stopAtThreshold(max_cost);
     }
-    
+
     if(seeds.hasData())
     {
         vigra_precondition(method != "unionfind",
@@ -646,7 +751,7 @@ pythonWatersheds2D(NumpyArray<2, Singleband<PixelType> > image,
         else
             options.seedOptions(SeedOptions().minima());
     }
-    
+
     if(method == "turbo")
     {
         vigra_precondition((IsSameType<PixelType, npy_uint8>::value),
@@ -654,19 +759,19 @@ pythonWatersheds2D(NumpyArray<2, Singleband<PixelType> > image,
         options.turboAlgorithm();
         method = "regiongrowing";
     }
-    
+
     npy_uint32 maxRegionLabel = 0;
     if(method == "regiongrowing")
     {
         PyAllowThreads _pythread;
         if(neighborhood == 4)
         {
-            maxRegionLabel = watershedsRegionGrowing(srcImageRange(image), destImage(res), 
+            maxRegionLabel = watershedsRegionGrowing(srcImageRange(image), destImage(res),
                                     FourNeighborCode(), options);
         }
         else
         {
-            maxRegionLabel = watershedsRegionGrowing(srcImageRange(image), destImage(res), 
+            maxRegionLabel = watershedsRegionGrowing(srcImageRange(image), destImage(res),
                                     EightNeighborCode(), options);
         }
     }
@@ -674,7 +779,7 @@ pythonWatersheds2D(NumpyArray<2, Singleband<PixelType> > image,
     {
         vigra_precondition(srgType == CompleteGrow,
            "watersheds(): UnionFind only supports 'CompleteGrow' mode.");
-           
+
         PyAllowThreads _pythread;
         if(neighborhood == 4)
         {
@@ -698,13 +803,13 @@ pythonWatersheds2D(NumpyArray<2, Singleband<PixelType> > image,
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pywatersheds2D, pythonWatersheds2D)
 
 template <unsigned int N, class PixelType >
-python::tuple 
+python::tuple
 pythonWatershedsNew(NumpyArray<N, Singleband<PixelType> > image,
                     int neighborhood = 0,
                     NumpyArray<N, Singleband<npy_uint32> > seeds = NumpyArray<N, Singleband<npy_uint32> >(),
-                    std::string method = "", 
-                    SRGType srgType = CompleteGrow, 
-                    PixelType max_cost = 0.0, 
+                    std::string method = "",
+                    SRGType srgType = CompleteGrow,
+                    PixelType max_cost = 0.0,
                     NumpyArray<N, Singleband<npy_uint32> > res = NumpyArray<N, Singleband<npy_uint32> >())
 {
     method = tolower(method);
@@ -712,16 +817,16 @@ pythonWatershedsNew(NumpyArray<N, Singleband<PixelType> > image,
     {
         method = "regiongrowing";
     }
-    
+
     std::string description("watershed labeling, neighborhood=");
     description += asString(neighborhood);
-    
-    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
             "watersheds(): Output array has wrong shape.");
-    
+
     WatershedOptions options;
     options.srgType(srgType);
-    
+
     if(method == "regiongrowing")
     {
         options.regionGrowing();
@@ -734,14 +839,14 @@ pythonWatershedsNew(NumpyArray<N, Singleband<PixelType> > image,
     {
         vigra_precondition(false, "watersheds(): Unknown watershed method requested.");
     }
-    
+
     if(max_cost > 0.0)
     {
         vigra_precondition(method != "unionfind",
            "watersheds(): UnionFind does not support a cost threshold.");
         options.stopAtThreshold(max_cost);
     }
-    
+
     if(seeds.hasData())
     {
         vigra_precondition(method != "unionfind",
@@ -752,10 +857,10 @@ pythonWatershedsNew(NumpyArray<N, Singleband<PixelType> > image,
     {
         options.seedOptions(SeedOptions().extendedMinima());
     }
-    
+
     NeighborhoodType n = (neighborhood == 0)
                              ? DirectNeighborhood
-                             : IndirectNeighborhood;    
+                             : IndirectNeighborhood;
     npy_uint32 maxRegionLabel = 0;
     {
         PyAllowThreads _pythread;
@@ -766,13 +871,13 @@ pythonWatershedsNew(NumpyArray<N, Singleband<PixelType> > image,
 }
 
 template <class PixelType >
-python::tuple 
+python::tuple
 pythonWatersheds2DNew(NumpyArray<2, Singleband<PixelType> > image,
                       int neighborhood = 4,
                       NumpyArray<2, Singleband<npy_uint32> > seeds = NumpyArray<2, Singleband<npy_uint32> >(),
-                      std::string method = "", 
-                      SRGType srgType = CompleteGrow, 
-                      PixelType max_cost = 0.0, 
+                      std::string method = "",
+                      SRGType srgType = CompleteGrow,
+                      PixelType max_cost = 0.0,
                       NumpyArray<2, Singleband<npy_uint32> > res = NumpyArray<2, Singleband<npy_uint32> >())
 {
     vigra_precondition(neighborhood == 4 || neighborhood == 8,
@@ -784,13 +889,13 @@ pythonWatersheds2DNew(NumpyArray<2, Singleband<PixelType> > image,
 }
 
 template <class PixelType >
-python::tuple 
+python::tuple
 pythonWatersheds3DNew(NumpyArray<3, Singleband<PixelType> > image,
                       int neighborhood = 6,
                       NumpyArray<3, Singleband<npy_uint32> > seeds = NumpyArray<3, Singleband<npy_uint32> >(),
-                      std::string method = "", 
-                      SRGType srgType = CompleteGrow, 
-                      PixelType max_cost = 0.0, 
+                      std::string method = "",
+                      SRGType srgType = CompleteGrow,
+                      PixelType max_cost = 0.0,
                       NumpyArray<3, Singleband<npy_uint32> > res = NumpyArray<3, Singleband<npy_uint32> >())
 {
     vigra_precondition(neighborhood == 6 || neighborhood == 26,
@@ -805,23 +910,23 @@ VIGRA_PYTHON_MULTITYPE_FUNCTOR(pywatersheds2DNew, pythonWatersheds2DNew)
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pywatersheds3DNew, pythonWatersheds3DNew)
 
 template < class PixelType >
-python::tuple 
+python::tuple
 pythonWatersheds3D(NumpyArray<3, Singleband<PixelType> > image,
                    int neighborhood = 6,
                    NumpyArray<3, Singleband<npy_uint32> > seeds = NumpyArray<3, Singleband<npy_uint32> >(),
-                   std::string method = "RegionGrowing", 
-                   SRGType srgType = CompleteGrow, 
-                   PixelType max_cost = 0.0, 
+                   std::string method = "RegionGrowing",
+                   SRGType srgType = CompleteGrow,
+                   PixelType max_cost = 0.0,
                    NumpyArray<3, Singleband<npy_uint32> > res = NumpyArray<3,Singleband<npy_uint32> >())
 {
     vigra_precondition(neighborhood == 6 || neighborhood == 26,
            "watersheds3D(): neighborhood must be 6 or 26.");
 
     method = tolower(method);
-    
+
     bool haveSeeds = seeds.hasData();
     unsigned int maxRegionLabel;
-    
+
     if(method == "")
     {
         if(IsSameType<PixelType, npy_uint8>::value)
@@ -829,7 +934,7 @@ pythonWatersheds3D(NumpyArray<3, Singleband<PixelType> > image,
         else
             method = "regiongrowing";
     }
-    
+
     if(method == "turbo")
     {
         vigra_precondition((Or<typename IsSameType<PixelType, npy_uint8>::type,
@@ -842,21 +947,21 @@ pythonWatersheds3D(NumpyArray<3, Singleband<PixelType> > image,
         vigra_precondition(max_cost == 0,
            "watersheds3D(): Turbo algorithm doesn't support 'max_cost'.");
     }
-    
+
     if(method == "regiongrowing" || method == "turbo")
     {
         std::string description("watershed seeds");
-        
-        seeds.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+        seeds.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
                 "watersheds(): Seed array has wrong shape.");
-        
+
         if(!haveSeeds)
         {
             PyAllowThreads _pythread;
             maxRegionLabel = 0;
-            
+
             MultiArray<3, npy_uint32> minima(seeds.shape());
-            
+
             if (neighborhood ==6)
             {
                 extendedLocalMinima3D(srcMultiArrayRange(image), destMultiArray(minima),
@@ -881,11 +986,11 @@ pythonWatersheds3D(NumpyArray<3, Singleband<PixelType> > image,
             inspectMultiArray(srcMultiArrayRange(seeds), minmax);
             maxRegionLabel = minmax.max;
         }
-           
+
         description = "watershed labeling, neighborhood=";
         description += asString(neighborhood);
-        
-        res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+        res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
                 "watersheds(): Output array has wrong shape.");
 
         PyAllowThreads _pythread;
@@ -895,20 +1000,20 @@ pythonWatersheds3D(NumpyArray<3, Singleband<PixelType> > image,
             if(method == "turbo")
             {
                 res = seeds;
-                
+
                 TWS<PixelType>::exec(image, res);
             }
             else
             {
-                seededRegionGrowing3D(srcMultiArrayRange(image), srcMultiArray(seeds), 
-                                      destMultiArray(res), 
+                seededRegionGrowing3D(srcMultiArrayRange(image), srcMultiArray(seeds),
+                                      destMultiArray(res),
                                       stats, srgType, NeighborCode3DSix(), max_cost);
             }
         }
         else
         {
-            seededRegionGrowing3D(srcMultiArrayRange(image), srcMultiArray(seeds), 
-                                  destMultiArray(res), 
+            seededRegionGrowing3D(srcMultiArrayRange(image), srcMultiArray(seeds),
+                                  destMultiArray(res),
                                   stats, srgType, NeighborCode3DTwentySix(), max_cost);
         }
     }
@@ -918,13 +1023,13 @@ pythonWatersheds3D(NumpyArray<3, Singleband<PixelType> > image,
            "watersheds(): UnionFind does not support seed images.");
         vigra_precondition(srgType == CompleteGrow,
            "watersheds(): UnionFind only supports 'CompleteGrow' mode.");
-           
+
         std::string description("watershed labeling, neighborhood=");
         description += asString(neighborhood);
-        
-        res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description), 
+
+        res.reshapeIfEmpty(image.taggedShape().setChannelDescription(description),
                 "watersheds(): Output array has wrong shape.");
-        
+
         PyAllowThreads _pythread;
         if(neighborhood == 6)
         {
@@ -946,33 +1051,33 @@ pythonWatersheds3D(NumpyArray<3, Singleband<PixelType> > image,
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pywatersheds3D, pythonWatersheds3D)
 
 template <unsigned int N, class PixelType >
-python::tuple 
+python::tuple
 pythonSlic(NumpyArray<N, PixelType > array,
            double intensityScaling,
            unsigned int seedDistance,
-           unsigned int minSize = 0,            // choose minSize automatically 
-           unsigned int iterations = 10, 
+           unsigned int minSize = 0,            // choose minSize automatically
+           unsigned int iterations = 10,
            NumpyArray<N, Singleband<npy_uint32> > res = NumpyArray<N, Singleband<npy_uint32> >())
 {
     typedef typename detail::ResolveMultiband<PixelType>::type ValueType;
     typedef typename NormTraits<ValueType>::NormType TmpType;
-    
+
     std::string description("Slic superpixels");
-    
-    res.reshapeIfEmpty(array.taggedShape().setChannelDescription(description), 
+
+    res.reshapeIfEmpty(array.taggedShape().setChannelDescription(description),
             "slicSuperpixels(): Output array has wrong shape.");
-    
+
     npy_uint32 maxRegionLabel = 0;
     {
         PyAllowThreads _pythread;
-        
+
         MultiArray<N, TmpType> gradMag(array.shape());
-        
+
         // the original code uses the symmetric difference instead of a Gaussian gradient
         gaussianGradientMagnitude(array, gradMag, 1.0);
         // search radius of 1 is also used in the original code
         generateSlicSeeds(gradMag, res, seedDistance, 1);
-        
+
         maxRegionLabel = slicSuperpixels(array, res, intensityScaling, seedDistance,
                                          SlicOptions().iterations(iterations)
                                                       .minSize(minSize));
@@ -982,12 +1087,12 @@ pythonSlic(NumpyArray<N, PixelType > array,
 }
 
 template <class PixelType >
-python::tuple 
+python::tuple
 pythonSlic2D(NumpyArray<2, PixelType > image,
              double intensityScaling,
              unsigned int seedDistance,
-             unsigned int minSize = 0,            // choose minSize automatically 
-             unsigned int iterations = 10, 
+             unsigned int minSize = 0,            // choose minSize automatically
+             unsigned int iterations = 10,
              NumpyArray<2, Singleband<npy_uint32> > res = NumpyArray<2, Singleband<npy_uint32> >())
 {
     return pythonSlic(image, intensityScaling, seedDistance, minSize, iterations, res);
@@ -996,12 +1101,12 @@ pythonSlic2D(NumpyArray<2, PixelType > image,
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pySlic2D, pythonSlic2D)
 
 template <class PixelType >
-python::tuple 
+python::tuple
 pythonSlic3D(NumpyArray<3, PixelType > image,
              double intensityScaling,
              unsigned int seedDistance,
-             unsigned int minSize = 0,            // choose minSize automatically 
-             unsigned int iterations = 10, 
+             unsigned int minSize = 0,            // choose minSize automatically
+             unsigned int iterations = 10,
              NumpyArray<3, Singleband<npy_uint32> > res = NumpyArray<3, Singleband<npy_uint32> >())
 {
     return pythonSlic(image, intensityScaling, seedDistance, minSize, iterations, res);
@@ -1009,22 +1114,125 @@ pythonSlic3D(NumpyArray<3, PixelType > image,
 
 VIGRA_PYTHON_MULTITYPE_FUNCTOR(pySlic3D, pythonSlic3D)
 
+
+template<unsigned int DIM>
+NumpyAnyArray  pythonShrinkLabels(
+    NumpyArray<DIM,npy_uint32> labels,
+    const size_t shrinkNpixels,
+    NumpyArray<DIM,Singleband<npy_uint32> > out = NumpyArray<DIM,Singleband<npy_uint32> >()
+){
+    out.reshapeIfEmpty(labels.shape());
+    shrinkLabels(labels,shrinkNpixels,out);
+    return out;
+}
+
+
+template<class T>
+vigra::NumpyAnyArray pySizeFilterSegInplace(vigra::NumpyArray<3, T>  seg, const vigra::UInt32 maxLabel, const vigra::UInt32 sizeLimit, bool checkAtBorder=false){
+
+
+    std::vector<bool > atBorder(maxLabel+1, false);
+
+    if (! checkAtBorder){
+        for(std::ptrdiff_t z=0;z<seg.shape(2); ++z)
+        for(std::ptrdiff_t y=0;y<seg.shape(1); ++y){
+            atBorder[seg(0,y,z)] = true;
+            atBorder[seg(seg.shape(0)-1,y,z)] = true;
+        }
+
+        for(std::ptrdiff_t z=0;z<seg.shape(2); ++z)
+        for(std::ptrdiff_t x=0;x<seg.shape(0); ++x){
+            atBorder[seg(x,0,z)] = true;
+            atBorder[seg(x,seg.shape(1)-1,z)] = true;
+        }
+
+        for(std::ptrdiff_t y=0;y<seg.shape(1); ++y)
+        for(std::ptrdiff_t x=0;x<seg.shape(0); ++x){
+            atBorder[seg(x,y,0)] = true;
+            atBorder[seg(x,y,seg.shape(2)-1)] = true;
+        }
+    }
+
+
+
+    std::vector<size_t > counts(maxLabel+1,0);
+
+    for(auto iter = seg.begin(); iter!=seg.end(); ++iter){
+        counts[*iter] += 1;
+    }
+
+
+
+    for(auto iter = seg.begin(); iter!=seg.end(); ++iter){
+        const auto l = *iter;
+        const auto c = counts[l];
+        if(c<sizeLimit && atBorder[l] == false){
+            *iter = 0;
+        }
+    }
+
+    return seg;
+}
+
+
+template<unsigned int DIM>
+python::tuple  pyUnionFindWatershedsBlockwise(
+    NumpyArray<DIM,float> data,
+    TinyVector<Int64, DIM> blockShape,
+    NumpyArray<DIM, UInt32 > out
+){
+    out.reshapeIfEmpty(data.shape());
+    UInt64 nSeg =  unionFindWatershedsBlockwise(data, out,
+                                                BlockwiseLabelOptions().neighborhood(DirectNeighborhood)
+                                                                       .blockShape(blockShape));
+    return python::make_tuple(out, nSeg);
+}
+
 void defineSegmentation()
 {
     using namespace python;
-    
+
     docstring_options doc_options(true, true, false);
 
-    multidef("labelImage", pyLabelImage<npy_uint8, npy_uint32, float>(),
-        (arg("image"), 
+
+    python::def("unionFindWatershed3D",
+        registerConverters(&pyUnionFindWatershedsBlockwise<3>),
+        (
+            python::arg("image"),
+            python::arg("blockShape"),
+            python::arg("out") = python::object()
+        )
+    );
+
+    python::def("segToSeeds", registerConverters(pythonShrinkLabels<2>),
+        (
+            python::arg("image"),
+            python::arg("shrinkN"),
+            python::arg("out")=python::object()
+        ),
+        "shrink / ungrow a labeling / segmentation"
+    );
+
+    python::def("segToSeeds", registerConverters(pythonShrinkLabels<3>),
+        (
+            python::arg("image"),
+            python::arg("shrinkN"),
+            python::arg("out")=python::object()
+        ),
+        "shrink / ungrow a labeling / segmentation"
+    );
+
+    multidef("labelImage", pyLabelMultiArray<2, npy_uint8, npy_uint32, float>(),
+        (arg("image"),
         arg("neighborhood") = 4,
         arg("out")=python::object()),
         "Find the connected components of a segmented image. Parameter 'neighborhood' specifies "
         "the pixel neighborhood to be used and can be 4 (default) or 8.\n\n"
-        "For details see labelImage_ in the vigra C++ documentation.\n");
+        "For details see labelMultiArray_ in the vigra C++ documentation.\n");
 
-    multidef("labelImageWithBackground", pyLabelImageWithBackground<npy_uint8, npy_uint32, float>(),
-        (arg("image"), 
+    multidef("labelImageWithBackground",
+         pyLabelMultiArrayWithBackground<2, npy_uint8, npy_uint32, float>(),
+        (arg("image"),
         arg("neighborhood") = 4,
         arg("background_value") = 0,
         arg("out")=python::object()),
@@ -1032,20 +1240,21 @@ void defineSegmentation()
         "background from labeling, where the background is the set of all pixels with "
         "the given 'background_value'. Parameter 'neighborhood' specifies "
         "the pixel neighborhood to be used and can be 4 (default) or 8.\n\n"
-        "For details see labelImageWithBackground_ in the vigra C++ documentation.\n");
+        "For details see labelMultiArrayWithBackground_ in the vigra C++ documentation.\n");
 
-    multidef("labelVolume", pyLabelVolume<npy_uint8, npy_uint32, float>(),
-        (arg("volume"), 
+    multidef("labelVolume", pyLabelMultiArray<3, npy_uint8, npy_uint32, float>(),
+        (arg("volume"),
         arg("neighborhood")=6,
         arg("out")=python::object()),
         "Find the connected components of a segmented volume. Parameter 'neighborhood' specifies "
         "the pixel neighborhood to be used and can be 6 (default) or 26.\n"
         "\n"
-        "For details see labelVolume_ in the vigra C++ documentation.\n");
+        "For details see labelMultiArray_ in the vigra C++ documentation.\n");
 
-    multidef("labelVolumeWithBackground", pyLabelVolumeWithBackground<npy_uint8, npy_uint32, float>(),
-        (arg("volume"), 
-         arg("neighborhood")=6, 
+    multidef("labelVolumeWithBackground",
+        pyLabelMultiArrayWithBackground<3, npy_uint8, npy_uint32, float>(),
+        (arg("volume"),
+         arg("neighborhood")=6,
          arg("background_value")=0,
          arg("out")=python::object()),
         "Find the connected components of a segmented volume, excluding the "
@@ -1053,34 +1262,122 @@ void defineSegmentation()
         "the given 'background_value'. Parameter 'neighborhood' specifies "
         "the pixel neighborhood to be used and can be 6 (default) or 26.\n"
         "\n"
-        "For details see labelVolumeWithBackground_ in the vigra C++ documentation.\n");
-    
+        "For details see labelMultiArrayWithBackground_ in the vigra C++ documentation.\n");
+
+    multidef("labelMultiArray", pyLabelMultiArray<2, npy_uint8, npy_uint32, float>(),
+        (arg("array"), arg("neighborhood")="", arg("out")=python::object()),
+        "Find the connected components of a segmented image."
+        "Parameter 'neighborhood' specifies the pixel neighborhood "
+        "to be used and can be 'direct' (default) or 'indirect' or 4 or 8.\n"
+        "\n"
+        "For details see labelMultiArray_ in the vigra C++ documentation.\n");
+
+    multidef("labelMultiArray", pyLabelMultiArray<3, npy_uint8, npy_uint32, float>(),
+        (arg("array"), arg("neighborhood")="", arg("out")=python::object()),
+        "Find the connected components of a segmented volume."
+        "Parameter 'neighborhood' specifies the voxel neighborhood "
+        "to be used and can be 'direct' (default) or 'indirect' or 6 or 26.\n");
+
+    multidef("labelMultiArray", pyLabelMultiArray<4, npy_uint8, npy_uint32, float>(),
+        (arg("array"), arg("neighborhood")="", arg("out")=python::object()),
+        "Find the connected components of a segmented 4D array."
+        "Parameter 'neighborhood' specifies the pixel neighborhood "
+        "to be used and can be 'direct' (default) or 'indirect' or 8 or 80.\n");
+
+    multidef("labelMultiArray", pyLabelMultiArray<5, npy_uint8, npy_uint32, float>(),
+        (arg("array"), arg("neighborhood")="", arg("out")=python::object()),
+        "Find the connected components of a segmented 5D array."
+        "Parameter 'neighborhood' specifies the pixel neighborhood "
+        "to be used and can be 'direct' (default) or 'indirect' or 10 or 242.\n");
+
+    multidef("labelMultiArrayWithBackground",
+        pyLabelMultiArrayWithBackground<2, npy_uint8, npy_uint32, float>(),
+        (arg("array"), arg("neighborhood")="", arg("background_value")=0, arg("out")=python::object()),
+        "Find the connected components of a segmented image, excluding the "
+        "background from labeling, where the background is the set of all pixels with "
+        "the given 'background_value'. Parameter 'neighborhood' specifies "
+        "the pixel neighborhood to be used and can be 'direct' (default) or 'indirect'\n"
+        " or 4 or 8.\n"
+        "\n"
+        "For details see labelMultiArrayWithBackground_ in the vigra C++ documentation.\n");
+
+    multidef("labelMultiArrayWithBackground",
+        pyLabelMultiArrayWithBackground<3, npy_uint8, npy_uint32, float>(),
+        (arg("array"), arg("neighborhood")="", arg("background_value")=0, arg("out")=python::object()),
+        "Find the connected components of a segmented volume, excluding the "
+        "background from labeling, where the background is the set of all pixels with "
+        "the given 'background_value'. Parameter 'neighborhood' specifies "
+        "the pixel neighborhood to be used and can be 'direct' (default) or 'indirect'\n"
+        " or 6 or 26.\n");
+
+    multidef("labelMultiArrayWithBackground",
+        pyLabelMultiArrayWithBackground<4, npy_uint8, npy_uint32, float>(),
+        (arg("array"), arg("neighborhood")="", arg("background_value")=0, arg("out")=python::object()),
+        "Find the connected components of a segmented 4D array, excluding the "
+        "background from labeling, where the background is the set of all pixels with "
+        "the given 'background_value'. Parameter 'neighborhood' specifies "
+        "the pixel neighborhood to be used and can be 'direct' (default) or 'indirect'\n"
+        " or 8 or 80.\n");
+
+    multidef("labelMultiArrayWithBackground",
+        pyLabelMultiArrayWithBackground<5, npy_uint8, npy_uint32, float>(),
+        (arg("array"), arg("neighborhood")="", arg("background_value")=0, arg("out")=python::object()),
+        "Find the connected components of a segmented 5D array, excluding the "
+        "background from labeling, where the background is the set of all pixels with "
+        "the given 'background_value'. Parameter 'neighborhood' specifies "
+        "the pixel neighborhood to be used and can be 'direct' (default) or 'indirect'\n"
+        " or 10 or 242.\n");
+
+    def("sizeFilterSegInplace",registerConverters(&pySizeFilterSegInplace<UInt32>),
+        (
+            arg("seg"),
+            arg("maxLabel"),
+            arg("sizeLimit"),
+            arg("checkAtBorder") = false
+        ),
+        "replace every occurance of each number in the array 'seg' with zeros if this number"
+        " occures less than 'sizeLimit' times in the array. If 'checkAtBorder' is false (default) "
+        "segments that touch the border of the array will not be changed.\n"
+        "'maxLabel' is the maximum label in seg\n"
+    );
+
     /******************************************************************************/
-    
+
     def("localMinima",
         registerConverters(&pythonLocalMinima2D<float>),
-        (arg("image"), 
-         arg("marker")=1.0, 
+        (arg("image"),
+         arg("marker")=1.0,
          arg("neighborhood") = 8,
+         arg("allowAtBorder") = false,
+         arg("allowPlateaus") = false,
          arg("out")=python::object()),
         "Find local minima in an image and mark them with the given 'marker'. Parameter "
         "'neighborhood' specifies the pixel neighborhood to be used and can be "
-        "4 or 8 (default).\n\n"
+        "4 or 8 (default). \n"
+        "If 'allowAtBorder' is true local minima at the image border will be detected.\n"
+        "If 'allowPlateaus' is true regions of constant gray value whose neighbors are all higher than the value of the region will be detected."
+        "\n\n"
         "For details see localMinima_ in the vigra C++ documentation.\n");
 
     def("localMinima3D",
-            registerConverters(&pythonLocalMinima3D<float> ),
-            (arg("volume"), arg("marker") = 1.0, arg("neighborhood") = 6, arg(
-                    "out") = python::object()),
-            "Find local minima in a volume and mark them with the given 'marker'. Parameter "
-                "'neighborhood' specifies the pixel neighborhood to be used and can be "
-                "6 or 26 (default).\n\n"
-                "For details see localMinima3D_ in the vigra C++ documentation.\n");
+        registerConverters(&pythonLocalMinima3D<float> ),
+        (arg("volume"),
+         arg("marker") = 1.0,
+         arg("neighborhood") = 6,
+         arg("allowAtBorder") = false,
+         arg("allowPlateaus") = false,
+         arg("out") = python::object()),
+        "Find local minima in a volume and mark them with the given 'marker'. Parameter "
+        "6 (default) or 26.\n"
+        "If 'allowAtBorder' is set to 'True' local minima at the volume border will be detected.\n"
+        "If 'allowPlateaus' is set to 'True' regions of constant gray value whose neighbors are all higher than the value of the region will be detected."
+        "\n\n"
+        "For details see localMinima_ in the vigra C++ documentation.\n");
 
     // def("extendedLocalMinima",
         // registerConverters(&pythonExtendedLocalMinima2D<float>),
-        // (arg("image"), 
-         // arg("marker")=1.0, 
+        // (arg("image"),
+         // arg("marker")=1.0,
          // arg("neighborhood") = 8,
          // arg("out")=python::object()),
         // "Find local minima and minimal plateaus in an image and mark them with "
@@ -1091,8 +1388,8 @@ void defineSegmentation()
 
     multidef("extendedLocalMinima",
         pyExtendedLocalMinima2D<npy_uint8, float>(),
-        (arg("image"), 
-         arg("marker")=1.0, 
+        (arg("image"),
+         arg("marker")=1.0,
          arg("neighborhood") = 8,
          arg("out")=python::object()),
         "Find local minima and minimal plateaus in an image and mark them with "
@@ -1102,7 +1399,7 @@ void defineSegmentation()
         );
 
     multidef("extendedLocalMinima3D",
-        pyExtendedLocalMinima3D<float, npy_uint8>(), 
+        pyExtendedLocalMinima3D<float, npy_uint8>(),
         (arg("volume"), arg("marker") = 1, arg("neighborhood") = 6, arg("out") = python::object()),
         "Find local minima and minimal plateaus in a volume and mark them with "
         "the given 'marker'. Parameter 'neighborhood' specifies the pixel "
@@ -1111,26 +1408,39 @@ void defineSegmentation()
 
     def("localMaxima",
         registerConverters(&pythonLocalMaxima2D<float>),
-        (arg("image"), 
-         arg("marker")=1.0, 
+        (arg("image"),
+         arg("marker")=1.0,
          arg("neighborhood") = 8,
+         arg("allowAtBorder") = false,
+         arg("allowPlateaus") = false,
          arg("out")=python::object()),
         "Find local maxima in an image and mark them with the given 'marker'. Parameter "
         "'neighborhood' specifies the pixel neighborhood to be used and can be "
-        "4 or 8 (default).\n\n"
+        "4 or 8 (default).\n"
+        "If 'allowAtBorder' is set to 'True' local maxima at image border will be detected.\n"
+        "If 'allowPlateaus' is set to 'True' regions of constant gray value whose neighbors are all lower than the value of the region will be detected."
+        "\n\n"
         "For details see localMaxima_ in the vigra C++ documentation.\n");
 
-    def("localMaxima3D", registerConverters(&pythonLocalMaxima3D<float> ), 
-         (arg("volume"), arg("marker") = 1.0, arg("neighborhood") = 6, arg("out") = python::object()),
-            "Find local maxima and maximal plateaus in a volume and mark them with "
-            "the given 'marker'. Parameter 'neighborhood' specifies the pixel "
-            "neighborhood to be used and can be 6(default) or 26 .\n\n"
-            "For details see localMaxima3D_ in the vigra C++ documentation.\n");
+    def("localMaxima3D", registerConverters(&pythonLocalMaxima3D<float> ),
+        (arg("volume"),
+         arg("marker") = 1.0,
+         arg("neighborhood") = 6,
+         arg("allowAtBorder") = false,
+         arg("allowPlateaus") = false,
+         arg("out") = python::object()),
+        "Find local maxima and maximal plateaus in a volume and mark them with "
+        "the given 'marker'. Parameter 'neighborhood' specifies the pixel "
+        "neighborhood to be used and can be 6(default) or 26.\n"
+        "If 'allowAtBorder' is set to 'True' local maxima at the volume border will be detected.\n"
+        "If 'allowPlateaus' is set to 'True' regions of constant gray value whose neighbors are all lower than the value of the region will be detected."
+        "\n\n"
+        "For details see localMaxima_ in the vigra C++ documentation.\n");
 
     def("extendedLocalMaxima",
         registerConverters(&pythonExtendedLocalMaxima2D<float>),
-        (arg("image"), 
-         arg("marker")=1.0, 
+        (arg("image"),
+         arg("marker")=1.0,
          arg("neighborhood") = 8,
          arg("out")=python::object()),
         "Find local maxima and maximal plateaus in an image and mark them with "
@@ -1138,8 +1448,8 @@ void defineSegmentation()
         "neighborhood to be used and can be 4 or 8 (default).\n\n"
         "For details see extendedLocalMaxima_ in the vigra C++ documentation.\n");
 
-    def("extendedLocalMaxima3D", 
-        registerConverters(&pythonExtendedLocalMaxima3D<float> ), 
+    def("extendedLocalMaxima3D",
+        registerConverters(&pythonExtendedLocalMaxima3D<float> ),
         (arg("volume"), arg("marker") = 1.0, arg("neighborhood") = 6, arg("out") = python::object()),
         "Find local maxima and maximal plateaus in a volume and mark them with "
         "the given 'marker'. Parameter 'neighborhood' specifies the pixel "
@@ -1156,9 +1466,9 @@ void defineSegmentation()
 
     /*  FIXME: int64 is unsupported by the C++ code (hard-coded int) */
     multidef("watersheds", pywatersheds2D< npy_uint8, float >(),
-      (arg("image"), 
-       arg("neighborhood") = 4, 
-       arg("seeds")=python::object(), 
+      (arg("image"),
+       arg("neighborhood") = 4,
+       arg("seeds")=python::object(),
        arg("method")="",
        arg("terminate")=CompleteGrow,
        arg("max_cost")=0,
@@ -1181,11 +1491,11 @@ void defineSegmentation()
         "        6 (default) or 26\n\n"
         " seeds:\n"
         "    a label image specifying region seeds, only supported by methods 'RegionGrowing' and 'Turbo'"
-        "    (with dtype=numpy.uint32).\n" 
+        "    (with dtype=numpy.uint32).\n"
         " method:\n"
         "    the algorithm to be used for watershed computation. Possible values:\n\n"
         "      'Turbo':\n"
-        "        (default if input dtype == uint8) use fastSeededRegionGrowing_ or tws() respectively\n"
+        "        (default if input dtype == uint8) use fastSeededRegionGrowing() (in 2D) or tws() (in 3D)\n"
         "      'RegionGrowing':\n"
         "        (default if input dtype != uint8) use seededRegionGrowing_ or seededRegionGrowing3D_ respectively\n"
         "      'UnionFind:\n"
@@ -1205,7 +1515,7 @@ void defineSegmentation()
         "        supported by method 'RegionGrowing'\n\n"
         " max_cost:\n"
         "    terminate growing when boundary indicator exceeds this value (ignored when "
-        "    'terminate' is not StopAtThreshold or method is not 'RegionGrowing')\n" 
+        "    'terminate' is not StopAtThreshold or method is not 'RegionGrowing')\n"
         " out:\n"
         "    the label image (with dtype=numpy.uint32) to be filled by the algorithm. "
         "    It will be allocated by the watershed function if not provided)\n\n"
@@ -1213,9 +1523,9 @@ void defineSegmentation()
          );
 
     multidef("watersheds", pywatersheds3D< npy_uint8, float >(),
-      (arg("volume"), 
-       arg("neighborhood") = 6, 
-       arg("seeds")=python::object(), 
+      (arg("volume"),
+       arg("neighborhood") = 6,
+       arg("seeds")=python::object(),
        arg("method")="",
        arg("terminate")=CompleteGrow,
        arg("max_cost")=0,
@@ -1223,9 +1533,9 @@ void defineSegmentation()
        "Likewise, compute watersheds of a volume.\n");
 
     multidef("watershedsNew", pywatersheds2DNew< npy_uint8, float >(),
-      (arg("image"), 
-       arg("neighborhood") = 4, 
-       arg("seeds")=python::object(), 
+      (arg("image"),
+       arg("neighborhood") = 4,
+       arg("seeds")=python::object(),
        arg("method")="",
        arg("terminate")=CompleteGrow,
        arg("max_cost")=0,
@@ -1233,9 +1543,9 @@ void defineSegmentation()
        "graph-based watershed");
 
     multidef("watershedsNew", pywatersheds3DNew< npy_uint8, float >(),
-      (arg("image"), 
-       arg("neighborhood") = 6, 
-       arg("seeds")=python::object(), 
+      (arg("image"),
+       arg("neighborhood") = 6,
+       arg("seeds")=python::object(),
        arg("method")="",
        arg("terminate")=CompleteGrow,
        arg("max_cost")=0,
@@ -1243,9 +1553,9 @@ void defineSegmentation()
        "graph-based watershed");
 
     multidef("slicSuperpixels", pySlic2D< TinyVector<float, 3>, Singleband<float> >(),
-      (arg("image"), 
-       arg("intensityScaling"), 
-       arg("seedDistance"), 
+      (arg("image"),
+       arg("intensityScaling"),
+       arg("seedDistance"),
        arg("minSize")=0,
        arg("iterations")=10,
        arg("out")=python::object()),
@@ -1269,13 +1579,14 @@ void defineSegmentation()
         "The function returns a Python tuple (labelImage, maxRegionLabel)\n\n");
 
     multidef("slicSuperpixels", pySlic3D< TinyVector<float, 3>, Singleband<float> >(),
-      (arg("image"), 
-       arg("intensityScaling"), 
-       arg("seedDistance"), 
+      (arg("image"),
+       arg("intensityScaling"),
+       arg("seedDistance"),
        arg("minSize")=0,
        arg("iterations")=10,
        arg("out")=python::object()),
        "Likewise compute Slic superpixels for a 3D volume, either single- or threeband.\n");
+
 }
 
 void defineEdgedetection();
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/vigranumpy/src/core/utilities.cxx
similarity index 64%
copy from vigranumpy/src/core/vigranumpycore.cxx
copy to vigranumpy/src/core/utilities.cxx
index 37a8c81..f8af573 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/vigranumpy/src/core/utilities.cxx
@@ -1,6 +1,6 @@
 /************************************************************************/
 /*                                                                      */
-/*                 Copyright 2009 by Ullrich Koethe                     */
+/*                 Copyright 2011 by Ullrich Koethe                     */
 /*                                                                      */
 /*    This file is part of the VIGRA computer vision library.           */
 /*    The VIGRA Website is                                              */
@@ -33,42 +33,67 @@
 /*                                                                      */
 /************************************************************************/
 
-#define PY_ARRAY_UNIQUE_SYMBOL vigranumpycore_PyArray_API
+#define PY_ARRAY_UNIQUE_SYMBOL vigranumpyutilities_PyArray_API
+//#define NO_IMPORT_ARRAY
 
-#include <Python.h>
-#include <vigra/config.hxx>
-#include <iostream>
-#include <boost/python.hpp>
 #include <vigra/numpy_array.hxx>
 #include <vigra/numpy_array_converters.hxx>
-#include <vigra/functorexpression.hxx>
-#include <vigra/mathutil.hxx>
-#include <vigra/utilities.hxx>
-#include <vector>
+#include <vigra/priority_queue.hxx>
+
+// Amazingly, the include order matters to Mac OS clang.
+// This line must come after the includes above.
+#include <string>
 
 namespace python = boost::python;
 
-namespace vigra {
+namespace vigra{
 
-UInt32 pychecksum(python::str const & s)
-{
-    unsigned int size = len(s);
-    return checksum(PyString_AsString(s.ptr()), size);
-}
+    template<class PQ>
+    void pyPush(
+        PQ & pq, 
+        const NumpyArray<1,UInt32> indices,
+        const NumpyArray<1,float>  priorities
+    ){
+        for(std::ptrdiff_t i=0;i<indices.shape(0);++i){
+            pq.push(indices(i),priorities(i));
+        }
+    }
+
+
+
+
+
+    template<class T,class COMP>
+	void defineChangeablePriorityQueue(const std::string & clsName){
 
-void registerNumpyArrayConverters();
-void defineAxisTags();
+        typedef ChangeablePriorityQueue<T,COMP> PQ;
+
+        python::class_<PQ>(clsName.c_str(),python::init<const size_t>())
+        .def("push",            registerConverters(&pyPush<PQ>))
+        .def("push",            &PQ::push)
+        .def("pop",             &PQ::pop)
+        .def("top",             &PQ::top)
+        .def("topPriority",     &PQ::topPriority)
+        .def("deleteItem",      &PQ::deleteItem)
+        .def("__len__",         &PQ::size)
+        .def("contains",    &PQ::contains)
+        .def("__empty__",       &PQ::empty)
+        ;
+
+    }
 
 } // namespace vigra
 
-using namespace boost::python;
 using namespace vigra;
+using namespace boost::python;
 
-BOOST_PYTHON_MODULE_INIT(vigranumpycore)
+
+
+
+BOOST_PYTHON_MODULE_INIT(utilities)
 {
-    import_array();
-    registerNumpyArrayConverters();
-    defineAxisTags();
-    
-    def("checksum", &pychecksum, args("data"));
+    import_vigranumpy();
+
+    // all exporters needed for graph exporters (like lemon::INVALID)
+    defineChangeablePriorityQueue<float,std::less<float> >("ChangeablePriorityQueueFloat32Min");
 }
diff --git a/vigranumpy/src/core/vigranumpycore.cxx b/vigranumpy/src/core/vigranumpycore.cxx
index 37a8c81..ed7effb 100644
--- a/vigranumpy/src/core/vigranumpycore.cxx
+++ b/vigranumpy/src/core/vigranumpycore.cxx
@@ -58,6 +58,7 @@ UInt32 pychecksum(python::str const & s)
 
 void registerNumpyArrayConverters();
 void defineAxisTags();
+void defineChunkedArray();
 
 } // namespace vigra
 
@@ -69,6 +70,7 @@ BOOST_PYTHON_MODULE_INIT(vigranumpycore)
     import_array();
     registerNumpyArrayConverters();
     defineAxisTags();
+    defineChunkedArray();
     
     def("checksum", &pychecksum, args("data"));
 }
diff --git a/vigranumpy/src/fourier/CMakeLists.txt b/vigranumpy/src/fourier/CMakeLists.txt
index 7c9f154..7f9f3dc 100644
--- a/vigranumpy/src/fourier/CMakeLists.txt
+++ b/vigranumpy/src/fourier/CMakeLists.txt
@@ -1,5 +1,7 @@
 INCLUDE_DIRECTORIES(${VIGRANUMPY_INCLUDE_DIRS} ${FFTW3_INCLUDE_DIR})
 
+VIGRA_CONFIGURE_THREADING()
+
 VIGRA_ADD_NUMPY_MODULE(fourier 
   SOURCES
     fourier.cxx
diff --git a/vigranumpy/test/CMakeLists.txt b/vigranumpy/test/CMakeLists.txt
index f1b30c2..655f6d5 100644
--- a/vigranumpy/test/CMakeLists.txt
+++ b/vigranumpy/test/CMakeLists.txt
@@ -2,11 +2,14 @@ INCLUDE_DIRECTORIES(${VIGRANUMPY_INCLUDE_DIRS})
 
 SET(TEST_SCRIPTS
     test_arraytypes.py
+    test_rf.py
     test_impex.py
     test1.py
     test2.py
     test3.py
+    test4.py
     test_color.py
+    test_segmentation.py
     )
 
 # setup the file 'testsuccess.cxx' which will become out-of-date when the
@@ -15,7 +18,7 @@ SET(TEST_SUCCESS_FILE "${CMAKE_CURRENT_BINARY_DIR}/testsuccess.cxx")
 
 # find the vigranumpy modules that we want to test, and make
 # 'testsuccess.cxx' depend on them
-# TODO: Does cmake provide a standard way to find those dependencies? 
+# TODO: Does cmake provide a standard way to find those dependencies?
 GET_TARGET_PROPERTY(VIGRANUMPY_DEPENDS vigranumpy VIGRA_DEPENDS)
 SEPARATE_ARGUMENTS(VIGRANUMPY_DEPENDS)
 
@@ -34,7 +37,7 @@ ENDIF()
 
 # setup the test target
 IF(AUTOBUILD_TESTS)
-  ADD_LIBRARY(vigranumpytest SHARED 
+  ADD_LIBRARY(vigranumpytest SHARED
                vigranumpytest.cxx ${TEST_SUCCESS_FILE} ${TEST_SCRIPTS})
 ELSE()
   ADD_LIBRARY(vigranumpytest SHARED EXCLUDE_FROM_ALL
@@ -49,7 +52,6 @@ ELSE()
     SET_TARGET_PROPERTIES(vigranumpytest PROPERTIES PREFIX "")
 ENDIF()
 
-#TARGET_LINK_LIBRARIES(vigranumpytest ${VIGRANUMPY_LIBRARIES} vigranumpy_core)
 TARGET_LINK_LIBRARIES(vigranumpytest ${VIGRANUMPY_LIBRARIES})
 ADD_DEPENDENCIES(check_python vigranumpytest)
 ADD_DEPENDENCIES(ctest vigranumpytest)
@@ -57,16 +59,32 @@ ADD_DEPENDENCIES(vigranumpytest vigranumpy)
 
 # setup the file 'set_path.py' to ensure that tests are run against the binaries
 # which are currently being built, not against (possibly outdated) installed modules
-DEPENDENCY_PATH(VIGRAIMPEX_PATH vigraimpex)
-DEPENDENCY_PATH(VIGRANUMPYTEST_PATH vigranumpytest)
-
 STRING(REGEX REPLACE "/vigra$" "" VIGRANUMPY_TMP_PATH ${vigranumpy_tmp_dir})
 FILE(TO_NATIVE_PATH "${VIGRANUMPY_TMP_PATH}" VIGRANUMPY_TMP_PATH)
 
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/set_paths.py.in
-                ${CMAKE_CURRENT_BINARY_DIR}/set_paths.py 
-                @ONLY)
-
+if(CMAKE_MAJOR_VERSION LESS 3)
+    DEPENDENCY_PATH(VIGRAIMPEX_PATH vigraimpex)
+    DEPENDENCY_PATH(VIGRANUMPYTEST_PATH vigranumpytest)
+
+    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/set_paths.py.cmake2.in
+                   ${CMAKE_CURRENT_BINARY_DIR}/set_paths.py
+                   @ONLY)
+else()
+    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/set_paths.py.in
+                   ${CMAKE_CURRENT_BINARY_DIR}/set_paths.py.in
+                   @ONLY)
+
+    # two-stage file configuration is necessary because certain target
+    # properties are only known at generation time (policy CMP0026)
+    if(MSVC)
+        file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/set_paths.py
+                      INPUT  ${CMAKE_CURRENT_BINARY_DIR}/set_paths.py.in
+                      CONDITION $<CONFIG:Release>)
+    else()
+        file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/set_paths.py
+                      INPUT  ${CMAKE_CURRENT_BINARY_DIR}/set_paths.py.in)
+    endif()
+endif()
 
 IF(NOT PYTHON_NOSETESTS_NOT_FOUND)
     # copy the individual test scripts
@@ -81,43 +99,52 @@ IF(NOT PYTHON_NOSETESTS_NOT_FOUND)
     ENDFOREACH(test_script)
 
     VIGRA_NATIVE_PATH(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE})
-    
+
     # Windows: Set the DLL path to the binaries currently being built
     #          (so that binaries which are already installed are ignored)
     #          This is not necessary on Linux, because the correct path
     #          is hard-coded into the module by means of 'rpath'
-    set(VIGRA_PATH "")
-    if(WIN32)
-        IF(CYGWIN)
-            SET(PATHSEP ":")
-        ELSE()
-            SET(PATHSEP ";")
-        ENDIF()
-        FOREACH(lib ${LIBRARIES})
+    cmake_policy(PUSH)
+    if(POLICY CMP0026)
+        # allow 'GET_TARGET_PROPERTY(... LOCATION)'
+        cmake_policy(SET CMP0026 OLD)
+    endif()
+    set(EXTRA_PATH "")
+    IF(MSVC)
+        SET(PATHSEP ";")
+    ELSE()
+        SET(PATHSEP ":")
+    ENDIF()
+    FOREACH(lib ${LIBRARIES})
+        if(TARGET ${lib})
             GET_TARGET_PROPERTY(p ${lib} LOCATION)
             if(p)
                 GET_FILENAME_COMPONENT(p ${p} PATH)
                 VIGRA_NATIVE_PATH(p ${p})
-                SET(VIGRA_PATH  "${p}${PATHSEP}${VIGRA_PATH}")
-           endif()
-        ENDFOREACH(lib)
-    endif()
-    
+                SET(EXTRA_PATH  "${p}${PATHSEP}${EXTRA_PATH}")
+            endif()
+        endif()
+    ENDFOREACH(lib)
+    cmake_policy(POP)
+
     # Setup the test execution script
     VIGRA_NATIVE_PATH(VIGRA_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
-    SET(VIGRA_TEST_EXECUTABLE "${PYTHON_EXECUTABLE} -c \"import nose; nose.main()\" .")        
     IF(MSVC OR MINGW)
-        SET(VIGRA_TEST_EXECUTABLE "${VIGRA_TEST_EXECUTABLE} %CONFIGURATION%")
-        SET(VIGRA_RUN_TEST "${CMAKE_CURRENT_BINARY_DIR}/run_vigranumpytest.bat")
+        get_filename_component(PYTHON_PATH ${PYTHON_EXECUTABLE} PATH)
+        get_filename_component(PYTHON_EXE  ${PYTHON_EXECUTABLE} NAME)
+        SET(EXTRA_PATH  "${PYTHON_PATH}${PATHSEP}${EXTRA_PATH}")
+        SET(VIGRA_TEST_EXECUTABLE "${PYTHON_EXE} -c \"import nose; nose.main()\" . %CONFIGURATION%")
+        SET(VIGRA_TEST_SCRIPT     "${CMAKE_CURRENT_BINARY_DIR}/run_vigranumpytest.bat")
         CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config/run_test.bat.in
-                        ${VIGRA_RUN_TEST}
-                        @ONLY)
-    ELSE()            
-        SET(VIGRA_RUN_TEST "${CMAKE_CURRENT_BINARY_DIR}/run_vigranumpytest.sh")
+                       ${VIGRA_TEST_SCRIPT}
+                       @ONLY)
+    ELSE()
+        SET(VIGRA_TEST_EXECUTABLE "${PYTHON_EXECUTABLE} -c \"import nose; nose.main()\" .")
+        SET(VIGRA_TEST_SCRIPT     "${CMAKE_CURRENT_BINARY_DIR}/run_vigranumpytest.sh")
         CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config/run_test.sh.in
-                        ${VIGRA_RUN_TEST}
+                       ${VIGRA_TEST_SCRIPT}
                        @ONLY)
-        EXECUTE_PROCESS(COMMAND chmod u+x ${VIGRA_RUN_TEST} OUTPUT_QUIET ERROR_QUIET)
+        EXECUTE_PROCESS(COMMAND chmod u+x ${VIGRA_TEST_SCRIPT} OUTPUT_QUIET ERROR_QUIET)
     ENDIF()
 
     # register the test execution command
@@ -135,12 +162,21 @@ IF(NOT PYTHON_NOSETESTS_NOT_FOUND)
         add_custom_command(
             TARGET vigranumpytest
             POST_BUILD
-            COMMAND ${VIGRA_RUN_TEST} ARGS ${VIGRA_CONFIGURATION}
+            COMMAND ${VIGRA_TEST_SCRIPT} ARGS ${VIGRA_CONFIGURATION}
             COMMENT "Running vigranumpy tests")
     ENDIF()
 
-    ADD_TEST(vigranumpytest ${VIGRA_RUN_TEST} ${VIGRA_CONFIGURATION})
+    ADD_TEST(vigranumpytest ${VIGRA_TEST_SCRIPT} ${VIGRA_CONFIGURATION})
 
+    # if we configure for Visual Studio, setup the debug command
+    if(MSVC AND NOT (MSVC_VERSION VERSION_LESS "11"))
+        # FIXME: this may not portable between VC versions (works for 11.0 - 14.0)
+        set(VIGRA_TEST_EXE "${PYTHON_EXECUTABLE}")
+        set(VIGRA_TEST_ARGS "-c \"import nose; nose.main()\" . \$(Configuration)")
+        configure_file(${CMAKE_SOURCE_DIR}/config/testdebug.vcxproj.user.in
+                       ${CMAKE_CURRENT_BINARY_DIR}/vigranumpytest.vcxproj.user
+                       @ONLY)
+    endif()
 ELSE()
         MESSAGE(STATUS "  vigranumpy tests will NOT be executed (nosetests missing)")
 ENDIF()
diff --git a/vigranumpy/test/set_paths.py.cmake2.in b/vigranumpy/test/set_paths.py.cmake2.in
new file mode 100644
index 0000000..1a4c67d
--- /dev/null
+++ b/vigranumpy/test/set_paths.py.cmake2.in
@@ -0,0 +1,45 @@
+#######################################################################
+#
+#         Copyright 2009-2010 by Ullrich Koethe
+#
+#    This file is part of the VIGRA computer vision library.
+#    The VIGRA Website is
+#        http://hci.iwr.uni-heidelberg.de/vigra/
+#    Please direct questions, bug reports, and contributions to
+#        ullrich.koethe at iwr.uni-heidelberg.de    or
+#        vigra at informatik.uni-hamburg.de
+#
+#    Permission is hereby granted, free of charge, to any person
+#    obtaining a copy of this software and associated documentation
+#    files (the "Software"), to deal in the Software without
+#    restriction, including without limitation the rights to use,
+#    copy, modify, merge, publish, distribute, sublicense, and/or
+#    sell copies of the Software, and to permit persons to whom the
+#    Software is furnished to do so, subject to the following
+#    conditions:
+#
+#    The above copyright notice and this permission notice shall be
+#    included in all copies or substantial portions of the
+#    Software.
+#
+#    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 AND
+#    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#    OTHER DEALINGS IN THE SOFTWARE.
+#
+#######################################################################
+
+import sys, os
+
+if len(sys.argv) == 3:
+    outdir = os.sep + sys.argv[-1]
+else:
+    outdir = ''
+
+os.environ['PATH'] = os.pathsep.join([r'@VIGRAIMPEX_PATH@%s' % outdir, os.environ['PATH']])
+sys.path.insert(0, r'@VIGRANUMPY_TMP_PATH@')
+sys.path.insert(0, r'@VIGRANUMPYTEST_PATH@%s' % outdir)
diff --git a/vigranumpy/test/set_paths.py.in b/vigranumpy/test/set_paths.py.in
index 8798274..b157d9f 100644
--- a/vigranumpy/test/set_paths.py.in
+++ b/vigranumpy/test/set_paths.py.in
@@ -1,45 +1,48 @@
 #######################################################################
-#                                                                      
-#         Copyright 2009-2010 by Ullrich Koethe                        
-#                                                                      
-#    This file is part of the VIGRA computer vision library.           
-#    The VIGRA Website is                                              
-#        http://hci.iwr.uni-heidelberg.de/vigra/                       
-#    Please direct questions, bug reports, and contributions to        
-#        ullrich.koethe at iwr.uni-heidelberg.de    or                    
-#        vigra at informatik.uni-hamburg.de                               
-#                                                                      
-#    Permission is hereby granted, free of charge, to any person       
-#    obtaining a copy of this software and associated documentation    
-#    files (the "Software"), to deal in the Software without           
-#    restriction, including without limitation the rights to use,      
-#    copy, modify, merge, publish, distribute, sublicense, and/or      
-#    sell copies of the Software, and to permit persons to whom the    
-#    Software is furnished to do so, subject to the following          
-#    conditions:                                                       
-#                                                                      
-#    The above copyright notice and this permission notice shall be    
-#    included in all copies or substantial portions of the             
-#    Software.                                                         
-#                                                                      
-#    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 AND          
-#    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       
-#    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      
-#    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      
-#    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     
-#    OTHER DEALINGS IN THE SOFTWARE.                                   
-#                                                                      
+#
+#         Copyright 2009-2010 by Ullrich Koethe
+#
+#    This file is part of the VIGRA computer vision library.
+#    The VIGRA Website is
+#        http://hci.iwr.uni-heidelberg.de/vigra/
+#    Please direct questions, bug reports, and contributions to
+#        ullrich.koethe at iwr.uni-heidelberg.de    or
+#        vigra at informatik.uni-hamburg.de
+#
+#    Permission is hereby granted, free of charge, to any person
+#    obtaining a copy of this software and associated documentation
+#    files (the "Software"), to deal in the Software without
+#    restriction, including without limitation the rights to use,
+#    copy, modify, merge, publish, distribute, sublicense, and/or
+#    sell copies of the Software, and to permit persons to whom the
+#    Software is furnished to do so, subject to the following
+#    conditions:
+#
+#    The above copyright notice and this permission notice shall be
+#    included in all copies or substantial portions of the
+#    Software.
+#
+#    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 AND
+#    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#    OTHER DEALINGS IN THE SOFTWARE.
+#
 #######################################################################
 
-import sys, os
+import sys, os, re
 
 if len(sys.argv) == 3:
-    outdir = os.sep + sys.argv[-1]
+    outdir = '/' + sys.argv[-1]
 else:
     outdir = ''
 
-os.environ['PATH'] = os.pathsep.join([r'@VIGRAIMPEX_PATH@%s' % outdir, os.environ['PATH']])
+vigraimpex_dir = re.sub('/Release$', outdir, r'$<TARGET_FILE_DIR:vigraimpex>')
+vigranumpytest_dir = re.sub('/Release$', outdir, r'$<TARGET_FILE_DIR:vigranumpytest>')
+
+os.environ['PATH'] = os.pathsep.join([vigraimpex_dir.replace('/', os.sep), os.environ['PATH']])
 sys.path.insert(0, r'@VIGRANUMPY_TMP_PATH@')
-sys.path.insert(0, r'@VIGRANUMPYTEST_PATH@%s' % outdir)
+sys.path.insert(0, vigranumpytest_dir.replace('/', os.sep))
diff --git a/vigranumpy/test/test4.py b/vigranumpy/test/test4.py
new file mode 100644
index 0000000..c0bb2f0
--- /dev/null
+++ b/vigranumpy/test/test4.py
@@ -0,0 +1,287 @@
+#######################################################################
+#                                                                      
+#         Copyright 2009-2010 by Ullrich Koethe                        
+#                                                                      
+#    This file is part of the VIGRA computer vision library.           
+#    The VIGRA Website is                                              
+#        http://hci.iwr.uni-heidelberg.de/vigra/                       
+#    Please direct questions, bug reports, and contributions to        
+#        ullrich.koethe at iwr.uni-heidelberg.de    or                    
+#        vigra at informatik.uni-hamburg.de                               
+#                                                                      
+#    Permission is hereby granted, free of charge, to any person       
+#    obtaining a copy of this software and associated documentation    
+#    files (the "Software"), to deal in the Software without           
+#    restriction, including without limitation the rights to use,      
+#    copy, modify, merge, publish, distribute, sublicense, and/or      
+#    sell copies of the Software, and to permit persons to whom the    
+#    Software is furnished to do so, subject to the following          
+#    conditions:                                                       
+#                                                                      
+#    The above copyright notice and this permission notice shall be    
+#    included in all copies or substantial portions of the             
+#    Software.                                                         
+#                                                                      
+#    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 AND          
+#    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       
+#    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      
+#    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      
+#    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     
+#    OTHER DEALINGS IN THE SOFTWARE.                                   
+#                                                                      
+#######################################################################
+
+import sys
+print >> sys.stderr, "\nexecuting test file", __file__
+execfile('set_paths.py')
+
+
+from nose.tools import assert_equal, raises
+from vigra import numpy as np
+from vigra import numpy as numpy
+from vigra import graphs as vigraph
+from vigra import graphs,taggedView
+import vigra
+
+def testGridGraphSegmentationFelzenszwalbSegmentation():
+    dataRGB  = numpy.random.random([3,3,3]).astype(numpy.float32)
+    dataRGB  = taggedView(dataRGB,'xyc')
+    data  = numpy.random.random([3,3]).astype(numpy.float32)
+    edata = numpy.random.random([3*2-1,3*2-1]).astype(numpy.float32)
+    g0 = graphs.gridGraph(data.shape)
+
+    ew = graphs.edgeFeaturesFromInterpolatedImage(g0,edata)
+
+    labels = graphs.felzenszwalbSegmentation(graph=g0,edgeWeights=ew,k=1.0,nodeNumStop=5)
+
+    g1  = graphs.regionAdjacencyGraph(graph=g0,labels=labels)
+    assert g1.nodeNum == 5
+
+
+    
+    data  = numpy.random.random([3,3,3]).astype(numpy.float32)
+    edata = numpy.random.random([3*2-1,3*2-1,3*2-1]).astype(numpy.float32)
+    g0 = graphs.gridGraph(data.shape)
+
+    ew = graphs.edgeFeaturesFromInterpolatedImage(g0,edata)
+
+    labels = graphs.felzenszwalbSegmentation(graph=g0,edgeWeights=ew,k=1.0,nodeNumStop=15)
+
+    g1  = graphs.regionAdjacencyGraph(graph=g0,labels=labels)
+    assert g1.nodeNum == 15
+
+def testGridGraphWatersheds():
+
+    data  = numpy.random.random([10,10,10]).astype(numpy.float32)
+    edata = numpy.random.random([10*2-1,10*2-1,10*2-1]).astype(numpy.float32)
+    g0 = graphs.gridGraph(data.shape)
+
+
+    ew = graphs.edgeFeaturesFromInterpolatedImage(graph=g0,image=edata)
+
+    # generate seeds
+    seeds = graphs.nodeWeightedWatershedsSeeds(graph=g0,nodeWeights=data)
+    # node weighted watershed seeds
+    labelsNodeWeightedA  = graphs.nodeWeightedWatersheds(graph=g0,nodeWeights=data,seeds=seeds)
+    # node weighted watershed seeds
+    labelsNodeWeightedB  = graphs.nodeWeightedWatersheds(graph=g0,nodeWeights=data)
+    # edge weighted watershed seeds
+    seeds = graphs.nodeWeightedWatershedsSeeds(graph=g0,nodeWeights=data)
+    labelsEdgeWeighted  = graphs.edgeWeightedWatersheds(graph=g0,edgeWeights=ew,seeds=seeds)
+
+    assert numpy.array_equal(labelsNodeWeightedA,labelsNodeWeightedB)
+
+    data  = numpy.random.random([10,10]).astype(numpy.float32)
+    edata = numpy.random.random([10*2-1,10*2-1]).astype(numpy.float32)
+    g0 = graphs.gridGraph(data.shape)
+
+
+    ew = graphs.edgeFeaturesFromInterpolatedImage(graph=g0,image=edata)
+
+    # generate seeds
+    seeds = graphs.nodeWeightedWatershedsSeeds(graph=g0,nodeWeights=data)
+    # node weighted watershed seeds
+    labelsNodeWeightedA  = graphs.nodeWeightedWatersheds(graph=g0,nodeWeights=data,seeds=seeds)
+    # node weighted watershed seeds
+    labelsNodeWeightedB  = graphs.nodeWeightedWatersheds(graph=g0,nodeWeights=data)
+    # edge weighted watershed seeds
+    labelsEdgeWeighted  = graphs.edgeWeightedWatersheds(graph=g0,edgeWeights=ew,seeds=seeds)
+
+    assert numpy.array_equal(labelsNodeWeightedA,labelsNodeWeightedB)
+
+
+def testGridGraphAgglomerativeClustering():
+    dataRGB  = numpy.random.random([10,10,3]).astype(numpy.float32)
+    dataRGB  = vigra.taggedView(dataRGB,'xyc')
+    data  = numpy.random.random([10,10]).astype(numpy.float32)
+    edata = numpy.random.random([10*2-1,10*2-1]).astype(numpy.float32)
+    g0 = graphs.gridGraph(data.shape)
+
+
+    ew = graphs.edgeFeaturesFromInterpolatedImage(graph=g0,image=edata)
+    #ew = taggedView(ew,'xyz')
+
+    
+    labels = graphs.agglomerativeClustering(graph=g0,edgeWeights=ew,nodeFeatures=dataRGB,nodeNumStop=5)
+    g1  = graphs.regionAdjacencyGraph(graph=g0,labels=labels)
+    assert g1.nodeNum == 5
+    
+    labels = graphs.agglomerativeClustering(graph=g0,edgeWeights=ew,nodeNumStop=5)
+    g1  = graphs.regionAdjacencyGraph(graph=g0,labels=labels)
+    assert g1.nodeNum == 5
+
+
+
+    dataRGB  = numpy.random.random([10,10,10,3]).astype(numpy.float32)
+    dataRGB  = vigra.taggedView(dataRGB,'xyzc')
+    data  = numpy.random.random([10,10,10]).astype(numpy.float32)
+    edata = numpy.random.random([10*2-1,10*2-1,10*2-1]).astype(numpy.float32)
+    g0 = graphs.gridGraph(data.shape)
+
+
+    ew = graphs.edgeFeaturesFromInterpolatedImage(graph=g0,image=edata)
+    #ew = taggedView(ew,'xyz')
+
+    
+    labels = graphs.agglomerativeClustering(graph=g0,edgeWeights=ew,nodeFeatures=dataRGB,nodeNumStop=5)
+    g1  = graphs.regionAdjacencyGraph(graph=g0,labels=labels)
+    assert g1.nodeNum == 5
+    
+    labels = graphs.agglomerativeClustering(graph=g0,edgeWeights=ew,nodeNumStop=5)
+    g1  = graphs.regionAdjacencyGraph(graph=g0,labels=labels)
+    assert g1.nodeNum == 5
+
+class TestGraph(object):
+
+    def testAddNodesWithIds(self):
+
+        IV = vigraph.INVALID
+
+        g  = vigraph.listGraph()
+        assert g.nodeNum == 0
+        assert g.edgeNum == 0
+        assert g.nodeFromId(0)==IV
+        assert g.nodeFromId(1)==IV
+        assert g.nodeFromId(2)==IV
+        assert g.nodeFromId(3)==IV
+        assert g.nodeFromId(4)==IV
+        assert g.nodeFromId(5)==IV
+        assert g.nodeFromId(6)==IV
+        assert g.nodeFromId(7)==IV
+
+        n5 =g.addNode(5)
+
+        assert g.id(n5)==5
+
+        assert n5!=IV
+        assert g.nodeNum == 1
+        assert g.edgeNum == 0
+        assert g.nodeFromId(0)==IV
+        assert g.nodeFromId(1)==IV
+        assert g.nodeFromId(2)==IV
+        assert g.nodeFromId(3)==IV
+        assert g.nodeFromId(4)==IV
+        assert g.nodeFromId(5)!=IV
+        assert g.nodeFromId(6)==IV
+        assert g.nodeFromId(7)==IV
+
+        n2=g.addNode(2)
+        assert n2!=IV
+        assert g.nodeNum == 2
+        assert g.nodeFromId(0)==IV
+        assert g.nodeFromId(1)==IV
+        assert g.nodeFromId(2)!=IV
+        assert g.nodeFromId(3)==IV
+        assert g.nodeFromId(4)==IV
+        assert g.nodeFromId(5)!=IV
+        assert g.nodeFromId(6)==IV
+        assert g.nodeFromId(7)==IV
+
+        n6=g.addNode(6)
+        assert n6!=IV
+        assert g.nodeNum == 3
+        assert g.nodeFromId(0)==IV
+        assert g.nodeFromId(1)==IV
+        assert g.nodeFromId(2)!=IV
+        assert g.nodeFromId(3)==IV
+        assert g.nodeFromId(4)==IV
+        assert g.nodeFromId(5)!=IV
+        assert g.nodeFromId(6)!=IV
+        assert g.nodeFromId(7)==IV
+
+        n6=g.addNode(5)
+        n2=g.addNode(2)
+        n6=g.addNode(6)
+        assert g.nodeNum == 3
+        assert g.nodeFromId(0)==IV
+        assert g.nodeFromId(1)==IV
+        assert g.nodeFromId(2)!=IV
+        assert g.nodeFromId(3)==IV
+        assert g.nodeFromId(4)==IV
+        assert g.nodeFromId(5)!=IV
+        assert g.nodeFromId(6)!=IV
+        assert g.nodeFromId(7)==IV
+
+    def testAddEdges(self):
+        IV = vigraph.INVALID
+        elist = [
+            [1,3],
+            [1,5],
+            [5,7],
+            [3,4]
+        ] 
+
+        edges = np.array(elist,dtype=np.uint32)
+        nodeIds = np.unique(edges.reshape(-1))
+
+
+        g = vigraph.listGraph()
+
+        edgeIds = g.addEdges(edges)
+
+        assert g.edgeNum == len(elist)
+        assert g.edgeNum == len(edgeIds)
+        assert g.nodeNum == len(nodeIds)
+        assert g.maxNodeId == nodeIds.max()
+
+        for ui,vi in elist :
+            assert g.findEdge(ui,vi)!=IV
+            assert g.findEdge(g.nodeFromId(ui),g.nodeFromId(vi))!=IV
+
+        for nId in nodeIds :
+            nId = int(nId)
+            assert g.nodeFromId(nId)!=IV
+
+        for eId in edgeIds :
+            eId = int(eId)
+            assert g.edgeFromId(eId)!=IV
+
+        findEdges = g.findEdges(edges)
+
+        assert np.array_equal(findEdges,edgeIds)
+
+    def testIters(self):
+        g  = vigraph.listGraph()
+        
+        nodes = [n for n in g.nodeIter()]
+        assert len(nodes)==0
+
+        g.addNode(3)
+        nodes = [n for n in g.nodeIter()]
+        assert len(nodes)==1
+        assert g.id(nodes[0]) == 3 
+
+        g.addNode(6)
+        nodes = [n for n in g.nodeIter()]
+        assert len(nodes)==2
+        assert g.id(nodes[0]) == 3 
+        assert g.id(nodes[1]) == 6 
+
+        g.addNode(2)
+        nodes = [n for n in g.nodeIter()]
+        assert len(nodes)==3
+        assert g.id(nodes[0]) == 2 
+        assert g.id(nodes[1]) == 3 
+        assert g.id(nodes[2]) == 6 
\ No newline at end of file
diff --git a/vigranumpy/test/test_arraytypes.py b/vigranumpy/test/test_arraytypes.py
index 4c14036..5974b9d 100644
--- a/vigranumpy/test/test_arraytypes.py
+++ b/vigranumpy/test/test_arraytypes.py
@@ -1,36 +1,36 @@
 #######################################################################
-#                                                                      
-#         Copyright 2009-2010 by Ullrich Koethe                        
-#                                                                      
-#    This file is part of the VIGRA computer vision library.           
-#    The VIGRA Website is                                              
-#        http://hci.iwr.uni-heidelberg.de/vigra/                       
-#    Please direct questions, bug reports, and contributions to        
-#        ullrich.koethe at iwr.uni-heidelberg.de    or                    
-#        vigra at informatik.uni-hamburg.de                               
-#                                                                      
-#    Permission is hereby granted, free of charge, to any person       
-#    obtaining a copy of this software and associated documentation    
-#    files (the "Software"), to deal in the Software without           
-#    restriction, including without limitation the rights to use,      
-#    copy, modify, merge, publish, distribute, sublicense, and/or      
-#    sell copies of the Software, and to permit persons to whom the    
-#    Software is furnished to do so, subject to the following          
-#    conditions:                                                       
-#                                                                      
-#    The above copyright notice and this permission notice shall be    
-#    included in all copies or substantial portions of the             
-#    Software.                                                         
-#                                                                      
-#    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 AND          
-#    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       
-#    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      
-#    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      
-#    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     
-#    OTHER DEALINGS IN THE SOFTWARE.                                   
-#                                                                      
+#
+#         Copyright 2009-2010 by Ullrich Koethe
+#
+#    This file is part of the VIGRA computer vision library.
+#    The VIGRA Website is
+#        http://hci.iwr.uni-heidelberg.de/vigra/
+#    Please direct questions, bug reports, and contributions to
+#        ullrich.koethe at iwr.uni-heidelberg.de    or
+#        vigra at informatik.uni-hamburg.de
+#
+#    Permission is hereby granted, free of charge, to any person
+#    obtaining a copy of this software and associated documentation
+#    files (the "Software"), to deal in the Software without
+#    restriction, including without limitation the rights to use,
+#    copy, modify, merge, publish, distribute, sublicense, and/or
+#    sell copies of the Software, and to permit persons to whom the
+#    Software is furnished to do so, subject to the following
+#    conditions:
+#
+#    The above copyright notice and this permission notice shall be
+#    included in all copies or substantial portions of the
+#    Software.
+#
+#    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 AND
+#    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#    OTHER DEALINGS IN THE SOFTWARE.
+#
 #######################################################################
 
 # run with a simple 'nosetests' in this directory
@@ -55,18 +55,18 @@ try:
     vt.testAny()
 except Exception, e:
     ArgumentError = type(e)
-    
+
 allTests = set()
 for n, f in vt.__dict__.items():
     if n.startswith('test'):
         allTests.add(n)
- 
+
 def checkShape(shape1, shape2):
     assert_equal(shape1, shape2)
 
 def checkStride(stride1, stride2):
     assert_equal(stride1, stride2)
-    
+
 def computeFStrides(shape):
     return tuple(numpy.cumprod((1,)+shape[:-1]))
 
@@ -76,7 +76,7 @@ def computeCStrides(shape):
 def computeVStrides(shape, hasChannelAxis):
     if not hasChannelAxis:
         return computeFStrides(shape)
-    stride = computeFStrides(shape[-1:] + shape[:-1])   
+    stride = computeFStrides(shape[-1:] + shape[:-1])
     return stride[1:] + stride[0:1]
 
 def checkArray(cls, channels, dim, hasChannelAxis=True):
@@ -102,32 +102,32 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
             assert_equal(b.flags.f_contiguous, img.flags.f_contiguous)
             assert (b == img).all()
             assert not numpy.may_share_memory(b, img)
-        
+
         shape = (channels, 5, 10, 20)
         axistags = [AxisInfo.c, AxisInfo.x, AxisInfo.y, AxisInfo.z]
         axistags3 = AxisTags(AxisInfo.y, AxisInfo.z, AxisInfo.x)
         axistags4 = AxisTags(AxisInfo.y, AxisInfo.z, AxisInfo.x, AxisInfo.c)
         axistags5 = AxisTags(AxisInfo.c, AxisInfo.x, AxisInfo.y, AxisInfo.z, AxisInfo.t)
-        
+
         # figure out expected strides and axistags
         s = 0 if hasChannelAxis else 1
         d = dim + 1
         fshape = shape[s:d]
         fstrides = computeFStrides(fshape)
         faxistags = AxisTags(axistags[s:d])
-        
+
         cshape = tuple(reversed(fshape))
         cstrides = computeCStrides(cshape)
         caxistags = AxisTags(list(reversed(faxistags)))
-        
+
         vshape = fshape[1-s:d] + fshape[:1-s]
         vstrides = computeVStrides(vshape, hasChannelAxis)
         vaxistags = AxisTags(axistags[1:d] + axistags[:1-s])
-        
+
         fcstrides = tuple([k*4 for k in cstrides])
         fvstrides = tuple([k*4 for k in vstrides])
         ffstrides = tuple([k*4 for k in fstrides])
-        
+
         value = 1 if channels == 1 else range(1,channels+1)
 
         # test type
@@ -135,8 +135,8 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
 #        assert type(img) is cls
         assert isinstance(img, numpy.ndarray)
         assert_equal(img.dtype, numpy.float32)
-        assert_equal(sys.getrefcount(img), 2)        
-        
+        assert_equal(sys.getrefcount(img), 2)
+
         # test shape
         checkShape(img.shape, vshape)
         assert_equal(img.width, vshape[0])
@@ -145,17 +145,27 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
             assert_equal(img.depth, vshape[2])
         assert_equal(img.channels, channels)
         assert_equal(img.spatialDimensions, dim)
-       
+
         # test strides and order
         checkStride(img.strides, fvstrides)
-        assert_equal(img.order, "V" if hasChannelAxis else "F")
+        if channels > 1:
+            assert_equal(img.order, "V" if hasChannelAxis else "F")
+        else:
+            assert_true(img.order in ['V', 'F'])
         assert_equal(img.flags.c_contiguous, False)
-        assert_equal(img.flags.f_contiguous, False if hasChannelAxis else True)
-        
+
         # test axistags
         assert_equal(img.axistags, vaxistags)
         assert_equal(img.view5D('F').axistags, axistags5)
         assert_equal(img.withAxes('y', 'z', 'x', 'c').axistags, axistags4)
+        assert_equal(img.withAxes('yzxc').axistags, axistags4)
+        assert_equal(img.withAxes(axistags4).axistags, axistags4)
+        assert_true(img.withAxes(img.axistags) is img)
+        array = img.noTags()
+        assert_equal(type(array), numpy.ndarray)
+        assert_equal(arraytypes.taggedView(array, vaxistags).axistags, vaxistags)
+        assert_equal(arraytypes.taggedView(array, vaxistags.keys()).axistags, vaxistags)
+        assert_equal(arraytypes.taggedView(array, ''.join(vaxistags.keys())).axistags, vaxistags)
         if img.channels == 1:
             assert_equal(img.withAxes('y', 'z', 'x').axistags, axistags3)
         else:
@@ -188,7 +198,7 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
         assert_equal(img.shape, (img*2).shape)
         assert_equal(img.strides, (img*2).strides)
         assert_equal(img.axistags, (img*2).axistags)
-        
+
         # test shape, strides, and copy for 'F' order
         img = cls(fshape, order='F')
         assert_equal(sys.getrefcount(img), 2)
@@ -198,7 +208,7 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
         assert_equal(img.order, "F")
         assert_equal(img.flags.c_contiguous, False)
         assert_equal(img.flags.f_contiguous, True)
-        
+
         assert_equal(img.min(), 0.0)
         assert_equal(img.max(), 0.0)
         img = cls(fshape, order="F", value=99.0)
@@ -224,9 +234,11 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
         assert_equal(sys.getrefcount(img), 2)
         checkShape(img.shape, vshape)
         checkStride(img.strides, fvstrides)
-        assert_equal(img.order, "V" if hasChannelAxis else "F")
+        if channels > 1:
+            assert_equal(img.order, "V" if hasChannelAxis else "F")
+        else:
+            assert_true(img.order in ['V', 'F'])
         assert_equal(img.flags.c_contiguous, False)
-        assert_equal(img.flags.f_contiguous, False if hasChannelAxis else True)
         assert_equal(img.axistags, vaxistags)
         img[1,2] = value
         testCopy(img)
@@ -246,13 +258,13 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
         assert_equal(img.order, "C")
         assert_equal(img.flags.c_contiguous, True)
         assert_equal(img.flags.f_contiguous, False)
-        
+
         assert_equal(img.min(), 0.0)
         assert_equal(img.max(), 0.0)
         img = cls(cshape, order="C", value=99.0)
         assert_equal(img.min(), 99.0)
         assert_equal(img.max(), 99.0)
-        
+
         img[1,2] = value
         testCopy(img)
         assert_equal(img.strides, (-img).strides)
@@ -266,7 +278,7 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
 
         value = 10 if channels == 1 else range(10,channels+10)
         zero = 0 if channels == 1 else (0,)*channels
-        
+
         # test shape, strides, and copy for dtype uint8
         img = cls(vshape, order="V")
         b = cls(img, dtype=numpy.uint8, order='V')
@@ -274,10 +286,12 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
         assert_equal(b.dtype, numpy.uint8)
         checkShape(b.shape, img.shape)
         checkStride(b.strides, computeVStrides(b.shape, hasChannelAxis))
-        assert_equal(img.order, "V" if hasChannelAxis else "F")
+        if channels > 1:
+            assert_equal(img.order, "V" if hasChannelAxis else "F")
+        else:
+            assert_true(img.order in ['V', 'F'])
         assert_equal(b.axistags, img.axistags)
         assert_equal(b.flags.c_contiguous, False)
-        assert_equal(b.flags.f_contiguous, False if hasChannelAxis else True)
         assert (b==img).all()
         b[2,1] = value
         assert (b[2,1]==value).all()
@@ -305,7 +319,7 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
         assert_equal(b.axistags, (-b).axistags)
         assert_equal(b.axistags, (b+b).axistags)
         assert_equal(b.axistags, (b*2).axistags)
-        
+
         img = cls(fshape, order="F")
         b = cls(img, dtype=numpy.uint8, order='F')
         assert_equal(sys.getrefcount(b), 2)
@@ -322,7 +336,7 @@ def checkArray(cls, channels, dim, hasChannelAxis=True):
         assert_equal(b.axistags, (-b).axistags)
         assert_equal(b.axistags, (b+b).axistags)
         assert_equal(b.axistags, (b*2).axistags)
-        
+
         value = 100 if channels == 1 else range(100,channels+100)
 
         # test ndarray view
@@ -349,25 +363,25 @@ def checkCompatibility(obj, compatible):
         try:
             f = getattr(vt, n)
             shape, acopy, default_ordering, same_ordering = f(obj)
-            
-            
+
+
             assert_equal(obj.shape, shape)
-            
+
             assert_equal(obj.__class__, acopy.__class__)
             assert_equal(obj.shape, acopy.shape)
             if hasattr(obj, 'axistags'):
                 assert_equal(obj.axistags, acopy.axistags)
             else:
                 assert(not hasattr(acopy, 'axistags'))
-                
+
             if n != "testAny":
                 assert_equal(obj.shape, same_ordering.shape)
                 assert(obj.view(numpy.ndarray) == same_ordering.view(numpy.ndarray)).all()
-                
+
                 if not hasattr(obj, 'axistags'):
                     assert_equal(numpy.ndarray, same_ordering.__class__)
                     assert(not hasattr(same_ordering, 'axistags'))
-                    
+
                     if n.startswith("testArray"):
                         assert_equal(numpy.ndarray, default_ordering.__class__)
                         assert_equal(obj.shape, default_ordering.shape)
@@ -375,21 +389,20 @@ def checkCompatibility(obj, compatible):
                         assert(not hasattr(default_ordering, 'axistags'))
                     else:
                         assert_equal(arraytypes.VigraArray, default_ordering.__class__)
-                        assert_equal(arraytypes.VigraArray.defaultOrder, default_ordering.order)
-                        assert_equal(default_ordering.axistags, 
+                        assert_equal(default_ordering.axistags,
                                      arraytypes.VigraArray.defaultAxistags(default_ordering.ndim))
-                        
+
                         if obj.ndim == default_ordering.ndim:
                             assert_equal(obj.shape, default_ordering.shape)
                             assert(obj.view(numpy.ndarray) == default_ordering.view(numpy.ndarray)).all()
                         else:
                             assert_equal(obj.shape + (1,), default_ordering.shape)
                             assert(obj.view(numpy.ndarray) == default_ordering[...,0].view(numpy.ndarray)).all()
-                     
+
                 else:
                     assert_equal(arraytypes.VigraArray, same_ordering.__class__)
                     assert_equal(obj.axistags, same_ordering.axistags)
-                    
+
                     if n.startswith("testArray"):
                         assert_equal(numpy.ndarray, default_ordering.__class__)
                         fobj = obj.transposeToNormalOrder()
@@ -399,10 +412,9 @@ def checkCompatibility(obj, compatible):
                         assert(not hasattr(default_ordering, 'axistags'))
                     else:
                         assert_equal(arraytypes.VigraArray, default_ordering.__class__)
-                        assert_equal(arraytypes.VigraArray.defaultOrder, default_ordering.order)
                         dobj = obj.transposeToOrder(arraytypes.VigraArray.defaultOrder)
                         dshape = dobj.shape
-                        assert_equal(default_ordering.axistags, 
+                        assert_equal(default_ordering.axistags,
                                      arraytypes.VigraArray.defaultAxistags(default_ordering.ndim))
                         if obj.ndim == default_ordering.ndim:
                             assert_equal(dshape, default_ordering.shape)
@@ -411,26 +423,26 @@ def checkCompatibility(obj, compatible):
                             assert_equal(dshape + (1,), default_ordering.shape)
                             assert(fobj.view(numpy.ndarray) == default_ordering[...,0].view(numpy.ndarray)).all()
         except Exception:
-            print "exception in %s with shape %s strides %s tags (%s)" % (n, obj.shape, obj.strides, 
+            print "exception in %s with shape %s strides %s tags (%s)" % (n, obj.shape, obj.strides,
                                             repr(getattr(obj, "axistags", "none")))
             raise
-        
+
     incompatible = allTests.difference(compatible)
-    
+
     for n in incompatible:
         try:
             checkFailure(obj, n)
         except Exception:
-            print "exception in %s with shape %s strides %s tags (%s)" % (n, obj.shape, obj.strides, 
+            print "exception in %s with shape %s strides %s tags (%s)" % (n, obj.shape, obj.strides,
                                             repr(getattr(obj, "axistags", "none")))
             raise
 
 def testAxisTags():
-    axistags = AxisTags(AxisInfo.c(description="RGB"), 
-                        AxisInfo.ft(3.0, "time frequency"), 
-                        AxisInfo.y(0.5), 
+    axistags = AxisTags(AxisInfo.c(description="RGB"),
+                        AxisInfo.ft(3.0, "time frequency"),
+                        AxisInfo.y(0.5),
                         AxisInfo.z(4, "confocal depth"))
-    
+
     json = '''{
   "axes": [
     {
@@ -460,7 +472,7 @@ def testAxisTags():
   ]
 }'''
     assert_equal(axistags.toJSON(), json)
-    
+
     readBack = AxisTags.fromJSON(json)
     assert_equal(axistags, readBack)
     assert_equal(readBack[0].description, "RGB")
@@ -471,7 +483,7 @@ def testAxisTags():
     assert_equal(readBack[1].resolution, 3)
     assert_equal(readBack[2].resolution, 0.5)
     assert_equal(readBack[3].resolution, 4)
-    
+
     import pickle
     s = pickle.dumps(axistags)
     unpickled = pickle.loads(s)
@@ -484,7 +496,7 @@ def testAxisTags():
     assert_equal(unpickled[1].resolution, 3)
     assert_equal(unpickled[2].resolution, 0.5)
     assert_equal(unpickled[3].resolution, 4)
-    
+
     # FIXME: add more tests here
     defaultTags = arraytypes.VigraArray.defaultAxistags('cxyt')
     assert_equal(defaultTags.permutationToOrder('A'), (0, 1, 2, 3))
@@ -497,7 +509,7 @@ def testAxisTags():
     assert_equal(defaultTags.permutationFromNormalOrder(), (0, 1, 2, 3))
     assert_equal(defaultTags.permutationFromNumpyOrder(), (3, 2, 1, 0))
     assert_equal(defaultTags.permutationFromVigraOrder(), (3, 0, 1, 2))
-    
+
     defaultTags = arraytypes.AxisTags(4)
     assert_equal(defaultTags.permutationToOrder('A'), (0, 1, 2, 3))
     assert_equal(defaultTags.permutationToOrder('F'), (0, 1, 2, 3))
@@ -517,18 +529,18 @@ def testAxisTags():
         defaultTags = arraytypes.VigraArray.defaultAxistags(3, order=order)
         assert_equal(defaultTags.permutationToOrder(order), (0, 1, 2))
         assert (defaultTags.channelIndex == 0 if order == 'F' else 2)
-        
+
         defaultTags.transpose(defaultTags.permutationToOrder('V'))
         assert_equal(defaultTags.permutationToVigraOrder(), (0, 1, 2))
         assert (defaultTags.channelIndex == 2)
-        
+
         defaultTags = arraytypes.VigraArray.defaultAxistags(3, order=order, noChannels=True)
         assert_equal(defaultTags.permutationToOrder(order), (0, 1, 2))
         assert (defaultTags.channelIndex == 3)
-            
+
 def testImage1():
     checkArray(arraytypes.Image, 1, 2)
-    
+
     shape = (10, 20)
     rshape = (20, 10)
 
@@ -538,11 +550,11 @@ def testImage1():
          "testImageMultibandUnstrided", "testImageMultibandStrided"]
 
     checkCompatibility(arraytypes.Image(rshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.Image(shape, order='V', value=2), c)
 
     checkCompatibility(arraytypes.Image(shape, order='F', value=2), c)
-    
+
     c = ["testAny",
          "testArray2Strided",
          "testImageSinglebandStrided",
@@ -555,33 +567,33 @@ def testImage1():
     img = arraytypes.Image(rshape, order='C').dropChannelAxis()
     checkShape(vt.viewArray2Unstrided(img), shape)
     assert_equal(img[0,0], 1)
-    
+
     img = arraytypes.Image(shape, order='V').dropChannelAxis()
     checkShape(vt.viewArray2Unstrided(img), shape)
     assert_equal(img[0,0], 1)
-    
+
     img = arraytypes.Image(shape, order='F').dropChannelAxis()
     checkShape(vt.viewArray2Unstrided(img), shape)
     assert_equal(img[0,0], 1)
- 
+
 def testImage2():
     checkArray(arraytypes.Image, 2, 2)
-    
+
     shape = (10, 20, 2)
     cshape = (20, 10, 2)
     fshape = (2, 10, 20)
-    
+
     c = ["testAny",
          "testArray3Unstrided", "testArray3Strided",
          "testImageVector2Unstrided", "testImageVector2Strided",
          "testImageMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.Image(cshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.Image(shape, order='V', value=2), c)
-    
+
     checkCompatibility(arraytypes.Image(fshape, order='F', value=2), c)
-    
+
     c = ["testAny",
          "testArray3Strided",
          "testImageMultibandStrided",
@@ -596,26 +608,26 @@ def testImage2():
     img = arraytypes.Image(cshape, order='C')
     assert_equal(vt.viewArray3Unstrided(img), fshape)
     assert (img[0,0]==(1,0)).all()
-    
+
     img = arraytypes.Image(shape, order='V')
     assert_equal(vt.viewArray3Unstrided(img), fshape)
     assert (img[0,0]==(1,0)).all()
-    
+
     img = arraytypes.Image(fshape, order='F')
     assert_equal(vt.viewArray3Strided(img), fshape)
     assert (img[:,0,0]==(1,0)).all()
-    
+
     img = arraytypes.Image(cshape, order='C')
     assert_equal(vt.viewImageVector2Strided(img), shape[:-1])
     assert (img[0,0]==(1,1)).all()
-    
+
     img = arraytypes.Image(shape, order='V')
     assert_equal(vt.viewImageVector2Unstrided(img), shape[:-1])
     assert (img[0,0]==(1,1)).all()
- 
+
 def testScalarImage():
     checkArray(arraytypes.ScalarImage, 1, 2, False)
-    
+
     shape = (10, 20)
     cshape = (20, 10)
 
@@ -623,35 +635,35 @@ def testScalarImage():
          "testArray2Unstrided", "testArray2Strided",
          "testImageSinglebandUnstrided", "testImageSinglebandStrided",
          "testImageMultibandUnstrided", "testImageMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.ScalarImage(cshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.ScalarImage(shape, order='V', value=2), c)
-    
+
     checkCompatibility(arraytypes.ScalarImage(shape, order='F', value=2), c)
-    
+
     c = ["testAny",
          "testArray2Strided",
          "testImageSinglebandStrided",
          "testImageMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.ScalarImage(cshape, order='C', value=2).view(numpy.ndarray), c)
 
     img = arraytypes.ScalarImage(cshape, order='C')
     checkShape(vt.viewArray2Unstrided(img), shape)
     assert_equal(img[0,0], 1)
-    
+
     img = arraytypes.ScalarImage(shape, order='V')
     checkShape(vt.viewArray2Unstrided(img), shape)
     assert_equal(img[0,0], 1)
-    
+
     img = arraytypes.ScalarImage(shape, order='F')
     checkShape(vt.viewArray2Strided(img), shape)
     assert_equal(img[0,0], 1)
- 
+
 def testRGBImage():
     checkArray(arraytypes.RGBImage, 3, 2)
-    
+
     cshape = (20, 10)
     shape = (10, 20)
     rshape = (3, 10, 20)
@@ -660,13 +672,13 @@ def testRGBImage():
          "testArray3Unstrided", "testArray3Strided",
          "testImageRGBUnstrided", "testImageRGBStrided",
          "testImageMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.RGBImage(cshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.RGBImage(shape, order='V', value=2), c)
 
     checkCompatibility(arraytypes.RGBImage(shape, order='F', value=2), c)
-    
+
     c = ["testAny",
          "testArray3Strided",
          "testImageMultibandStrided",
@@ -679,26 +691,26 @@ def testRGBImage():
     img = arraytypes.RGBImage(cshape, order='C')
     assert_equal(vt.viewArray3Unstrided(img), rshape)
     assert (img[0,0]==(1,0,0)).all()
-    
+
     img = arraytypes.RGBImage(shape, order='V')
     assert_equal(vt.viewArray3Unstrided(img), rshape)
     assert (img[0,0]==(1,0,0)).all()
-    
+
     img = arraytypes.RGBImage(shape, order='F')
     assert_equal(vt.viewArray3Strided(img), rshape)
     assert (img[:,0,0]==(1,0,0)).all()
-    
+
     img = arraytypes.RGBImage(cshape, order='C')
     assert_equal(vt.viewImageRGBUnstrided(img), shape)
     assert (img[0,0]==(1,1,1)).all()
-    
+
     img = arraytypes.RGBImage(shape, order='V')
     assert_equal(vt.viewImageRGBStrided(img), shape)
     assert (img[0,0]==(1,1,1)).all()
- 
+
 def testVector2Image():
     checkArray(arraytypes.Vector2Image, 2, 2)
-    
+
     cshape = (20, 10)
     shape = (10, 20)
     rshape = (2, 10, 20)
@@ -707,18 +719,18 @@ def testVector2Image():
          "testArray3Unstrided", "testArray3Strided",
          "testImageVector2Unstrided", "testImageVector2Strided",
          "testImageMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.Vector2Image(cshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.Vector2Image(shape, order='V', value=2), c)
-    
+
     checkCompatibility(arraytypes.Vector2Image(shape, order='F', value=2), c)
-    
+
     c = ["testAny",
          "testArray3Strided",
          "testImageMultibandStrided",
          "testImageVector2Strided",
-         "testVolumeSinglebandStrided", 
+         "testVolumeSinglebandStrided",
          "testVolumeMultibandStrided"]
 
     checkCompatibility(arraytypes.Vector2Image(cshape, order='C', value=2).view(numpy.ndarray), c)
@@ -726,32 +738,32 @@ def testVector2Image():
     img = arraytypes.Vector2Image(cshape, order='C')
     assert_equal(vt.viewArray3Unstrided(img), rshape)
     assert (img[0,0]==(1,0)).all()
-    
+
     img = arraytypes.Vector2Image(shape, order='V')
     assert_equal(vt.viewArray3Unstrided(img), rshape)
     assert (img[0,0]==(1,0)).all()
-    
+
     img = arraytypes.Vector2Image(shape, order='F')
     assert_equal(vt.viewArray3Strided(img), rshape)
     assert (img[:,0,0]==(1,0)).all()
-    
+
     img = arraytypes.Vector2Image(cshape, order='C')
     assert_equal(vt.viewImageVector2Unstrided(img), shape)
     assert (img[0,0]==(1,1)).all()
-    
+
     img = arraytypes.Vector2Image(shape, order='V')
     assert_equal(vt.viewImageVector2Unstrided(img), shape)
     assert (img[0,0]==(1,1)).all()
- 
+
 def testVector3Image():
     checkArray(arraytypes.Vector3Image, 3, 2)
- 
+
 def testVector4Image():
     checkArray(arraytypes.Vector4Image, 4, 2)
- 
+
 def testVolume1():
     checkArray(arraytypes.Volume, 1, 3)
-    
+
     shape = (5, 10, 20)
     rshape = (20, 10, 5)
 
@@ -759,13 +771,13 @@ def testVolume1():
          "testArray4Unstrided", "testArray4Strided",
          "testVolumeSinglebandUnstrided", "testVolumeSinglebandStrided",
          "testVolumeMultibandUnstrided", "testVolumeMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.Volume(rshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.Volume(shape, order='V', value=2), c)
-    
+
     checkCompatibility(arraytypes.Volume(shape, order='F', value=2), c)
-    
+
     c = ["testAny",
          "testArray3Strided",
          "testImageMultibandStrided",
@@ -779,38 +791,38 @@ def testVolume1():
     vol = arraytypes.Volume(rshape, order='C').dropChannelAxis()
     checkShape(vt.viewArray3Unstrided(vol), shape)
     assert_equal(vol[0,0,0], 1)
-    
+
     vol = arraytypes.Volume(shape, order='V').dropChannelAxis()
     checkShape(vt.viewArray3Unstrided(vol), shape)
     assert_equal(vol[0,0,0], 1)
-    
+
     vol = arraytypes.Volume(shape, order='F').dropChannelAxis()
     checkShape(vt.viewArray3Unstrided(vol), shape)
     assert_equal(vol[0,0,0], 1)
- 
+
 def testVolume2():
     checkArray(arraytypes.Volume, 2, 3)
-    
+
     shape = (5, 10, 20, 2)
     cshape = (20, 10, 5, 2)
     fshape = (2, 5, 10, 20)
-        
+
     c = ["testAny",
          "testArray4Unstrided", "testArray4Strided",
          "testVolumeVector2Unstrided", "testVolumeVector2Strided",
          "testVolumeMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.Volume(cshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.Volume(shape, order='V', value=2), c)
-    
+
     checkCompatibility(arraytypes.Volume(fshape, order='F', value=2), c)
-        
+
     c = ["testAny",
          "testArray4Strided",
          "testVolumeVector2Strided",
          "testVolumeMultibandStrided"]
-         
+
     a = numpy.ndarray(cshape, dtype=numpy.float32)
     a[...] = 2
     checkCompatibility(a, c)
@@ -818,26 +830,26 @@ def testVolume2():
     vol = arraytypes.Volume(cshape, order='C')
     assert_equal(vt.viewArray4Unstrided(vol), fshape)
     assert (vol[0,0,0]==(1,0)).all()
-    
+
     vol = arraytypes.Volume(shape, order='V')
     assert_equal(vt.viewArray4Unstrided(vol), fshape)
     assert (vol[0,0,0]==(1,0)).all()
-    
+
     vol = arraytypes.Volume(fshape, order='F')
     assert_equal(vt.viewArray4Strided(vol), fshape)
     assert (vol[:,0,0,0]==(1,0)).all()
-    
+
     vol = arraytypes.Volume(cshape, order='C')
     assert_equal(vt.viewVolumeVector2Unstrided(vol), shape[:-1])
     assert (vol[0,0,0]==(1,1)).all()
-    
+
     vol = arraytypes.Volume(shape, order='V')
     assert_equal(vt.viewVolumeVector2Unstrided(vol), shape[:-1])
     assert (vol[0,0,0]==(1,1)).all()
- 
+
 def testScalarVolume():
     checkArray(arraytypes.ScalarVolume, 1, 3, False)
-    
+
     cshape = (20, 10, 5)
     shape = (5, 10, 20)
 
@@ -845,36 +857,36 @@ def testScalarVolume():
          "testArray3Unstrided", "testArray3Strided",
          "testVolumeSinglebandUnstrided", "testVolumeSinglebandStrided",
          "testVolumeMultibandUnstrided", "testVolumeMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.ScalarVolume(cshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.ScalarVolume(shape, order='V', value=2), c)
-    
+
     checkCompatibility(arraytypes.ScalarVolume(shape, order='F', value=2), c)
-    
+
     c = ["testAny",
          "testArray3Strided",
          "testImageMultibandStrided",
          "testVolumeSinglebandStrided",
          "testVolumeMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.ScalarVolume(cshape, order='C', value=2).view(numpy.ndarray), c)
 
     vol = arraytypes.ScalarVolume(cshape, order='C')
     checkShape(vt.viewArray3Unstrided(vol), shape)
     assert_equal(vol[0,0,0], 1)
-    
+
     vol = arraytypes.ScalarVolume(shape, order='V')
     checkShape(vt.viewArray3Unstrided(vol), shape)
     assert_equal(vol[0,0,0], 1)
- 
+
     vol = arraytypes.ScalarVolume(shape, order='F')
     checkShape(vt.viewArray3Strided(vol), shape)
     assert_equal(vol[0,0,0], 1)
 
 def testRGBVolume():
     checkArray(arraytypes.RGBVolume, 3, 3)
-    
+
     cshape = (20, 10, 5)
     shape = (5, 10, 20)
     rshape = (3, 5, 10, 20)
@@ -883,43 +895,43 @@ def testRGBVolume():
          "testArray4Unstrided", "testArray4Strided",
          "testVolumeRGBUnstrided", "testVolumeRGBStrided",
          "testVolumeMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.RGBVolume(cshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.RGBVolume(shape, order='V', value=2), c)
-    
+
     checkCompatibility(arraytypes.RGBVolume(shape, order='F', value=2), c)
-    
+
     c = ["testAny",
          "testArray4Strided",
          "testVolumeRGBStrided",
          "testVolumeMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.RGBVolume(cshape, order='C', value=2).view(numpy.ndarray), c)
-    
+
     vol = arraytypes.RGBVolume(cshape, order='C')
     checkShape(vt.viewArray4Unstrided(vol), rshape)
     assert (vol[0,0,0]==(1,0,0)).all()
-    
+
     vol = arraytypes.RGBVolume(shape, order='V')
     checkShape(vt.viewArray4Unstrided(vol), rshape)
     assert (vol[0,0,0]==(1,0,0)).all()
-    
+
     vol = arraytypes.RGBVolume(shape, order='F')
     checkShape(vt.viewArray4Strided(vol), rshape)
     assert (vol[:,0,0,0]==(1,0,0)).all()
-    
+
     vol = arraytypes.RGBVolume(cshape, order='C')
     checkShape(vt.viewVolumeRGBUnstrided(vol), shape)
     assert (vol[0,0,0]==(1,1,1)).all()
-    
+
     vol = arraytypes.RGBVolume(shape, order='V')
     checkShape(vt.viewVolumeRGBUnstrided(vol), shape)
     assert (vol[0,0,0]==(1,1,1)).all()
- 
+
 def testVector2Volume():
     checkArray(arraytypes.Vector2Volume, 2, 3)
-    
+
     cshape = (20, 10, 5)
     shape = (5, 10, 20)
     rshape = (2, 5, 10, 20)
@@ -928,98 +940,145 @@ def testVector2Volume():
          "testArray4Unstrided", "testArray4Strided",
          "testVolumeVector2Unstrided", "testVolumeVector2Strided",
          "testVolumeMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.Vector2Volume(cshape, order='C', value=2), c)
-    
+
     checkCompatibility(arraytypes.Vector2Volume(shape, order='V', value=2), c)
-    
+
     checkCompatibility(arraytypes.Vector2Volume(shape, order='F', value=2), c)
-    
+
     c = ["testAny",
          "testArray4Strided",
          "testVolumeVector2Strided",
          "testVolumeMultibandStrided"]
-         
+
     checkCompatibility(arraytypes.Vector2Volume(cshape, order='C', value=2).view(numpy.ndarray), c)
-    
+
     vol = arraytypes.Vector2Volume(cshape, order='C')
     checkShape(vt.viewArray4Unstrided(vol), rshape)
     assert (vol[0,0,0]==(1,0)).all()
-    
+
     vol = arraytypes.Vector2Volume(shape, order='V')
     checkShape(vt.viewArray4Unstrided(vol), rshape)
     assert (vol[0,0,0]==(1,0)).all()
-    
+
     vol = arraytypes.Vector2Volume(shape, order='F')
     checkShape(vt.viewArray4Strided(vol), rshape)
     assert (vol[:,0,0,0]==(1,0)).all()
-    
+
     vol = arraytypes.Vector2Volume(cshape, order='C')
     checkShape(vt.viewVolumeVector2Unstrided(vol), shape)
     assert (vol[0,0,0]==(1,1)).all()
-    
+
     vol = arraytypes.Vector2Volume(shape, order='V')
     checkShape(vt.viewVolumeVector2Unstrided(vol), shape)
     assert (vol[0,0,0]==(1,1)).all()
- 
+
 def testVector3Volume():
     checkArray(arraytypes.Vector3Volume, 3, 3)
- 
+
 def testVector4Volume():
     checkArray(arraytypes.Vector4Volume, 4, 3)
 
 def testTaggedShape():
+    a = arraytypes.makeAxistags(4)
+    assert_equal(repr(a), 'x y z c')
+    a = arraytypes.makeAxistags(4, order='C')
+    assert_equal(repr(a), 'z y x c')
+    a = arraytypes.makeAxistags(4, order='F')
+    assert_equal(repr(a), 'c x y z')
+    a = arraytypes.makeAxistags(4, order='C', noChannels=True)
+    assert_equal(repr(a), 't z y x')
+    a = arraytypes.makeAxistags(4, noChannels=True)
+    assert_equal(repr(a), 'x y z t')
+
+    aa = arraytypes.makeAxistags('xyc')
+    a = arraytypes.makeAxistags(aa)
+    assert_equal(repr(a), 'x y c')
+    assert(a is not aa)
+    a = arraytypes.makeAxistags(aa, order='C')
+    assert_equal(repr(a), 'y x c')
+    assert(a is not aa)
+    a = arraytypes.makeAxistags(aa, order='F')
+    assert_equal(repr(a), 'c x y')
+    assert(a is not aa)
+
+    a = arraytypes.makeAxistags(aa, noChannels=True)
+    assert_equal(repr(a), 'x y')
+    assert(a is not aa)
+    a = arraytypes.makeAxistags(aa, order='V', noChannels=True)
+    assert_equal(repr(a), 'x y')
+    assert(a is not aa)
+    a = arraytypes.makeAxistags(aa, order='C', noChannels=True)
+    assert_equal(repr(a), 'y x')
+    assert(a is not aa)
+    a = arraytypes.makeAxistags(aa, order='F', noChannels=True)
+    assert_equal(repr(a), 'x y')
+    assert(a is not aa)
+
+    a = arraytypes.makeAxistags('xyc', order='V')
+    assert_equal(repr(a), 'x y c')
+    a = arraytypes.makeAxistags('xyc', order='C')
+    assert_equal(repr(a), 'y x c')
+    a = arraytypes.makeAxistags('xyc', order='F')
+    assert_equal(repr(a), 'c x y')
+    a = arraytypes.makeAxistags('xyc', order='F', noChannels=True)
+    assert_equal(repr(a), 'x y')
+    a = arraytypes.makeAxistags('xyc', order='V', noChannels=True)
+    assert_equal(repr(a), 'x y')
+    a = arraytypes.makeAxistags('xyc', order='C', noChannels=True)
+    assert_equal(repr(a), 'y x')
 
     a = arraytypes.Image((20,10))
     a.axistags.setChannelDescription("in")
     res = vt.checkTaggedShapeMultiband(a)
-    
+
     assert_equal(res[0].shape, (20,10,1))
     assert_equal(res[0].axistags, a.axistags)
     assert_equal(res[0].axistags[2].description, "in")
-    
+
     assert_equal(res[1].shape, (20,10,1))
     assert_equal(res[1].axistags, a.axistags)
     assert_equal(res[1].axistags[2].description, "res2")
-    
+
     assert_equal(res[2].shape, (20,10,1))
     assert_equal(res[2].axistags, a.axistags)
     assert_equal(res[2].axistags[2].description, "res3")
-    
+
     assert_equal(res[3].shape, (20,10,3))
     assert_equal(res[3].axistags, a.axistags)
     assert_equal(res[3].axistags[2].description, "res4")
-    
+
     assert_equal(res[4].shape, (20,10,1))
     assert_equal(res[4].axistags, a.axistags)
     assert_equal(res[4].axistags[2].description, "res5")
-    
+
     assert_equal(res[5].shape, (20,10,3))
     assert_equal(res[5].axistags, a.axistags)
     assert_equal(res[5].axistags[2].description, "res6")
 
     res = vt.checkTaggedShapeSingleband(a)
-    
+
     assert_equal(res[0].shape, (20,10,1))
     assert_equal(res[0].axistags, a.axistags)
     assert_equal(res[0].axistags[2].description, "in")
-    
+
     assert_equal(res[1].shape, (20,10,1))
     assert_equal(res[1].axistags, a.axistags)
     assert_equal(res[1].axistags[2].description, "res2")
-    
+
     assert_equal(res[2].shape, (20,10,1))
     assert_equal(res[2].axistags, a.axistags)
     assert_equal(res[2].axistags[2].description, "res3")
-    
+
     assert_equal(res[3].shape, (20,10,3))
     assert_equal(res[3].axistags, a.axistags)
     assert_equal(res[3].axistags[2].description, "res4")
-    
+
     assert_equal(res[4].shape, (20,10,1))
     assert_equal(res[4].axistags, a.axistags)
     assert_equal(res[4].axistags[2].description, "res5")
-    
+
     assert_equal(res[5].shape, (20,10,3))
     assert_equal(res[5].axistags, a.axistags)
     assert_equal(res[5].axistags[2].description, "res6")
@@ -1027,27 +1086,27 @@ def testTaggedShape():
     a = arraytypes.Image((20,10,2))
     a.axistags.setChannelDescription("in")
     res = vt.checkTaggedShapeMultiband(a)
-    
+
     assert_equal(res[0].shape, (20,10,2))
     assert_equal(res[0].axistags, a.axistags)
     assert_equal(res[0].axistags[2].description, "in")
-    
+
     assert_equal(res[1].shape, (20,10,2))
     assert_equal(res[1].axistags, a.axistags)
     assert_equal(res[1].axistags[2].description, "res2")
-    
+
     assert_equal(res[2].shape, (20,10,1))
     assert_equal(res[2].axistags, a.axistags)
     assert_equal(res[2].axistags[2].description, "res3")
-    
+
     assert_equal(res[3].shape, (20,10,3))
     assert_equal(res[3].axistags, a.axistags)
     assert_equal(res[3].axistags[2].description, "res4")
-    
+
     assert_equal(res[4].shape, (20,10,1))
     assert_equal(res[4].axistags, a.axistags)
     assert_equal(res[4].axistags[2].description, "res5")
-    
+
     assert_equal(res[5].shape, (20,10,3))
     assert_equal(res[5].axistags, a.axistags)
     assert_equal(res[5].axistags[2].description, "res6")
@@ -1056,69 +1115,126 @@ def testTaggedShape():
     a.axistags.setChannelDescription("in")
     resaxistags = copy.copy(a.axistags)
     resaxistags.insertChannelAxis()
-    
+
     res = vt.checkTaggedShapeMultiband(a)
-    
+
     assert_equal(res[0].shape, (20,10))
     assert_equal(res[0].axistags, a.axistags)
     assert_equal(len(res[0].axistags), 2)
-    
+
     assert_equal(res[1].shape, (20,10))
     assert_equal(res[1].axistags, a.axistags)
     assert_equal(len(res[1].axistags), 2)
-    
+
     assert_equal(res[2].shape, (20,10))
     assert_equal(res[2].axistags, a.axistags)
     assert_equal(len(res[1].axistags), 2)
-    
+
     assert_equal(res[3].shape, (20,10,3))
     assert_equal(res[3].axistags, resaxistags)
     assert_equal(res[3].axistags[2].description, "res4")
-    
+
     assert_equal(res[4].shape, (20,10))
     assert_equal(res[4].axistags, a.axistags)
     assert_equal(len(res[4].axistags), 2)
-    
+
     assert_equal(res[5].shape, (20,10,3))
     assert_equal(res[5].axistags, resaxistags)
     assert_equal(res[5].axistags[2].description, "res6")
-    
+
     res = vt.checkTaggedShapeSingleband(a)
-    
+
     assert_equal(res[0].shape, (20,10))
     assert_equal(res[0].axistags, a.axistags)
     assert_equal(len(res[0].axistags), 2)
-    
+
     assert_equal(res[1].shape, (20,10))
     assert_equal(res[1].axistags, a.axistags)
     assert_equal(len(res[1].axistags), 2)
-    
+
     assert_equal(res[2].shape, (20,10))
     assert_equal(res[2].axistags, a.axistags)
     assert_equal(len(res[1].axistags), 2)
-    
+
     assert_equal(res[3].shape, (20,10,3))
     assert_equal(res[3].axistags, resaxistags)
     assert_equal(res[3].axistags[2].description, "res4")
-    
+
     assert_equal(res[4].shape, (20,10))
     assert_equal(res[4].axistags, a.axistags)
     assert_equal(len(res[4].axistags), 2)
-    
+
     assert_equal(res[5].shape, (20,10,3))
     assert_equal(res[5].axistags, resaxistags)
     assert_equal(res[5].axistags[2].description, "res6")
-    
+
     a = numpy.zeros((3,4,5))
     at = AxisTags(AxisInfo.x, AxisInfo.y, AxisInfo.z)
+
     r = arraytypes.taggedView(a, at)
     assert_equal(r.shape, (3,4,5))
     assert_equal(r.axistags, at)
     assert(r.axistags is not at)
+
     r = arraytypes.taggedView(a, 'xyz')
     assert_equal(r.shape, (3,4,5))
     assert_equal(r.axistags, at)
- 
+
+    r = arraytypes.taggedView(a, 'cyx')
+    assert_equal(r.shape, (3,4,5))
+    assert_equal(repr(r.axistags), 'c y x')
+
+    try:
+        r = arraytypes.taggedView(a, 'cxy', order='C')
+        raise AssertionError, "arraytypes.taggedView() failed to throw."
+    except RuntimeError:
+        pass
+
+    a = arraytypes.taggedView(a, 'zyx')
+    r = arraytypes.taggedView(a, order='C')
+    assert_equal(r.shape, (3,4,5))
+    assert_equal(repr(r.axistags), 'z y x')
+    r = arraytypes.taggedView(a, order='V')
+    assert_equal(r.shape, (5,4,3))
+    assert_equal(repr(r.axistags), 'x y z')
+    r = arraytypes.taggedView(a, order='F')
+    assert_equal(r.shape, (5,4,3))
+    assert_equal(repr(r.axistags), 'x y z')
+
+    a = a[0,...]
+    r = arraytypes.taggedView(a, 'xcy')
+    assert_equal(r.shape, (5,1,4))
+    assert_equal(repr(r.axistags), 'x c y')
+    r = arraytypes.taggedView(a, 'yxc')
+    assert_equal(r.shape, (4,5,1))
+    assert_equal(repr(r.axistags), 'y x c')
+
+    try:
+        r = arraytypes.taggedView(a, 'xcz')
+        raise AssertionError, "arraytypes.taggedView() failed to throw."
+    except RuntimeError:
+        pass
+
+    try:
+        r = arraytypes.taggedView(a, 'xcz', force=True)
+        raise AssertionError, "arraytypes.taggedView() failed to throw."
+    except RuntimeError:
+        pass
+
+    r = arraytypes.taggedView(a, 'xz', force=True)
+    assert_equal(r.shape, (4,5))
+    assert_equal(repr(r.axistags), 'x z')
+
+    a = a[..., arraytypes.newaxis('c')]
+    r = arraytypes.taggedView(a, order='V')
+    assert_equal(r.shape, (5, 4, 1))
+    assert_equal(repr(r.axistags), 'x y c')
+
+    r = arraytypes.taggedView(a, order='V', noChannels=True)
+    assert_equal(r.shape, (5, 4))
+    assert_equal(repr(r.axistags), 'x y')
+
+
 def testDeepcopy():
     a = arraytypes.RGBImage(numpy.random.random((10, 4, 3)), order='C')
     b = copy.deepcopy(a)
@@ -1188,7 +1304,7 @@ def testPickle():
     assert_equal(b.strides, a.strides)
     assert_equal(b.axistags, a.axistags)
     assert numpy.all(a == b)
-    
+
 def testZMQ():
     try:
         import zmq
@@ -1199,7 +1315,7 @@ def testZMQ():
         receiver.connect('inproc://a')
     except:
         return
-        
+
     a = arraytypes.RGBImage(numpy.random.random((10, 4, 3)), order='C')
     a.sendSocket(sender, copy=False)
     b = arraytypes.VigraArray.receiveSocket(receiver, copy=False)
@@ -1223,64 +1339,64 @@ def testZMQ():
     assert_equal(b.strides, a.strides)
     assert_equal(b.axistags, a.axistags)
     assert numpy.all(a == b)
-    
+
 def testSlicing():
     a = arraytypes.Vector2Volume((5,4,3))
     a.flat[...] = xrange(a.size)
-    
+
     tags = arraytypes.VigraArray.defaultAxistags('xyzc')
     assert_equal(tags, a.axistags)
-    
+
     b = a[...]
     assert_true((a==b).all())
     assert_equal(tags, b.axistags)
-    
+
     b = a[...,0]
     assert_equal(b.shape, a.shape[:-1])
     assert_equal(b.axistags, arraytypes.VigraArray.defaultAxistags('xyz'))
     assert_equal(b[3,2,1], a[3,2,1,0])
-    
+
     b = a[1,...]
     assert_equal(b.shape, a.shape[1:])
     assert_equal(b.axistags, arraytypes.VigraArray.defaultAxistags('yzc'))
     assert_equal(b[3,2,1], a[1,3,2,1])
-    
+
     b = a[:,2,...]
     assert_equal(b.shape, (5,3,2))
     assert_equal(b.axistags, arraytypes.VigraArray.defaultAxistags('xzc'))
     assert_equal(b[3,2,1], a[3,2,2,1])
-    
+
     b = a[:,1,2,...]
     assert_equal(b.shape, (5,2))
     assert_equal(b.axistags, arraytypes.VigraArray.defaultAxistags('xc'))
     assert_equal(b[2,1], a[2,1,2,1])
-    
+
     b = a[2:4, :, 2, ...]
     assert_equal(b.shape, (2, 4, 2))
     assert_equal(b.axistags, arraytypes.VigraArray.defaultAxistags('xyc'))
     assert_equal(b[0,2,1], a[2,2,2,1])
-    
+
     b = a[1:4, :, arraytypes.newaxis(arraytypes.AxisInfo.t), 1, ...]
     assert_equal(b.shape, (3, 4, 1, 2))
     assert_equal(b.axistags, arraytypes.VigraArray.defaultAxistags('xytc'))
     assert_equal(b[0,2,0,0], a[1,2,1,0])
-    
+
     b = a[..., None, :,1]
     assert_equal(b.shape, (5, 4, 1, 3))
-    rtags = arraytypes.AxisTags(arraytypes.AxisInfo.x, arraytypes.AxisInfo.y, arraytypes.AxisInfo(), arraytypes.AxisInfo.z) 
+    rtags = arraytypes.AxisTags(arraytypes.AxisInfo.x, arraytypes.AxisInfo.y, arraytypes.AxisInfo(), arraytypes.AxisInfo.z)
     assert_equal(b.axistags, rtags)
     assert_equal(b[0,3,0,1], a[0,3,1,1])
-    
+
     b = a.subarray((4,3,2))
     assert_equal(b.shape, (4,3,2,2))
     assert_true((a[:4,:3,:2,:]==b).all())
     assert_equal(tags, b.axistags)
-    
+
     b = a.subarray((1,1,1),(4,3,2))
     assert_equal(b.shape, (3,2,1,2))
     assert_true((a[1:4,1:3,1:2]==b).all())
     assert_equal(tags, b.axistags)
-    
+
     b = a.subarray((1,1,1,1),(4,3,2,2))
     assert_equal(b.shape, (3,2,1,1))
     assert_true((a[1:4,1:3,1:2,1:]==b).all())
@@ -1289,100 +1405,100 @@ def testSlicing():
 def testMethods():
     a = arraytypes.ScalarImage((20, 30))
     ones = arraytypes.ScalarImage((20, 30), value=1)
-    
+
     a.ravel()[...] = range(a.size)
-    
+
     for k, i in zip(a.flat, xrange(a.size)):
         assert_equal(k, i)
-        
+
     assert (a.flatten() == range(a.size)).all()
-    
+
     assert (a >= 0).all()
     assert not (a == 0).all()
-    
+
     assert (a == 0).any()
     assert not (a == -1).any()
-    
+
     assert_equal(a.argmax(), a.size-1)
     assert (a.argmax(axis='y') == a.shape[1]-1).all()
-    
+
     assert_equal(a.argmin(), 0)
     assert (a.argmin(axis='y') == 0).all()
-    
+
     assert (ones.cumsum()-1 == a.ravel()).all()
     oc = ones.cumsum(axis='x')-1
     for s in oc.sliceIter('y'):
         assert (s == range(a.shape[0])).all()
-    
+
     assert (ones.cumprod() == 1).all()
     assert (ones.cumprod(axis='x') == 1).all()
-    
+
     assert_equal(a.max(), a.size-1)
     assert (a.max(axis='y') == range(a.size-a.shape[0], a.size)).all()
-    
+
     assert_equal(a.mean(dtype=numpy.longdouble), (a.size - 1.0) / 2.0)
-    assert (a.mean(axis='y', dtype=numpy.longdouble) == 
+    assert (a.mean(axis='y', dtype=numpy.longdouble) ==
             range((a.size-a.shape[0])/2, (a.size+a.shape[0])/2)).all()
 
     assert_equal(a.min(), 0)
     assert (a.min(axis='y') == range(a.shape[0])).all()
-    
+
     n = arraytypes.ScalarImage(numpy.array([[1, 0, 0],[0, 1, 1],[1, 0, 1]]))
     nz = n.nonzero()
     assert (nz[0] == [0, 1, 1, 2, 2]).all()
     assert_equal(nz[0].axistags, n.defaultAxistags('x'))
     assert (nz[1] == [0, 1, 2, 0, 2]).all()
     assert_equal(nz[1].axistags, n.defaultAxistags('y'))
-    
+
     assert_equal(ones.prod(), 1.0)
     assert (ones.prod(axis='y') == [1]*ones.shape[0]).all()
-    
+
     assert_equal(a.ptp(), a.size-1)
     assert (a.ptp(axis='x') == [a.shape[0]-1]*a.shape[1]).all()
-    
+
     r = arraytypes.ScalarImage((2,2))
     r.ravel()[...] = range(4)
-    
+
     assert (r.repeat(1) == r.ravel()).all()
     assert (r.repeat(2) == reduce(lambda x,y: x+[y,y], range(4), [])).all()
     assert (r.repeat([0,1,2,3]) == [1,2,2,3,3,3]).all()
     assert (r.repeat(2, axis='y').ravel() == [0,1,0,1,2,3,2,3]).all()
     assert (r.repeat([1,2], axis='y').ravel() == [0,1,2,3,2,3]).all()
-    
+
     s = a[arraytypes.AxisInfo.c,:,arraytypes.AxisInfo.z,:,arraytypes.AxisInfo.t]
     assert_equal(s.shape, (1, a.shape[0], 1, a.shape[1], 1))
     assert_equal(s.axistags,a.defaultAxistags('cxzyt'))
     ss = s.squeeze()
     assert_equal(ss.shape, a.shape)
     assert_equal(ss.axistags,a.axistags)
-    
+
     assert_equal(ones.std(dtype=numpy.longdouble), 0.0)
     assert (ones.std(axis='x', dtype=numpy.longdouble) == [0.0]*a.shape[1]).all()
-    
+
     assert_equal(ones.sum(dtype=numpy.longdouble), ones.size)
     assert (ones.sum(axis='x', dtype=numpy.longdouble) == [a.shape[0]]*a.shape[1]).all()
-    
+
     b = a.swapaxes(0, 1)
     assert_equal(b.shape, (a.shape[1], a.shape[0]))
     assert_equal(len(b.axistags), 2)
     assert_equal(b.axistags[0], a.axistags[1])
     assert_equal(b.axistags[1], a.axistags[0])
-    
+
     b = a.swapaxes(0, 1, keepTags=True)
     assert_equal(b.shape, (a.shape[1], a.shape[0]))
     assert_equal(len(b.axistags), 2)
     assert_equal(b.axistags, a.axistags)
-    
+
     rt = r.take([1,2])
     assert (rt == [1,2]).all()
     assert_equal(rt.axistags, arraytypes.AxisTags(1))
     rt = r.take([0,1], axis='y')
     assert (rt == r).all()
     assert_equal(rt.axistags, rt.axistags)
-    
+
     assert_equal(ones.var(dtype=numpy.longdouble), 0.0)
     assert (ones.var(axis='x', dtype=numpy.longdouble) == [0.0]*a.shape[1]).all()
-    
+
     a = arraytypes.Image((5,4,3))
     b = a.transpose()
     assert_equal(b.shape, (3,4,5))
@@ -1404,7 +1520,7 @@ def testMethods():
     assert_equal(b.shape, (4,3,5))
     assert_equal(len(b.axistags), len(a.axistags))
     assert_equal(b.axistags, a.axistags)
-    
+
 def testUfuncs():
     from numpy import bool, int8, uint8, int16, uint16, int32, uint32, int64, uint64
     from numpy import float32, float64, longdouble, complex64, complex128, clongdouble
@@ -1412,7 +1528,7 @@ def testUfuncs():
     floats = [float32, float64, longdouble]
     compl = [complex64, complex128, clongdouble]
     types = integers + floats + compl
-    
+
     arrays, ones  = {}, {}
     for t in types:
         arrays[t] = arraytypes.ScalarImage((2,2), t, value=2)
@@ -1521,7 +1637,7 @@ def testUfuncs():
         assert (b == 2.5).all()
         assert_equal(a1.dtype, b.dtype)
         assert_equal(a1.axistags, b.axistags)
-        
+
         fractional, integral = ufunc.modf(b)
         assert (fractional == 0.5).all()
         assert (integral == 2.0).all()
@@ -1529,7 +1645,7 @@ def testUfuncs():
         assert_equal(a1.axistags, fractional.axistags)
         assert_equal(a1.dtype, integral.dtype)
         assert_equal(a1.axistags, integral.axistags)
-        
+
     assert_equal(float64, (arrays[float32]+arrays[float64]).dtype)
     assert_equal(float64, (arrays[float64]+arrays[float32]).dtype)
     assert_equal(longdouble, (arrays[float32]+arrays[longdouble]).dtype)
@@ -1564,7 +1680,7 @@ def testUfuncs():
     assert (b == 254).all()
     b = 255 + a
     assert (b == 254).all()
-    
+
     b = arraytypes.ScalarImage((2,2), int32, value=0)
     bb = ufunc.add(a, a, b)
     assert bb is b
diff --git a/vigranumpy/test/test_rf.py b/vigranumpy/test/test_rf.py
new file mode 100644
index 0000000..5b78227
--- /dev/null
+++ b/vigranumpy/test/test_rf.py
@@ -0,0 +1,22 @@
+import sys
+print >> sys.stderr, "\nexecuting test file", __file__
+
+import vigra
+import numpy as np
+
+
+gaus1=10*np.random.randn(1000).reshape((500,2))+np.array([20,20])
+gaus1=gaus1.astype(np.float32)
+gaus2=10*np.random.randn(1000).reshape((500,2))+np.array([20,20])
+gaus2=gaus2.astype(np.float32)
+label_gaus1=np.ones(500).astype(np.uint32)
+label_gaus2=np.zeros(500).astype(np.uint32)
+
+def test_rf_learn():
+    RF=vigra.learning.RandomForest(10)
+    fmat=np.vstack([gaus1,gaus2])
+    lmat=np.vstack([label_gaus1,label_gaus2]).reshape(-1,1)
+    RF.learnRF(fmat,lmat,0,1,100)
+
+def ok_():
+    print >> sys.stderr, ".",
diff --git a/vigranumpy/test/test_segmentation.py b/vigranumpy/test/test_segmentation.py
new file mode 100644
index 0000000..3dc307f
--- /dev/null
+++ b/vigranumpy/test/test_segmentation.py
@@ -0,0 +1,37 @@
+import sys
+print >> sys.stderr, "\nexecuting test file", __file__
+execfile('set_paths.py')
+
+import numpy
+import vigra
+
+def _impl_test_labelMultiArray(dtype):
+    a = numpy.zeros( (10,10,10,10,2), dtype=dtype )
+    a[3:4, 5:8, 5:8, 5:8] = 100
+    a[4:5, 8:10, 5:8, 5:8] = 100 # touches above object on corners only.
+    
+    a[3:4, 1:4, 5:8, 5:8] = 200
+    
+    labeled = vigra.analysis.labelMultiArray(a)
+    assert labeled.dtype == numpy.uint32
+    assert labeled.max() == 4
+
+    labeled = vigra.analysis.labelMultiArrayWithBackground(a)
+    assert labeled.dtype == numpy.uint32
+    assert labeled.max() == 3
+
+    labeled = vigra.analysis.labelMultiArrayWithBackground(a, neighborhood='indirect')
+    assert labeled.dtype == numpy.uint32
+    assert labeled.max() == 2
+    
+    labeled = vigra.analysis.labelMultiArrayWithBackground(a, background_value=100)
+    assert labeled.dtype == numpy.uint32
+    assert labeled.max() == 2
+
+def test_labelMultiArray():
+    _impl_test_labelMultiArray(numpy.uint8)
+    _impl_test_labelMultiArray(numpy.uint32)
+    _impl_test_labelMultiArray(numpy.float32)
+    
+def ok_():
+    print >> sys.stderr, ".",

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/libvigraimpex.git



More information about the debian-science-commits mailing list