---
milena/apps/bench/Makefile.am | 15 +++-
milena/apps/bench/dilation-lena.cc | 119 +++++++++++++++++++++++++--
milena/apps/bench/static_dpoints_pixter.hh | 102 ++++++++++++-----------
milena/apps/bench/static_window.hh | 4 +-
milena/apps/bench/trait.hh | 99 +++++++++++++++++++++++
5 files changed, 277 insertions(+), 62 deletions(-)
create mode 100644 milena/apps/bench/trait.hh
diff --git a/milena/apps/bench/Makefile.am b/milena/apps/bench/Makefile.am
index adc0cdf..266b71b 100644
--- a/milena/apps/bench/Makefile.am
+++ b/milena/apps/bench/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE).
+# Copyright (C) 2010, 2011 EPITA Research and Development Laboratory (LRDE).
#
# This file is part of Olena.
#
@@ -29,7 +29,12 @@ noinst_PROGRAMS = \
EXTRA_DIST += \
and_not.hh \
- minus.hh
+ minus.hh \
+ \
+ static_array.hh \
+ static_dpoints_pixter.hh \
+ static_window.hh \
+ trait.hh
dilation_lena_SOURCES = dilation-lena.cc
gradient_lena_SOURCES = gradient-lena.cc
@@ -37,6 +42,8 @@ gradient_spe_lena_SOURCES = gradient-spe-lena.cc
MOSTLYCLEANFILES = \
dilation-lena-out-512-nongen.pgm \
+ dilation-lena-out-512-nongen_2ptr.pgm \
+ dilation-lena-out-512-nongen_1ptr.pgm \
dilation-lena-out-512-gen.pgm \
dilation-lena-out-512-fast.pgm \
dilation-lena-out-512-fast_noaccu.pgm \
@@ -46,6 +53,8 @@ MOSTLYCLEANFILES = \
dilation-lena-out-512-faster_static.pgm \
\
dilation-lena-out-1024-nongen.pgm \
+ dilation-lena-out-1024-nongen_2ptr.pgm \
+ dilation-lena-out-1024-nongen_1ptr.pgm \
dilation-lena-out-1024-gen.pgm \
dilation-lena-out-1024-fast.pgm \
dilation-lena-out-1024-fast_noaccu.pgm \
@@ -55,6 +64,8 @@ MOSTLYCLEANFILES = \
dilation-lena-out-1024-faster_static.pgm \
\
dilation-lena-out-2048-nongen.pgm \
+ dilation-lena-out-2048-nongen_2ptr.pgm \
+ dilation-lena-out-2048-nongen_1ptr.pgm \
dilation-lena-out-2048-gen.pgm \
dilation-lena-out-2048-fast.pgm \
dilation-lena-out-2048-fast_noaccu.pgm \
diff --git a/milena/apps/bench/dilation-lena.cc b/milena/apps/bench/dilation-lena.cc
index 69c82a7..e4996fb 100644
--- a/milena/apps/bench/dilation-lena.cc
+++ b/milena/apps/bench/dilation-lena.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -23,6 +23,8 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
+#include <cstddef>
+
#include <iostream>
#include <mln/core/image/image2d.hh>
@@ -39,9 +41,12 @@
#include "apps/bench/static_window.hh"
#include "apps/bench/static_dpoints_pixter.hh"
+#include "apps/bench/trait.hh"
+
#include "apps/data.hh"
+
namespace nongen
{
typedef mln::image2d<mln::value::int_u8> image;
@@ -63,6 +68,99 @@ namespace nongen
}
}
+namespace nongen_2ptr
+{
+ typedef mln::image2d<mln::value::int_u8> image;
+
+ image dilation(const image& input)
+ {
+ typedef mln::value::int_u8 val_t;
+ // Offsets corresponding to a 4-c window on INPUT.
+ ptrdiff_t win_offset[4] = { &input.at_(-1, 0) - &input.at_(0, 0),
+ &input.at_(+1, 0) - &input.at_(0, 0),
+ &input.at_( 0, -1) - &input.at_(0, 0),
+ &input.at_( 0, +1) - &input.at_(0, 0) };
+
+ image output (input.nrows(), input.ncols()); // Initialize an output image.
+ for (unsigned int r = 0; r < input.nrows(); ++r) // Iterate on rows.
+ {
+ const val_t* pi = &input.at_(r, 0);
+ val_t* po = &output.at_(r, 0);
+ for (; pi < &input.at_(r, 0) + input.ncols(); ++pi, ++po)
+ {
+ unsigned char sup = *pi;
+ // (-1, 0) neighbor.
+ if (r != 0
+ && *(pi + win_offset[0]) > sup)
+ sup = *(pi + win_offset[0]);
+ // (+1, 0) neighbor.
+ if (r != input.nrows() - 1
+ && *(pi + win_offset[1]) > sup)
+ sup = *(pi + win_offset[1]);
+ // (0, -1) neighbor.
+ if (pi != &input.at_(r, 0)
+ && *(pi + win_offset[2]) > sup)
+ sup = *(pi + win_offset[2]);
+ // (0, +1) neighbor.
+ if (pi != &input.at_(r, 0) + input.ncols() - 1
+ && *(pi + win_offset[3]) > sup)
+ sup = *(pi + win_offset[3]);
+ *po = sup;
+ }
+ }
+ return output;
+ }
+}
+
+namespace nongen_1ptr
+{
+ typedef mln::image2d<mln::value::int_u8> image;
+
+ image dilation(const image& input)
+ {
+ typedef mln::value::int_u8 val_t;
+ // Offsets corresponding to a 4-c window on INPUT.
+ ptrdiff_t win_offset[4] = { &input.at_(-1, 0) - &input.at_(0, 0),
+ &input.at_(+1, 0) - &input.at_(0, 0),
+ &input.at_( 0, -1) - &input.at_(0, 0),
+ &input.at_( 0, +1) - &input.at_(0, 0) };
+
+ image output;
+ initialize(output, input);
+ // Offset between a the pixel located at the same position in
+ // INPUT and OUTPUT.
+ ptrdiff_t output_offset = &output.at_(0, 0) - &input.at_(0, 0);
+
+ for (unsigned int r = 0; r < input.nrows(); ++r) // Iterate on rows.
+ {
+ for (const val_t* pi = &input.at_(r, 0);
+ pi < &input.at_(r, 0) + input.ncols();
+ ++pi)
+ {
+ unsigned char sup = *pi;
+ // (-1, 0) neighbor.
+ if (r != 0
+ && *(pi + win_offset[0]) > sup)
+ sup = *(pi + win_offset[0]);
+ // (+1, 0) neighbor.
+ if (r != input.nrows() - 1
+ && *(pi + win_offset[1]) > sup)
+ sup = *(pi + win_offset[1]);
+ // (0, -1) neighbor.
+ if (pi != &input.at_(r, 0)
+ && *(pi + win_offset[2]) > sup)
+ sup = *(pi + win_offset[2]);
+ // (0, +1) neighbor.
+ if (pi != &input.at_(r, 0) + input.ncols() - 1
+ && *(pi + win_offset[3]) > sup)
+ sup = *(pi + win_offset[3]);
+ const_cast<val_t&>(*(pi + output_offset)) = sup;
+ }
+ }
+ return output;
+ }
+}
+
namespace gen
{
using namespace mln;
@@ -201,9 +299,8 @@ namespace fast_static
mln_pixter(const I) pi(input); // Iterator on the pixels of `input'.
mln_pixter(O) po(output); // Iterator on the pixels of `output'.
+ mln_static_qixter(const I, W) q(pi, win); // Iterator on the neighbors of `p'
w.r.t. `win'.
- typedef mln::static_dpoints_fwd_pixter<const I, W::Size> mln_static_qixter;
- mln_static_qixter q(pi, win);
for_all_2(pi, po)
{
// FIXME: Cheat: replace the accu::supremum by a maximum.
@@ -227,9 +324,8 @@ namespace faster_static
O output; initialize(output, input); // Initialize output.
mln_pixter(const I) p(input); // Iterator on the pixels of `input'.
+ mln_static_qixter(const I, W) q(p, win); // Iterator on the neighbors of `p'
w.r.t. `win'.
- typedef mln::static_dpoints_fwd_pixter<const I, W::Size> mln_static_qixter;
- mln_static_qixter q(p, win);
for_all(p)
{
// FIXME: Cheat: replace the accu::supremum by a maximum.
@@ -288,9 +384,13 @@ run(const std::string& filename, const std::string& length,
unsigned niters)
std::string prefix = "dilation-lena-out";
std::cout << "== " << filename << std::endl;
- DILATION_WITH_BUILTIN_WINDOW(nongen, "nongen", "nongen\t\t");
+ DILATION_WITH_BUILTIN_WINDOW(nongen, "nongen",
"nongen\t\t");
+ DILATION_WITH_BUILTIN_WINDOW(nongen_2ptr, "nongen_2ptr",
"nongen_2ptr\t");
+ DILATION_WITH_BUILTIN_WINDOW(nongen_1ptr, "nongen_1ptr",
"nongen_1ptr\t");
DILATION(gen, win_c4p(), "gen", "gen\t\t");
+ // FIXME: Introduce a new test case, gen_static, using a static window
+ // and static_qiters.
DILATION(fast, win_c4p(), "fast", "fast\t\t");
DILATION(fast_noaccu, win_c4p(), "fast_noaccu",
"fast_noaccu\t");
DILATION(faster, win_c4p(), "faster", "faster\t\t");
@@ -315,7 +415,8 @@ run(const std::string& filename, const std::string& length,
unsigned niters)
int
main ()
{
- run(MLN_IMG_DIR "/lena.pgm", "512", 10);
- run(MLN_APPS_DIR "/bench/lena1024.pgm", "1024", 10);
- run(MLN_APPS_DIR "/bench/lena2048.pgm", "2048", 10);
+ unsigned niters = 10;
+ run(MLN_IMG_DIR "/lena.pgm", "512", niters);
+ run(MLN_APPS_DIR "/bench/lena1024.pgm", "1024", niters);
+ run(MLN_APPS_DIR "/bench/lena2048.pgm", "2048", niters);
}
diff --git a/milena/apps/bench/static_dpoints_pixter.hh
b/milena/apps/bench/static_dpoints_pixter.hh
index d7823ac..ffa4a81 100644
--- a/milena/apps/bench/static_dpoints_pixter.hh
+++ b/milena/apps/bench/static_dpoints_pixter.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2007, 2008, 2009, 2010 EPITA Research and Development
+// Copyright (C) 2007, 2008, 2009, 2010, 2011 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
@@ -50,19 +50,19 @@ namespace mln
{
/*----------------------------------.
- | static_dpoints_fwd_pixter<I, n>. |
+ | static_dpoints_fwd_pixter<I, W>. |
`----------------------------------*/
/// \brief A generic forward iterator on the pixels of a
/// dpoint-based window or neighborhood.
///
/// Parameter \c I is the image type.
- template <typename I, unsigned n>
+ template <typename I, typename W>
class static_dpoints_fwd_pixter
- : public Pixel_Iterator< static_dpoints_fwd_pixter<I, n> >,
- public internal::pixel_impl_< I, static_dpoints_fwd_pixter<I, n> >
+ : public Pixel_Iterator< static_dpoints_fwd_pixter<I, W> >,
+ public internal::pixel_impl_< I, static_dpoints_fwd_pixter<I, W> >
{
- typedef typename internal::pixel_impl_< I, static_dpoints_fwd_pixter<I, n>
> super_;
+ typedef typename internal::pixel_impl_< I, static_dpoints_fwd_pixter<I, W>
> super_;
public:
/// \brief Constructor (using an image).
@@ -111,6 +111,8 @@ namespace mln
void init_(const Dps& dps);
private:
+ enum { n = W::length };
+
/// \brief Offset of each delta-point.
///
/// offset_[0] is absolute, while other offsets are relative
@@ -133,19 +135,19 @@ namespace mln
/*----------------------------------.
- | static_dpoints_bkd_pixter<I, n>. |
+ | static_dpoints_bkd_pixter<I, W>. |
`----------------------------------*/
/// \brief A generic backward iterator on the pixels of a
/// dpoint-based window or neighborhood.
///
/// Parameter \c I is the image type.
- template <typename I, unsigned n>
+ template <typename I, typename W>
class static_dpoints_bkd_pixter
- : public Pixel_Iterator< static_dpoints_bkd_pixter<I, n> >,
- public internal::pixel_impl_< I, static_dpoints_bkd_pixter<I, n> >
+ : public Pixel_Iterator< static_dpoints_bkd_pixter<I, W> >,
+ public internal::pixel_impl_< I, static_dpoints_bkd_pixter<I, W> >
{
- typedef typename internal::pixel_impl_< I, static_dpoints_bkd_pixter<I, n>
> super_;
+ typedef typename internal::pixel_impl_< I, static_dpoints_bkd_pixter<I, W>
> super_;
public:
/// \brief Constructor (using an image).
@@ -194,6 +196,8 @@ namespace mln
void init_(const Dps& dps);
private:
+ enum { n = W::length };
+
/// \brief Offset of each delta-point.
///
/// offset_[dps.size() - 1] is absolute, while other offsets
@@ -219,13 +223,13 @@ namespace mln
#ifndef MLN_INCLUDE_ONLY
/*----------------------------------.
- | static_dpoints_fwd_pixter<I, n>. |
+ | static_dpoints_fwd_pixter<I, W>. |
`----------------------------------*/
- template <typename I, unsigned n>
+ template <typename I, typename W>
template <typename Dps, typename Pref>
inline
- static_dpoints_fwd_pixter<I, n>::static_dpoints_fwd_pixter(I& image,
+ static_dpoints_fwd_pixter<I, W>::static_dpoints_fwd_pixter(I& image,
const Dps& dps,
const Pref& p_ref)
: super_(image)
@@ -239,10 +243,10 @@ namespace mln
init_(dps);
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
template <typename Dps, typename Pref>
inline
- static_dpoints_fwd_pixter<I, n>::static_dpoints_fwd_pixter(const
Generalized_Pixel<Pref>& pxl_ref_,
+ static_dpoints_fwd_pixter<I, W>::static_dpoints_fwd_pixter(const
Generalized_Pixel<Pref>& pxl_ref_,
const Dps& dps)
: super_(internal::force_exact<Pref>(pxl_ref_).ima())
{
@@ -254,10 +258,10 @@ namespace mln
init_(dps);
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
const mln_value(I)&
- static_dpoints_fwd_pixter<I, n>::center_val() const
+ static_dpoints_fwd_pixter<I, W>::center_val() const
{
mln_invariant(value_ref_ != 0 || p_ref_ != 0);
if (p_ref_)
@@ -266,11 +270,11 @@ namespace mln
return **value_ref_;
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
template <typename Dps>
inline
void
- static_dpoints_fwd_pixter<I, n>::init_(const Dps& dps)
+ static_dpoints_fwd_pixter<I, W>::init_(const Dps& dps)
{
for (unsigned i = 0; i < dps.size(); ++i)
offset_[i] = this->image_.delta_index(dps.dp(i));
@@ -282,10 +286,10 @@ namespace mln
invalidate();
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
void
- static_dpoints_fwd_pixter<I, n>::update()
+ static_dpoints_fwd_pixter<I, W>::update()
{
if (is_valid())
{
@@ -296,50 +300,50 @@ namespace mln
}
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
void
- static_dpoints_fwd_pixter<I, n>::start()
+ static_dpoints_fwd_pixter<I, W>::start()
{
i_ = 0;
update();
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
void
- static_dpoints_fwd_pixter<I, n>::next_()
+ static_dpoints_fwd_pixter<I, W>::next_()
{
++i_;
if (is_valid())
this->value_ptr_ += offset_[i_];
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
bool
- static_dpoints_fwd_pixter<I, n>::is_valid() const
+ static_dpoints_fwd_pixter<I, W>::is_valid() const
{
return i_ < n;
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
void
- static_dpoints_fwd_pixter<I, n>::invalidate()
+ static_dpoints_fwd_pixter<I, W>::invalidate()
{
i_ = n;
}
/*----------------------------------.
- | static_dpoints_bkd_pixter<I, n>. |
+ | static_dpoints_bkd_pixter<I, W>. |
`----------------------------------*/
- template <typename I, unsigned n>
+ template <typename I, typename W>
template <typename Dps, typename Pref>
inline
- static_dpoints_bkd_pixter<I, n>::static_dpoints_bkd_pixter(I& image,
+ static_dpoints_bkd_pixter<I, W>::static_dpoints_bkd_pixter(I& image,
const Dps& dps,
const Pref& p_ref)
: super_(image)
@@ -350,10 +354,10 @@ namespace mln
init_(dps);
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
template <typename Dps, typename Pref>
inline
- static_dpoints_bkd_pixter<I, n>::static_dpoints_bkd_pixter(const
Generalized_Pixel<Pref>& pxl_ref_,
+ static_dpoints_bkd_pixter<I, W>::static_dpoints_bkd_pixter(const
Generalized_Pixel<Pref>& pxl_ref_,
const Dps& dps)
: super_(internal::force_exact<Pref>(pxl_ref_).ima())
{
@@ -365,10 +369,10 @@ namespace mln
init_(dps);
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
const mln_value(I)&
- static_dpoints_bkd_pixter<I, n>::center_val() const
+ static_dpoints_bkd_pixter<I, W>::center_val() const
{
mln_invariant(value_ref_ != 0 || p_ref_ != 0);
if (p_ref_)
@@ -377,11 +381,11 @@ namespace mln
return **value_ref_;
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
template <typename Dps>
inline
void
- static_dpoints_bkd_pixter<I, n>::init_(const Dps& dps)
+ static_dpoints_bkd_pixter<I, W>::init_(const Dps& dps)
{
for (unsigned i = 0; i < dps.size(); ++i)
offset_[i] = this->image_.delta_index(dps.dp(i));
@@ -393,10 +397,10 @@ namespace mln
invalidate();
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
void
- static_dpoints_bkd_pixter<I, n>::update()
+ static_dpoints_bkd_pixter<I, W>::update()
{
if (is_valid())
{
@@ -407,37 +411,37 @@ namespace mln
}
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
void
- static_dpoints_bkd_pixter<I, n>::start()
+ static_dpoints_bkd_pixter<I, W>::start()
{
i_ = 0;
update();
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
void
- static_dpoints_bkd_pixter<I, n>::next_()
+ static_dpoints_bkd_pixter<I, W>::next_()
{
++i_;
if (is_valid())
this->value_ptr_ += offset_[n - 1 - i_];
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
bool
- static_dpoints_bkd_pixter<I, n>::is_valid() const
+ static_dpoints_bkd_pixter<I, W>::is_valid() const
{
return i_ < n;
}
- template <typename I, unsigned n>
+ template <typename I, typename W>
inline
void
- static_dpoints_bkd_pixter<I, n>::invalidate()
+ static_dpoints_bkd_pixter<I, W>::invalidate()
{
i_ = n;
}
diff --git a/milena/apps/bench/static_window.hh b/milena/apps/bench/static_window.hh
index fe8f791..5a8ce21 100644
--- a/milena/apps/bench/static_window.hh
+++ b/milena/apps/bench/static_window.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2007, 2008, 2009, 2010 EPITA Research and Development
+// Copyright (C) 2007, 2008, 2009, 2010, 2011 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
@@ -90,7 +90,7 @@ namespace mln
{
public:
- enum { Size = n };
+ enum { length = n };
/// Regular window associated type.
typedef static_window<D, n> regular;
diff --git a/milena/apps/bench/trait.hh b/milena/apps/bench/trait.hh
new file mode 100644
index 0000000..e3e5004
--- /dev/null
+++ b/milena/apps/bench/trait.hh
@@ -0,0 +1,99 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef APPS_BENCH_TRAITS_HH
+# define APPS_BENCH_TRAITS_HH
+
+# include <mln/core/image/image2d.hh>
+# include <mln/metal/none.hh>
+
+# include "apps/bench/static_dpoints_pixter.hh"
+
+
+// FIXME: Move this into mln/core/macro.hh.
+# define mln_static_fwd_qixter(I, W) typename mln::trait::static_fwd_qixter< I, W
>::ret
+# define mln_static_fwd_qixter_(I, W) mln::trait::static_fwd_qixter< I, W
>::ret
+
+# define mln_static_bkd_qixter(I, W) typename mln::trait::static_bkd_qixter< I, W
>::ret
+# define mln_static_bkd_qixter_(I, W) mln::trait::static_bkd_qixter< I, W
>::ret
+
+# define mln_static_qixter(I, W) mln_static_fwd_qixter(I, W)
+# define mln_static_qixter_(I, W) mln_static_fwd_qixter_(I, W)
+
+
+// FIXME: Move this into mln/trait/ (and mln/core/image/?)
+namespace mln
+{
+
+ namespace trait
+ {
+
+ // qixter
+
+ template <typename I, typename W>
+ struct static_fwd_qixter
+ {
+ typedef metal::none ret;
+ };
+
+ template <typename I, typename W>
+ struct static_bkd_qixter
+ {
+ typedef metal::none ret;
+ };
+
+
+ template <typename T, typename W>
+ struct static_fwd_qixter< image2d<T>, W >
+ {
+ typedef static_dpoints_fwd_pixter< image2d<T>, W > ret;
+ };
+
+ template <typename T, typename W>
+ struct static_fwd_qixter< const image2d<T>, W >
+ {
+ typedef static_dpoints_fwd_pixter< const image2d<T>, W > ret;
+ };
+
+ template <typename T, typename W>
+ struct static_bkd_qixter< image2d<T>, W >
+ {
+ typedef static_dpoints_bkd_pixter< image2d<T>, W > ret;
+ };
+
+ template <typename T, typename W>
+ struct static_bkd_qixter< const image2d<T>, W >
+ {
+ typedef static_dpoints_bkd_pixter< const image2d<T>, W > ret;
+ };
+
+ // FIXME: Also handle mln::image1d<T> and mln::image3d<T>.
+
+
+ } // end of namespace mln::trait
+
+} // end of namespace mln
+
+#endif // ! APPS_BENCH_TRAITS_HH
--
1.7.2.5