comparison tango/tango/util/collection/ArraySeq.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
comparison
equal deleted inserted replaced
131:5825d48b27d1 132:1700239cab2e
1 /*
2 File: ArraySeq.d
3
4 Originally written by Doug Lea and released into the public domain.
5 Thanks for the assistance and support of Sun Microsystems Labs, Agorics
6 Inc, Loral, and everyone contributing, testing, and using this code.
7
8 History:
9 Date Who What
10 2Oct95 dl@cs.oswego.edu refactored from DASeq.d
11 13Oct95 dl Changed protection statuses
12
13 */
14
15
16 module tango.util.collection.ArraySeq;
17
18 private import tango.util.collection.model.Iterator,
19 tango.util.collection.model.Sortable,
20 tango.util.collection.model.Comparator,
21 tango.util.collection.model.GuardIterator;
22
23 private import tango.util.collection.impl.SeqCollection,
24 tango.util.collection.impl.AbstractIterator;
25
26
27 /**
28 *
29 * Dynamically allocated and resized Arrays.
30 *
31 * Beyond implementing its interfaces, adds methods
32 * to adjust capacities. The default heuristics for resizing
33 * usually work fine, but you can adjust them manually when
34 * you need to.
35 *
36 * ArraySeqs are generally like java.util.Vectors. But unlike them,
37 * ArraySeqs do not actually allocate arrays when they are constructed.
38 * Among other consequences, you can adjust the capacity `for free'
39 * after construction but before adding elements. You can adjust
40 * it at other times as well, but this may lead to more expensive
41 * resizing. Also, unlike Vectors, they release their internal arrays
42 * whenever they are empty.
43 *
44 *
45 author: Doug Lea
46 * @version 0.93
47 *
48 * <P> For an introduction to this package see <A HREF="index.html"> Overview </A>.
49 *
50 **/
51
52 public class ArraySeq(T) : SeqCollection!(T), Sortable!(T)
53 {
54 alias SeqCollection!(T).remove remove;
55 alias SeqCollection!(T).removeAll removeAll;
56
57 /**
58 * The minimum capacity of any non-empty buffer
59 **/
60
61 public static int minCapacity = 16;
62
63
64 // instance variables
65
66 /**
67 * The elements, or null if no buffer yet allocated.
68 **/
69
70 package T array[];
71
72
73 // constructors
74
75 /**
76 * Make a new empty ArraySeq.
77 **/
78
79 public this ()
80 {
81 this (null, null, 0);
82 }
83
84 /**
85 * Make an empty ArraySeq with given element screener
86 **/
87
88 public this (Predicate screener)
89 {
90 this (screener, null, 0);
91 }
92
93 /**
94 * Special version of constructor needed by clone()
95 **/
96 package this (Predicate s, T[] b, int c)
97 {
98 super(s);
99 array = b;
100 count = c;
101 }
102
103 /**
104 * Make an independent copy. The elements themselves are not cloned
105 **/
106
107 public final ArraySeq duplicate()
108 {
109 int cap = count;
110 if (cap is 0)
111 return new ArraySeq (screener, null, 0);
112 else
113 {
114 if (cap < minCapacity)
115 cap = minCapacity;
116
117 T newArray[] = new T[cap];
118 //System.copy (array[0].sizeof, array, 0, newArray, 0, count);
119
120 newArray[0..count] = array[0..count];
121 return new ArraySeq!(T)(screener, newArray, count);
122 }
123 }
124
125 // methods introduced _in ArraySeq
126
127 /**
128 * return the current internal buffer capacity (zero if no buffer allocated).
129 * Returns: capacity (always greater than or equal to size())
130 **/
131
132 public final int capacity()
133 {
134 return (array is null) ? 0 : array.length;
135 }
136
137 /**
138 * Set the internal buffer capacity to max(size(), newCap).
139 * That is, if given an argument less than the current
140 * number of elements, the capacity is just set to the
141 * current number of elements. Thus, elements are never lost
142 * by setting the capacity.
143 *
144 * @param newCap the desired capacity.
145 * Returns: condition:
146 * <PRE>
147 * capacity() >= size() &&
148 * version() != PREV(this).version() == (capacity() != PREV(this).capacity())
149 * </PRE>
150 **/
151
152 public final void capacity(int newCap)
153 {
154 if (newCap < count)
155 newCap = count;
156
157 if (newCap is 0)
158 {
159 clear();
160 }
161 else
162 if (array is null)
163 {
164 array = new T[newCap];
165 incVersion();
166 }
167 else
168 if (newCap !is array.length)
169 {
170 //T newArray[] = new T[newCap];
171 //newArray[0..count] = array[0..count];
172 //array = newArray;
173 array ~= new T[newCap - array.length];
174 incVersion();
175 }
176 }
177
178
179 // Collection methods
180
181 /**
182 * Implements tango.util.collection.impl.Collection.Collection.contains
183 * Time complexity: O(n).
184 * See_Also: tango.util.collection.impl.Collection.Collection.contains
185 **/
186 public final bool contains(T element)
187 {
188 if (! isValidArg (element))
189 return false;
190
191 for (int i = 0; i < count; ++i)
192 if (array[i] == (element))
193 return true;
194 return false;
195 }
196
197 /**
198 * Implements tango.util.collection.impl.Collection.Collection.instances
199 * Time complexity: O(n).
200 * See_Also: tango.util.collection.impl.Collection.Collection.instances
201 **/
202 public final uint instances(T element)
203 {
204 if (! isValidArg(element))
205 return 0;
206
207 uint c = 0;
208 for (uint i = 0; i < count; ++i)
209 if (array[i] == (element))
210 ++c;
211 return c;
212 }
213
214 /**
215 * Implements tango.util.collection.impl.Collection.Collection.elements
216 * Time complexity: O(1).
217 * See_Also: tango.util.collection.impl.Collection.Collection.elements
218 **/
219 public final GuardIterator!(T) elements()
220 {
221 return new ArrayIterator!(T)(this);
222 }
223
224 /**
225 * Implements tango.util.collection.model.View.View.opApply
226 * Time complexity: O(n).
227 * See_Also: tango.util.collection.model.View.View.opApply
228 **/
229 int opApply (int delegate (inout T value) dg)
230 {
231 auto scope iterator = new ArrayIterator!(T)(this);
232 return iterator.opApply (dg);
233 }
234
235
236 // Seq methods:
237
238 /**
239 * Implements tango.util.collection.model.Seq.Seq.head.
240 * Time complexity: O(1).
241 * See_Also: tango.util.collection.model.Seq.Seq.head
242 **/
243 public final T head()
244 {
245 checkIndex(0);
246 return array[0];
247 }
248
249 /**
250 * Implements tango.util.collection.model.Seq.Seq.tail.
251 * Time complexity: O(1).
252 * See_Also: tango.util.collection.model.Seq.Seq.tail
253 **/
254 public final T tail()
255 {
256 checkIndex(count -1);
257 return array[count -1];
258 }
259
260 /**
261 * Implements tango.util.collection.model.Seq.Seq.get.
262 * Time complexity: O(1).
263 * See_Also: tango.util.collection.model.Seq.Seq.get
264 **/
265 public final T get(int index)
266 in {
267 checkIndex(index);
268 }
269 body
270 {
271 return array[index];
272 }
273
274 /**
275 * Implements tango.util.collection.model.Seq.Seq.first.
276 * Time complexity: O(n).
277 * See_Also: tango.util.collection.model.Seq.Seq.first
278 **/
279 public final int first(T element, int startingIndex = 0)
280 {
281 if (startingIndex < 0)
282 startingIndex = 0;
283
284 for (int i = startingIndex; i < count; ++i)
285 if (array[i] == (element))
286 return i;
287 return -1;
288 }
289
290 /**
291 * Implements tango.util.collection.model.Seq.Seq.last.
292 * Time complexity: O(n).
293 * See_Also: tango.util.collection.model.Seq.Seq.last
294 **/
295 public final int last(T element, int startingIndex = 0)
296 {
297 if (startingIndex >= count)
298 startingIndex = count -1;
299
300 for (int i = startingIndex; i >= 0; --i)
301 if (array[i] == (element))
302 return i;
303 return -1;
304 }
305
306
307 /**
308 * Implements tango.util.collection.model.Seq.Seq.subseq.
309 * Time complexity: O(length).
310 * See_Also: tango.util.collection.model.Seq.Seq.subseq
311 **/
312 public final ArraySeq subset (int from, int _length)
313 {
314 if (_length > 0)
315 {
316 checkIndex(from);
317 checkIndex(from + _length - 1);
318
319 T newArray[] = new T[_length];
320 //System.copy (array[0].sizeof, array, from, newArray, 0, _length);
321
322 newArray[0.._length] = array[from..from+_length];
323 return new ArraySeq!(T)(screener, newArray, _length);
324 }
325 else
326 return new ArraySeq!(T)(screener);
327 }
328
329
330 // MutableCollection methods
331
332 /**
333 * Implements tango.util.collection.impl.Collection.Collection.clear.
334 * Time complexity: O(1).
335 * See_Also: tango.util.collection.impl.Collection.Collection.clear
336 **/
337 public final void clear()
338 {
339 array = null;
340 setCount(0);
341 }
342
343 /**
344 * Implements tango.util.collection.impl.Collection.Collection.removeOneOf.
345 * Time complexity: O(n).
346 * See_Also: tango.util.collection.impl.Collection.Collection.removeOneOf
347 **/
348 public final void remove(T element)
349 {
350 remove_(element, false);
351 }
352
353
354 /**
355 * Implements tango.util.collection.impl.Collection.Collection.replaceOneOf
356 * Time complexity: O(n).
357 * See_Also: tango.util.collection.impl.Collection.Collection.replaceOneOf
358 **/
359 public final void replace(T oldElement, T newElement)
360 {
361 replace_(oldElement, newElement, false);
362 }
363
364 /**
365 * Implements tango.util.collection.impl.Collection.Collection.replaceAllOf.
366 * Time complexity: O(n * number of replacements).
367 * See_Also: tango.util.collection.impl.Collection.Collection.replaceAllOf
368 **/
369 public final void replaceAll(T oldElement, T newElement)
370 {
371 replace_(oldElement, newElement, true);
372 }
373
374 /**
375 * Implements tango.util.collection.impl.Collection.Collection.exclude.
376 * Time complexity: O(n * instances(element)).
377 * See_Also: tango.util.collection.impl.Collection.Collection.exclude
378 **/
379 public final void removeAll(T element)
380 {
381 remove_(element, true);
382 }
383
384 /**
385 * Implements tango.util.collection.impl.Collection.Collection.take.
386 * Time complexity: O(1).
387 * Takes the rightmost element of the array.
388 * See_Also: tango.util.collection.impl.Collection.Collection.take
389 **/
390 public final T take()
391 {
392 T v = tail();
393 removeTail();
394 return v;
395 }
396
397
398 // SortableCollection methods:
399
400
401 /**
402 * Implements tango.util.collection.SortableCollection.sort.
403 * Time complexity: O(n log n).
404 * Uses a quicksort-based algorithm.
405 * See_Also: tango.util.collection.SortableCollection.sort
406 **/
407 public void sort(Comparator!(T) cmp)
408 {
409 if (count > 0)
410 {
411 quickSort(array, 0, count - 1, cmp);
412 incVersion();
413 }
414 }
415
416
417 // MutableSeq methods
418
419 /**
420 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.prepend.
421 * Time complexity: O(n)
422 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.prepend
423 **/
424 public final void prepend(T element)
425 {
426 checkElement(element);
427 growBy_(1);
428 for (int i = count -1; i > 0; --i)
429 array[i] = array[i - 1];
430 array[0] = element;
431 }
432
433 /**
434 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.replaceHead.
435 * Time complexity: O(1).
436 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.replaceHead
437 **/
438 public final void replaceHead(T element)
439 {
440 checkElement(element);
441 array[0] = element;
442 incVersion();
443 }
444
445 /**
446 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.removeHead.
447 * Time complexity: O(n).
448 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.removeHead
449 **/
450 public final void removeHead()
451 {
452 removeAt(0);
453 }
454
455 /**
456 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.append.
457 * Time complexity: normally O(1), but O(n) if size() == capacity().
458 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.append
459 **/
460 public final void append(T element)
461 in {
462 checkElement (element);
463 }
464 body
465 {
466 int last = count;
467 growBy_(1);
468 array[last] = element;
469 }
470
471 /**
472 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.replaceTail.
473 * Time complexity: O(1).
474 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.replaceTail
475 **/
476 public final void replaceTail(T element)
477 {
478 checkElement(element);
479 array[count -1] = element;
480 incVersion();
481 }
482
483 /**
484 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.removeTail.
485 * Time complexity: O(1).
486 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.removeTail
487 **/
488 public final void removeTail()
489 {
490 checkIndex(0);
491 array[count -1] = T.init;
492 growBy_( -1);
493 }
494
495 /**
496 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.addAt.
497 * Time complexity: O(n).
498 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.addAt
499 **/
500 public final void addAt(int index, T element)
501 {
502 if (index !is count)
503 checkIndex(index);
504
505 checkElement(element);
506 growBy_(1);
507 for (int i = count -1; i > index; --i)
508 array[i] = array[i - 1];
509 array[index] = element;
510 }
511
512 /**
513 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.remove.
514 * Time complexity: O(n).
515 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.removeAt
516 **/
517 public final void removeAt(int index)
518 {
519 checkIndex(index);
520 for (int i = index + 1; i < count; ++i)
521 array[i - 1] = array[i];
522 array[count -1] = T.init;
523 growBy_( -1);
524 }
525
526
527 /**
528 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.replaceAt.
529 * Time complexity: O(1).
530 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.replaceAt
531 **/
532 public final void replaceAt(int index, T element)
533 {
534 checkIndex(index);
535 checkElement(element);
536 array[index] = element;
537 incVersion();
538 }
539
540 /**
541 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.prepend.
542 * Time complexity: O(n + number of elements in e) if (e
543 * instanceof CollectionIterator) else O(n * number of elements in e)
544 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.prepend
545 **/
546 public final void prepend(Iterator!(T) e)
547 {
548 insert_(0, e);
549 }
550
551 /**
552 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.append.
553 * Time complexity: O(number of elements in e)
554 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.append
555 **/
556 public final void append(Iterator!(T) e)
557 {
558 insert_(count, e);
559 }
560
561 /**
562 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.addAt.
563 * Time complexity: O(n + number of elements in e) if (e
564 * instanceof CollectionIterator) else O(n * number of elements in e)
565 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.addAt
566 **/
567 public final void addAt(int index, Iterator!(T) e)
568 {
569 if (index !is count)
570 checkIndex(index);
571 insert_(index, e);
572 }
573
574
575 /**
576 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.removeFromTo.
577 * Time complexity: O(n).
578 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.removeFromTo
579 **/
580 public final void removeRange (int fromIndex, int toIndex)
581 {
582 checkIndex(fromIndex);
583 checkIndex(toIndex);
584 if (fromIndex <= toIndex)
585 {
586 int gap = toIndex - fromIndex + 1;
587 int j = fromIndex;
588 for (int i = toIndex + 1; i < count; ++i)
589 array[j++] = array[i];
590
591 for (int i = 1; i <= gap; ++i)
592 array[count -i] = T.init;
593 addToCount( -gap);
594 }
595 }
596
597 /**
598 * An implementation of Quicksort using medians of 3 for partitions.
599 * Used internally by sort.
600 * It is public and static so it can be used to sort plain
601 * arrays as well.
602 * @param s, the array to sort
603 * @param lo, the least index to sort from
604 * @param hi, the greatest index
605 * @param cmp, the comparator to use for comparing elements
606 **/
607
608 public final static void quickSort(T s[], int lo, int hi, Comparator!(T) cmp)
609 {
610 if (lo >= hi)
611 return;
612
613 /*
614 Use median-of-three(lo, mid, hi) to pick a partition.
615 Also swap them into relative order while we are at it.
616 */
617
618 int mid = (lo + hi) / 2;
619
620 if (cmp.compare(s[lo], s[mid]) > 0)
621 {
622 T tmp = s[lo];
623 s[lo] = s[mid];
624 s[mid] = tmp; // swap
625 }
626
627 if (cmp.compare(s[mid], s[hi]) > 0)
628 {
629 T tmp = s[mid];
630 s[mid] = s[hi];
631 s[hi] = tmp; // swap
632
633 if (cmp.compare(s[lo], s[mid]) > 0)
634 {
635 T tmp2 = s[lo];
636 s[lo] = s[mid];
637 s[mid] = tmp2; // swap
638 }
639 }
640
641 int left = lo + 1; // start one past lo since already handled lo
642 int right = hi - 1; // similarly
643 if (left >= right)
644 return; // if three or fewer we are done
645
646 T partition = s[mid];
647
648 for (;;)
649 {
650 while (cmp.compare(s[right], partition) > 0)
651 --right;
652
653 while (left < right && cmp.compare(s[left], partition) <= 0)
654 ++left;
655
656 if (left < right)
657 {
658 T tmp = s[left];
659 s[left] = s[right];
660 s[right] = tmp; // swap
661 --right;
662 }
663 else
664 break;
665 }
666
667 quickSort(s, lo, left, cmp);
668 quickSort(s, left + 1, hi, cmp);
669 }
670
671 /***********************************************************************
672
673 expose collection content as an array
674
675 ************************************************************************/
676
677 override public T[] toArray ()
678 {
679 return array[0..count].dup;
680 }
681
682 // helper methods
683
684 /**
685 * Main method to control buffer sizing.
686 * The heuristic used for growth is:
687 * <PRE>
688 * if out of space:
689 * if need less than minCapacity, grow to minCapacity
690 * else grow by average of requested size and minCapacity.
691 * </PRE>
692 * <P>
693 * For small buffers, this causes them to be about 1/2 full.
694 * while for large buffers, it causes them to be about 2/3 full.
695 * <P>
696 * For shrinkage, the only thing we do is unlink the buffer if it is empty.
697 * @param inc, the amount of space to grow by. Negative values mean shrink.
698 * Returns: condition: adjust record of count, and if any of
699 * the above conditions apply, allocate and copy into a new
700 * buffer of the appropriate size.
701 **/
702
703 private final void growBy_(int inc)
704 {
705 int needed = count + inc;
706 if (inc > 0)
707 {
708 /* heuristic: */
709 int current = capacity();
710 if (needed > current)
711 {
712 incVersion();
713 int newCap = needed + (needed + minCapacity) / 2;
714
715 if (newCap < minCapacity)
716 newCap = minCapacity;
717
718 if (array is null)
719 {
720 array = new T[newCap];
721 }
722 else
723 {
724 //T newArray[] = new T[newCap];
725 //newArray[0..count] = array[0..count];
726 //array = newArray;
727 array ~= new T[newCap - array.length];
728 }
729 }
730 }
731 else
732 if (needed is 0)
733 array = null;
734
735 setCount(needed);
736 }
737
738
739 /**
740 * Utility to splice in enumerations
741 **/
742
743 private final void insert_(int index, Iterator!(T) e)
744 {
745 if (cast(GuardIterator!(T)) e)
746 {
747 // we know size!
748 int inc = (cast(GuardIterator!(T)) (e)).remaining();
749 int oldcount = count;
750 int oldversion = vershion;
751 growBy_(inc);
752
753 for (int i = oldcount - 1; i >= index; --i)
754 array[i + inc] = array[i];
755
756 int j = index;
757 while (e.more())
758 {
759 T element = e.get();
760 if (!allows (element))
761 { // Ugh. Can only do full rollback
762 for (int i = index; i < oldcount; ++i)
763 array[i] = array[i + inc];
764
765 vershion = oldversion;
766 count = oldcount;
767 checkElement(element); // force throw
768 }
769 array[j++] = element;
770 }
771 }
772 else
773 if (index is count)
774 { // next best; we can append
775 while (e.more())
776 {
777 T element = e.get();
778 checkElement(element);
779 growBy_(1);
780 array[count -1] = element;
781 }
782 }
783 else
784 { // do it the slow way
785 int j = index;
786 while (e.more())
787 {
788 T element = e.get();
789 checkElement(element);
790 growBy_(1);
791
792 for (int i = count -1; i > j; --i)
793 array[i] = array[i - 1];
794 array[j++] = element;
795 }
796 }
797 }
798
799 private final void remove_(T element, bool allOccurrences)
800 {
801 if (! isValidArg(element))
802 return;
803
804 for (int i = 0; i < count; ++i)
805 {
806 while (i < count && array[i] == (element))
807 {
808 for (int j = i + 1; j < count; ++j)
809 array[j - 1] = array[j];
810
811 array[count -1] = T.init;
812 growBy_( -1);
813
814 if (!allOccurrences || count is 0)
815 return ;
816 }
817 }
818 }
819
820 private final void replace_(T oldElement, T newElement, bool allOccurrences)
821 {
822 if (isValidArg(oldElement) is false || count is 0)
823 return;
824
825 for (int i = 0; i < count; ++i)
826 {
827 if (array[i] == (oldElement))
828 {
829 checkElement(newElement);
830 array[i] = newElement;
831 incVersion();
832
833 if (! allOccurrences)
834 return;
835 }
836 }
837 }
838
839 /**
840 * Implements tango.util.collection.model.View.View.checkImplementation.
841 * See_Also: tango.util.collection.model.View.View.checkImplementation
842 **/
843 public override void checkImplementation()
844 {
845 super.checkImplementation();
846 assert(!(array is null && count !is 0));
847 assert((array is null || count <= array.length));
848
849 for (int i = 0; i < count; ++i)
850 {
851 assert(allows(array[i]));
852 assert(instances(array[i]) > 0);
853 assert(contains(array[i]));
854 }
855 }
856
857 /***********************************************************************
858
859 opApply() has migrated here to mitigate the virtual call
860 on method get()
861
862 ************************************************************************/
863
864 static class ArrayIterator(T) : AbstractIterator!(T)
865 {
866 private int row;
867 private T[] array;
868
869 public this (ArraySeq seq)
870 {
871 super (seq);
872 array = seq.array;
873 }
874
875 public final T get()
876 {
877 decRemaining();
878 return array[row++];
879 }
880
881 int opApply (int delegate (inout T value) dg)
882 {
883 int result;
884
885 for (auto i=remaining(); i--;)
886 {
887 auto value = get();
888 if ((result = dg(value)) != 0)
889 break;
890 }
891 return result;
892 }
893 }
894 }
895
896
897
898 debug (Test)
899 {
900 import tango.io.Console;
901
902 void main()
903 {
904 auto array = new ArraySeq!(char[]);
905 array.append ("foo");
906 array.append ("bar");
907 array.append ("wumpus");
908
909 foreach (value; array.elements) {}
910
911 auto elements = array.elements();
912 while (elements.more)
913 auto v = elements.get();
914
915 foreach (value; array)
916 Cout (value).newline;
917
918 auto a = array.toArray;
919 foreach (value; a)
920 Cout (value).newline;
921
922 array.checkImplementation();
923 }
924 }