vigra - vigra/coordinate_iterator.hxx Source File

[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

coordinate_iterator.hxx |

1 /************************************************************************/
2 /* */
3 /* Copyright 2011-2012 by Markus Nullmeier and Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35
36 #ifndef VIGRA_COORDINATE_ITERATOR_HXX
37 #define VIGRA_COORDINATE_ITERATOR_HXX
38
39 #include <complex>
40
41 #include "tuple.hxx"
42 #include "accessor.hxx"
43 #include "tinyvector.hxx"
44 #include "numerictraits.hxx"
45 #include "multi_iterator.hxx"
46 #include "multi_array.hxx"
47
48 namespace vigra {
49
50 template<unsigned N>
51 struct StridePair
52 {
53 typedef typename MultiArrayShape<N>::type index_type;
54 typedef TinyVector<double, N> coord_type;
55 typedef coord_type deref_type;
56 typedef StridePair type;
57 typedef StridePair stride_type;
58 typedef TinyVector<type, N> stride_array_type;
59 typedef TinyVector<index_type, N> shape_array_type;
60 typedef shape_array_type shape_type;
61
62 index_type index;
63 coord_type coord;
64
65 StridePair(const index_type & i) : index(i), coord(i) {}
66 StridePair(const coord_type & c) : index(), coord(c) {}
67 StridePair(const index_type & i, const coord_type & c)
68 : index (i), coord(c) {}
69 StridePair( MultiArrayIndex i, const coord_type & c)
70 : index(index_type(i)), coord(c) {}
71 StridePair() {}
72
73 // use just the coordinates for further processing ...
74 const coord_type & operator*() const
75 {
76 return this->coord;
77 }
78
79 void operator+=(const StridePair & x)
80 {
81 index += x.index;
82 coord += x.coord;
83 }
84 void operator-=(const StridePair & x)
85 {
86 index -= x.index;
87 coord -= x.coord;
88 }
89 StridePair operator+(const StridePair & x)
90 {
91 StridePair ret = *this;
92 ret += x;
93 return ret;
94 }
95 StridePair operator-(const StridePair & x)
96 {
97 StridePair ret = *this;
98 ret -= x;
99 return ret;
100 }
101 StridePair operator*(const StridePair & x)
102 {
103 StridePair ret = *this;
104 ret.index *= x.index;
105 ret.coord *= x.coord;
106 return ret;
107 }
108 StridePair operator/(const StridePair & x)
109 {
110 StridePair ret = *this;
111 ret.index /= x.index;
112 ret.coord /= x.coord;
113 return ret;
114 }
115
116 MultiArrayIndex & idx0()
117 {
118 return index[0];
119 }
120 const index_type & idx() const
121 {
122 return index;
123 }
124 double & dim0()
125 {
126 return coord[0];
127 }
128 double dim0() const
129 {
130 return coord[0];
131 }
132 };
133
134 template<unsigned M>
135 struct NumericTraits<StridePair<M> >
136 : public NumericTraits<typename StridePair<M>::index_type>
137 {};
138
139 template<unsigned N>
140 struct StridePairCoord : public TinyVector<double, N>
141 {
142 typedef TinyVector<double, N> entry_type;
143
144 StridePairCoord(const entry_type & c) : entry_type(c) {}
145 StridePairCoord() {}
146
147 double & dim0()
148 {
149 return (*this)[0];
150 }
151 double dim0() const
152 {
153 return (*this)[0];
154 }
155 };
156 template<unsigned M>
157 struct NumericTraits<StridePairCoord<M> >
158 : public NumericTraits<typename StridePairCoord<M>::entry_type>
159 {};
160
161 template<unsigned N>
162 struct StridePairDiff : public StridePairCoord<N>
163 {
164 MultiArrayIndex c;
165
166 typedef StridePairCoord<N> base_type;
167 StridePairDiff(MultiArrayIndex c_, const base_type & x)
168 : base_type(x), c(c_) {}
169 StridePairDiff(const base_type & x)
170 : base_type(x), c(0) {}
171 StridePairDiff(const TinyVector<double, N> & x)
172 : base_type(x), c(0) {}
173 StridePairDiff(const TinyVector<MultiArrayIndex, N> & x)
174 : base_type(x), c(0) {}
175 StridePairDiff() : c(0) {}
176
177 const base_type & base() const
178 {
179 return *this;
180 }
181 StridePairDiff operator*(const StridePairDiff & x)
182 {
183 StridePairDiff ret = base() * x.base();
184 ret.c = c * x.c;
185 return ret;
186 }
187 };
188
189 template<unsigned M>
190 struct NumericTraits<StridePairDiff<M> >
191 : public NumericTraits<StridePairCoord<M> >
192 {};
193
194 template<unsigned N, class T>
195 struct StridePairPointer : public StridePairCoord<N>
196 {
197 typedef const T* index_type;
198 typedef StridePairCoord<N> coord_type;
199 typedef typename coord_type::entry_type coord_num_type;
200 typedef StridePairPointer type;
201 typedef type deref_type;
202 typedef StridePairDiff<N> stride_type;
203 typedef TinyVector<stride_type, N> stride_array_type;
204 typedef typename MultiArrayShape<N>::type shape_array_type;
205 typedef shape_array_type shape_type;
206
207 index_type index;
208
209 StridePairPointer(const index_type & i, const coord_type & c)
210 : coord_type(c), index(i) {}
211
212 const type & operator*() const
213 {
214 return *this;
215 }
216 const T & value() const
217 {
218 return *index;
219 }
220 const coord_type & coord() const
221 {
222 return *this;
223 }
224
225 index_type & idx0()
226 {
227 return index;
228 }
229 const index_type & idx() const
230 {
231 return index;
232 }
233
234 void operator+=(stride_type x)
235 {
236 index += x.c;
237 coord_type::operator+=(x);
238 }
239 void operator-=(stride_type x)
240 {
241 index -= x.c;
242 coord_type::operator-=(x);
243 }
244 };
245
246 template<unsigned M, class T>
247 struct NumericTraits<StridePairPointer<M, T> >
248 : public NumericTraits<typename StridePairPointer<M, T>::coord_type>
249 {};
250
251 namespace detail {
252
253 template<class T, bool is_complex = NumericTraits<T>::isComplex::value,
254 bool is_vector = !NumericTraits<T>::isScalar::value>
255 struct weighted_abs
256 {
257 static double get(const T & x)
258 {
259 return x;
260 }
261 };
262
263 template<class T>
264 struct weighted_abs<T, true, false>
265 {
266 static double get(const T & x)
267 {
268 using std::abs;
269 return abs(x);
270 }
271 };
272
273 template<class T, bool is_complex>
274 struct weighted_abs<T, is_complex, true>
275 {
276 static double get(const T & x)
277 {
278 return x.magnitude();
279 }
280 };
281
282 template<class T>
283 struct accumulable_coord_access;
284 template<class T>
285 struct accumulable_value_access;
286 template<class T>
287 struct accumulable_weighted_access;
288
289 template<unsigned N, class T>
290 struct accumulable_coord_access<StridePairPointer<N, T> >
291 {
292 typedef StridePairPointer<N, T> accumulable_type;
293 typedef typename accumulable_type::coord_num_type type;
294 static const type & get(const accumulable_type & v) { return v.coord(); }
295 };
296
297 template<unsigned N, class T>
298 struct accumulable_value_access<StridePairPointer<N, T> >
299 {
300 typedef StridePairPointer<N, T> accumulable_type;
301 typedef T type;
302 static const type & get(const accumulable_type & v) { return v.value(); }
303 };
304
305 template<unsigned N, class T>
306 struct accumulable_weighted_access<StridePairPointer<N, T> >
307 {
308 typedef StridePairPointer<N, T> accumulable_type;
309 typedef typename accumulable_type::coord_num_type type;
310 static type get(const accumulable_type & v)
311 {
312 return weighted_abs<T>::get(v.value()) * v.coord();
313 }
314 };
315
316 template<class X>
317 void dismember(X & r, const X & x, unsigned i)
318 {
319 r[i] = x[i];
320 }
321 template<unsigned N>
322 void dismember(StridePair<N> & r, const StridePair<N> & x, unsigned i)
323 {
324 r.index[i] = x.index[i];
325 r.coord[i] = x.coord[i];
326 }
327 template<unsigned N>
328 void dismember(StridePairDiff<N> & r, const StridePairDiff<N> & x, unsigned i)
329 {
330 r.c = static_cast<MultiArrayIndex>(r[i] = x[i]);
331 }
332
333 template<unsigned N, class X>
334 TinyVector<X, N>
335 dismember(const X & x)
336 {
337 TinyVector<X, N> ret;
338 for (unsigned i = 0; i != N; ++i)
339 dismember(ret[i], x, i);
340 return ret;
341 }
342 template<unsigned N>
343 TinyVector<StridePairDiff<N>, N>
344 dismember(const TinyVector<MultiArrayIndex, N> & x,
345 const StridePairCoord<N> & y)
346 {
347 typedef StridePairDiff<N> type;
348 TinyVector<type, N> ret;
349 for (unsigned i = 0; i != N; ++i)
350 {
351 ret[i].c = x[i];
352 ret[i][i] = y[i];
353 }
354 return ret;
355 }
356
357 } // namespace detail
358
359 // A fake "pointer" for MultiIterator containing coordinates.
360 // Indices (or a pointer) cannot be circumvented in coordiante iterators,
361 // since floating point addition is not associative and
362 // iterator comparison is done via via '<' or '!='. Class CoordinateStride
363 // thus forwards iterator comparison to the index or pointer part
364 // of its template parameter S.
365 template<unsigned N, class S = StridePair<N> >
366 class CoordinateStride : protected S
367 {
368 public:
369 typedef MultiArrayIndex difference_type;
370 typedef typename S::stride_type stride_type;
371 typedef typename S::deref_type deref_type;
372 typedef CoordinateStride<N> type;
373 typedef typename S::coord_type coord_type;
374 typedef typename S::index_type index_type;
375 typedef typename S::shape_array_type shape_array_type;
376
377 protected:
378 double stride_0;
379
380 CoordinateStride(void*) {} // used MultiIterator ctor, unused.
381
382 public:
383 CoordinateStride(const S & x, double s0)
384 : S(x), stride_0(s0) {}
385
386 #ifndef DOXYGEN
387 using S::operator*;
388 using S::idx0;
389 using S::idx;
390 using S::dim0;
391 using S::operator+=;
392 using S::operator-=;
393 #endif
394
395 void operator++()
396 {
397 ++idx0();
398 dim0() += stride_0;
399 }
400 void operator--()
401 {
402 --idx0();
403 dim0() -= stride_0;
404 }
405 void operator+=(difference_type n)
406 {
407 idx0() += n;
408 dim0() += n * stride_0;
409 }
410 void operator-=(difference_type n)
411 {
412 idx0() -= n;
413 dim0() -= n * stride_0;
414 }
415
416 stride_type operator[](difference_type n) const
417 {
418 type ret = *this;
419 ret[0] += n;
420 return ret;
421 }
422
423 stride_type operator[](stride_type x) const
424 {
425 return *this + x;
426 }
427
428 // ... but use the idx() for comparisons:
429 bool operator!=(const CoordinateStride & y) const
430 {
431 return idx() != y.idx();
432 }
433 bool operator==(const CoordinateStride & y) const
434 {
435 if (stride_0 != y.stride_0)
436 return false;
437 return idx() == y.idx();
438 }
439 bool operator<(const CoordinateStride & y) const
440 {
441 return idx() < y.idx();
442 }
443
444 bool operator<=(const CoordinateStride & y) const
445 {
446 if (stride_0 == y.stride_0)
447 return true;
448 return *this < y;
449 }
450 bool operator>(const CoordinateStride & y) const
451 {
452 return y < *this;
453 }
454 bool operator>=(const CoordinateStride & y) const
455 {
456 if (stride_0 == y.stride_0)
457 return true;
458 return operator>(y);
459 }
460
461 friend std::ostream &
462 operator<<(std::ostream & os, const CoordinateStride & x)
463 {
464 os << "{" << x.stride_0 << ": " << static_cast<const S &>(x) << "}";
465 return os;
466 }
467
468 typedef MultiIterator<N, deref_type, const deref_type &, CoordinateStride>
469 iterator_type;
470 };
471
472 template <unsigned N, class S>
473 struct MultiIteratorStrideTraits<CoordinateStride<N, S> >
474 {
475 typedef typename S::stride_type stride_type;
476 typedef typename S::stride_array_type stride_array_type;
477 typedef typename S::shape_array_type shape_array_type;
478 static stride_array_type shift(const stride_array_type & s, unsigned d)
479 {
480 stride_array_type ret;
481 for (unsigned i = d; i != N; ++i)
482 ret[i - d] = s[i];
483 return ret;
484 }
485 };
486
487 template <unsigned N>
488 struct CoordinateMultiIterator : public CoordinateStride<N>::iterator_type
489 {
490 typedef CoordinateStride<N> ptr_type;
491 typedef typename ptr_type::iterator_type base_type;
492 typedef typename ptr_type::stride_type stride_type;
493 typedef typename ptr_type::shape_array_type shape_array_type;
494 typedef typename ptr_type::coord_type coord_type;
495 typedef typename ptr_type::index_type index_type;
496
497 CoordinateMultiIterator(const stride_type & origin,
498 const stride_type & stride,
499 const index_type & shape)
500
501 : base_type(ptr_type(origin, stride.dim0()),
502 detail::dismember<N>(stride),
503 detail::dismember<N>(shape)) {}
504
505 CoordinateMultiIterator(const base_type & x) : base_type(x) {}
506 };
507
508 namespace detail {
509
510 template<unsigned N>
511 struct CoordinateMultiRangeReturns
512 {
513 typedef CoordinateMultiIterator<N> iterator_type;
514 typedef typename iterator_type::coord_type coord_type;
515 typedef StridePair<N> pair_type;
516 typedef typename pair_type::type stride_type;
517 typedef typename pair_type::stride_array_type stride_array_type;
518
519 typedef typename AccessorTraits<coord_type>::default_const_accessor
520 access_type;
521 typedef triple<iterator_type, stride_array_type, access_type> type;
522 };
523
524 } // namespace detail
525
526 template <unsigned N>
527 typename detail::CoordinateMultiRangeReturns<N>::type
528 coordinateMultiRange(const typename MultiArrayShape<N>::type & shape,
529 const TinyVector<double, N> & stride
530 = TinyVector<double, N>(1.0),
531 const TinyVector<double, N> & origin
532 = TinyVector<double, N>(0.0))
533 {
534 typedef typename
535 detail::CoordinateMultiRangeReturns<N>::stride_type stride_type;
536 typedef typename
537 detail::CoordinateMultiRangeReturns<N>::access_type access_type;
538
539 return typename detail::CoordinateMultiRangeReturns<N>::type
540 (CoordinateMultiIterator<N>(stride_type(0, origin),
541 stride_type(1, stride),
542 shape),
543 detail::dismember<N>(stride_type(shape)),
544 access_type());
545 }
546
547 template <unsigned N, class T>
548 struct CombinedMultiIterator
549 : public CoordinateStride<N, StridePairPointer<N, T> >::iterator_type
550 {
551 typedef StridePairPointer<N, T> pair_type;
552 typedef CoordinateStride<N, pair_type> ptr_type;
553 typedef typename ptr_type::iterator_type base_type;
554 typedef typename ptr_type::stride_type stride_type;
555 typedef typename ptr_type::coord_type coord_type;
556 typedef typename pair_type::shape_array_type shape_array_type;
557
558 CombinedMultiIterator(const T* raw_pointer,
559 const stride_type & origin,
560 const TinyVector<MultiArrayIndex, N> & pointer_stride,
561 const stride_type & stride,
562 const shape_array_type & shape)
563
564 : base_type(ptr_type(pair_type(raw_pointer, origin), stride.dim0()),
565 detail::dismember<N>(pointer_stride, stride),
566 shape) {}
567
568 CombinedMultiIterator(const base_type & x) : base_type(x) {}
569 };
570
571 template<unsigned N, class T>
572 struct SrcCoordinateMultiArrayRangeReturns
573 {
574 typedef CombinedMultiIterator<N, T> iterator_type;
575 typedef typename iterator_type::coord_type coord_type;
576 typedef typename iterator_type::pair_type pair_type;
577 typedef typename iterator_type::ptr_type ptr_type;
578 typedef typename ptr_type::deref_type deref_type;
579 typedef typename iterator_type::stride_type stride_type;
580 typedef typename pair_type::stride_array_type stride_array_type;
581 typedef typename pair_type::shape_array_type shape_array_type;
582
583 typedef typename AccessorTraits<deref_type>::default_const_accessor
584 access_type;
585 typedef triple<iterator_type, stride_array_type, access_type> type;
586 };
587
588 // work around GCC 4.4.3 template argument deduction bug:
589 template<unsigned N>
590 struct CoordinateSteps
591 {
592 typedef const TinyVector<double, N> & type;
593 };
594
595 template <unsigned int N, class T, class StrideTag>
596 inline typename SrcCoordinateMultiArrayRangeReturns<N, T>::type
597 srcCoordinateMultiArrayRange(const MultiArrayView<N, T, StrideTag> & array,
598 typename CoordinateSteps<N>::type stride
599 = TinyVector<double, N>(1.0),
600 typename CoordinateSteps<N>::type origin
601 = TinyVector<double, N>(0.0))
602 {
603 typedef SrcCoordinateMultiArrayRangeReturns<N, T> returns;
604 typedef typename returns::type type;
605 typedef typename returns::stride_type stride_type;
606 typedef typename returns::access_type access_type;
607 typedef typename returns::iterator_type iterator_type;
608 typedef typename returns::shape_array_type shape_array_type;
609
610 shape_array_type shape = array.shape();
611 return type(iterator_type(array.traverser_begin().get(),
612 stride_type(origin),
613 array.stride(),
614 stride_type(stride),
615 shape),
616 detail::dismember<N>(stride_type(shape)),
617 access_type());
618 }
619
620 template <class VALUETYPE, class COORD>
621 struct AccessorCoordinatePair
622 {
623 typedef VALUETYPE value_type;
624 typedef COORD coord_type;
625 typedef AccessorCoordinatePair type;
626
627 value_type v;
628 const coord_type & c;
629
630 AccessorCoordinatePair(const value_type & v_, const coord_type & c_)
631 : v(v_), c(c_) {}
632
633 const value_type & value() const
634 {
635 return v;
636 }
637 const coord_type & coord() const
638 {
639 return c;
640 }
641 };
642
643 /** \brief Forward accessor to the value() part of the values an iterator
644 points to.
645
646 CoordinateConstValueAccessor is a accessor that forwards
647 the underlying accessor's operator() read functions.
648 It passes its arguments <em>by value</em>.
649
650 <b>\#include</b> <vigra/coordinate_iterator.hxx><br>
651 Namespace: vigra
652 */
653 template <class Accessor, class COORD>
654 class CoordinateConstValueAccessor
655 {
656 public:
657 typedef typename Accessor::value_type forward_type;
658 typedef AccessorCoordinatePair<forward_type, COORD> value_type;
659 Accessor a;
660 CoordinateConstValueAccessor(const Accessor & a_) : a(a_) {}
661 /** Read the current data item.
662 */
663 template <class ITERATOR>
664 value_type operator()(ITERATOR const & i) const
665 {
666 const typename ITERATOR::value_type & x = *i;
667 return value_type(a(&x.value()), x.coord());
668 }
669 /** Read the data item at an offset.
670 */
671 template <class ITERATOR, class DIFFERENCE>
672 value_type operator()(ITERATOR const & i, DIFFERENCE const & diff) const
673 {
674 const typename ITERATOR::value_type & x = i[diff];
675 return value_type(a(&x.value()), x.coord());
676 }
677 };
678
679 template<unsigned N, class T, class Accessor>
680 struct SrcCoordinateMultiArrayRangeAccessorReturns
681 {
682 typedef CombinedMultiIterator<N, T> iterator_type;
683 typedef typename iterator_type::coord_type coord_type;
684 typedef typename iterator_type::pair_type pair_type;
685 typedef typename iterator_type::ptr_type ptr_type;
686 typedef typename ptr_type::deref_type deref_type;
687 typedef typename iterator_type::stride_type stride_type;
688 typedef typename pair_type::stride_array_type stride_array_type;
689 typedef typename pair_type::shape_array_type shape_array_type;
690
691 typedef CoordinateConstValueAccessor<Accessor, coord_type> access_type;
692 typedef triple<iterator_type, stride_array_type, access_type> type;
693 };
694
695 template <unsigned int N, class T, class StrideTag, class Access>
696 inline typename SrcCoordinateMultiArrayRangeAccessorReturns<N, T, Access>::type
697 srcCoordinateMultiArrayRangeAccessor(const MultiArrayView<N, T, StrideTag> &
698 array,
699 Access a,
700 typename CoordinateSteps<N>::type stride
701 = TinyVector<double, N>(1.0),
702 typename CoordinateSteps<N>::type origin
703 = TinyVector<double, N>(0.0))
704 {
705 typedef SrcCoordinateMultiArrayRangeAccessorReturns<N, T, Access> returns;
706 typedef typename returns::type type;
707 typedef typename returns::stride_type stride_type;
708 typedef typename returns::access_type access_type;
709 typedef typename returns::iterator_type iterator_type;
710 typedef typename returns::shape_array_type shape_array_type;
711
712 shape_array_type shape = array.shape();
713 return type(iterator_type(array.traverser_begin().get(),
714 stride_type(origin),
715 array.stride(),
716 stride_type(stride),
717 shape),
718 detail::dismember<N>(stride_type(shape)),
719 access_type(a));
720 }
721
722 } // namespace vigra
723
724 namespace std {
725
726 template <unsigned N>
727 ostream &
728 operator<<(ostream & os, const vigra::StridePair<N> & x)
729 {
730 os << "[" << x.index << ", " << x.coord << "]";
731 return os;
732 }
733
734 template <unsigned N>
735 ostream &
736 operator<<(ostream & os, const vigra::StridePairDiff<N> & x)
737 {
738 os << "<" << x.c << "; "
739 << static_cast<vigra::StridePairCoord<N> >(x) << ">";
740 return os;
741 }
742
743 template <unsigned N, class T>
744 ostream &
745 operator<<(ostream & os, const vigra::StridePairPointer<N, T> & x)
746 {
747 os << "[" << x.value() << ", " << x.coord() << "]";
748 return os;
749 }
750
751 template <class VALUETYPE, class COORD>
752 ostream &
753 operator<<(ostream & os,
754 const vigra::AccessorCoordinatePair<VALUETYPE, COORD> & x)
755 {
756 os << "[" << x.value() << ", " << x.coord() << "]";
757 return os;
758 }
759
760 } // namespace std
761
762 #endif // VIGRA_COORDINATE_ITERATOR_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.10.0 (Mon Nov 18 2013)