• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 /**
18  * @author Igor V. Stolyarov
19  * @version $Revision$
20  */
21 
22 package java.awt.image;
23 
24 import java.util.Arrays;
25 
26 import org.apache.harmony.awt.internal.nls.Messages;
27 
28 /**
29  * The ComponentSampleModel class represents a set of image data whose each
30  * element - the sample of a pixel - takes one data element of the DataBuffer.
31  * <p>
32  * The Bank indices denote the correspondence between the bank of data buffers
33  * and a band of image data. The Pixel stride is the number of data array
34  * elements between two samples for the same band on the same scanline. The
35  * pixel stride for a BandedSampleModel is one. The scanline stride represents
36  * the number of data array elements between a specified sample and the
37  * corresponding sample in the same column in the next scanline. The array of
38  * band offsets gives the starting offsets within each data banks of the in the
39  * DataBuffer. The bank indices represents the indices within each bank of the
40  * DataBuffer corresponding to a band of image data.
41  *
42  * @since Android 1.0
43  */
44 public class ComponentSampleModel extends SampleModel {
45 
46     /**
47      * The band offsets array of this ComponentSampleModel.
48      */
49     protected int bandOffsets[];
50 
51     /**
52      * The bank indices array of this ComponentSampleModel.
53      */
54     protected int bankIndices[];
55 
56     /**
57      * The number of bands in this ComponentSampleModel.
58      */
59     protected int numBands;
60 
61     /**
62      * The number banks of this ComponentSampleModel.
63      */
64     protected int numBanks;
65 
66     /**
67      * The scanline stride of this ComponentSampleModel.
68      */
69     protected int scanlineStride;
70 
71     /**
72      * The pixel stride of this ComponentSampleModel.
73      */
74     protected int pixelStride;
75 
76     /**
77      * Instantiates a new ComponentSampleModel with the specified properties.
78      *
79      * @param dataType
80      *            the data type of samples.
81      * @param w
82      *            the width of the image data.
83      * @param h
84      *            the height of the image data.
85      * @param pixelStride
86      *            the pixel stride of the image data.
87      * @param scanlineStride
88      *            the scanline stride of the image data.
89      * @param bankIndices
90      *            the array of the bank indices.
91      * @param bandOffsets
92      *            the array of the band offsets.
93      */
ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, int bankIndices[], int bandOffsets[])94     public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride,
95             int bankIndices[], int bandOffsets[]) {
96 
97         super(dataType, w, h, bandOffsets.length);
98 
99         if (pixelStride < 0) {
100             // awt.24B=Pixel stride must be >= 0
101             throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$
102         }
103 
104         if (scanlineStride < 0) {
105             // awt.24C=Scanline stride must be >= 0
106             throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$
107         }
108 
109         if (bankIndices.length != bandOffsets.length) {
110             // awt.24D=Bank Indices length must be equal Bank Offsets length
111             throw new IllegalArgumentException(Messages.getString("awt.24D")); //$NON-NLS-1$
112         }
113 
114         this.pixelStride = pixelStride;
115         this.scanlineStride = scanlineStride;
116         this.bandOffsets = bandOffsets.clone();
117         this.bankIndices = bankIndices.clone();
118         this.numBands = bandOffsets.length;
119 
120         int maxBank = 0;
121         for (int i = 0; i < bankIndices.length; i++) {
122             if (bankIndices[i] < 0) {
123                 // awt.24E=Index of {0} bank must be >= 0
124                 throw new IllegalArgumentException(Messages.getString("awt.24E", i)); //$NON-NLS-1$
125             }
126             if (bankIndices[i] > maxBank) {
127                 maxBank = bankIndices[i];
128             }
129         }
130         this.numBanks = maxBank + 1;
131 
132     }
133 
134     /**
135      * Instantiates a new ComponentSampleModel with the specified properties.
136      *
137      * @param dataType
138      *            the data type of the samples.
139      * @param w
140      *            the width of the image data.
141      * @param h
142      *            the height of the image data.
143      * @param pixelStride
144      *            the pixel stride of the image data.
145      * @param scanlineStride
146      *            the scanline stride of the image data.
147      * @param bandOffsets
148      *            the band offsets.
149      */
ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, int bandOffsets[])150     public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride,
151             int bandOffsets[]) {
152 
153         super(dataType, w, h, bandOffsets.length);
154         if (pixelStride < 0) {
155             // awt.24B=Pixel stride must be >= 0
156             throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$
157         }
158 
159         if (scanlineStride < 0) {
160             // awt.24C=Scanline stride must be >= 0
161             throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$
162         }
163 
164         this.pixelStride = pixelStride;
165         this.scanlineStride = scanlineStride;
166         this.bandOffsets = bandOffsets.clone();
167         this.numBands = bandOffsets.length;
168         this.numBanks = 1;
169 
170         this.bankIndices = new int[numBands];
171         for (int i = 0; i < numBands; i++) {
172             bankIndices[i] = 0;
173         }
174     }
175 
176     @Override
getDataElements(int x, int y, Object obj, DataBuffer data)177     public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
178         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
179             // awt.63=Coordinates are not in bounds
180             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
181         }
182         switch (dataType) {
183             case DataBuffer.TYPE_BYTE:
184                 byte bdata[];
185                 if (obj == null) {
186                     bdata = new byte[numBands];
187                 } else {
188                     bdata = (byte[])obj;
189                 }
190 
191                 for (int i = 0; i < numBands; i++) {
192                     bdata[i] = (byte)getSample(x, y, i, data);
193                 }
194 
195                 obj = bdata;
196                 break;
197 
198             case DataBuffer.TYPE_SHORT:
199             case DataBuffer.TYPE_USHORT:
200                 short sdata[];
201                 if (obj == null) {
202                     sdata = new short[numBands];
203                 } else {
204                     sdata = (short[])obj;
205                 }
206 
207                 for (int i = 0; i < numBands; i++) {
208                     sdata[i] = (short)getSample(x, y, i, data);
209                 }
210 
211                 obj = sdata;
212                 break;
213 
214             case DataBuffer.TYPE_INT:
215                 int idata[];
216                 if (obj == null) {
217                     idata = new int[numBands];
218                 } else {
219                     idata = (int[])obj;
220                 }
221 
222                 for (int i = 0; i < numBands; i++) {
223                     idata[i] = getSample(x, y, i, data);
224                 }
225 
226                 obj = idata;
227                 break;
228 
229             case DataBuffer.TYPE_FLOAT:
230                 float fdata[];
231                 if (obj == null) {
232                     fdata = new float[numBands];
233                 } else {
234                     fdata = (float[])obj;
235                 }
236 
237                 for (int i = 0; i < numBands; i++) {
238                     fdata[i] = getSampleFloat(x, y, i, data);
239                 }
240 
241                 obj = fdata;
242                 break;
243 
244             case DataBuffer.TYPE_DOUBLE:
245                 double ddata[];
246                 if (obj == null) {
247                     ddata = new double[numBands];
248                 } else {
249                     ddata = (double[])obj;
250                 }
251 
252                 for (int i = 0; i < numBands; i++) {
253                     ddata[i] = getSampleDouble(x, y, i, data);
254                 }
255 
256                 obj = ddata;
257                 break;
258         }
259 
260         return obj;
261     }
262 
263     @Override
setDataElements(int x, int y, Object obj, DataBuffer data)264     public void setDataElements(int x, int y, Object obj, DataBuffer data) {
265         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
266             // awt.63=Coordinates are not in bounds
267             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
268         }
269         switch (dataType) {
270             case DataBuffer.TYPE_BYTE:
271                 byte barr[] = (byte[])obj;
272                 for (int i = 0; i < numBands; i++) {
273                     setSample(x, y, i, barr[i] & 0xff, data);
274                 }
275                 break;
276 
277             case DataBuffer.TYPE_SHORT:
278             case DataBuffer.TYPE_USHORT:
279                 short sarr[] = (short[])obj;
280                 for (int i = 0; i < numBands; i++) {
281                     setSample(x, y, i, sarr[i] & 0xffff, data);
282                 }
283                 break;
284 
285             case DataBuffer.TYPE_INT:
286                 int iarr[] = (int[])obj;
287                 for (int i = 0; i < numBands; i++) {
288                     setSample(x, y, i, iarr[i], data);
289                 }
290                 break;
291 
292             case DataBuffer.TYPE_FLOAT:
293                 float farr[] = (float[])obj;
294                 for (int i = 0; i < numBands; i++) {
295                     setSample(x, y, i, farr[i], data);
296                 }
297                 break;
298 
299             case DataBuffer.TYPE_DOUBLE:
300                 double darr[] = (double[])obj;
301                 for (int i = 0; i < numBands; i++) {
302                     setSample(x, y, i, darr[i], data);
303                 }
304                 break;
305         }
306     }
307 
308     /**
309      * Compares this ComponentSampleModel with the specified Object.
310      *
311      * @param o
312      *            the Object.
313      * @return true, if the object is a ComponentSampleModel with identical data
314      *         values to this ComponentSampleModel, false otherwise.
315      */
316     @Override
equals(Object o)317     public boolean equals(Object o) {
318         if ((o == null) || !(o instanceof ComponentSampleModel)) {
319             return false;
320         }
321         ComponentSampleModel model = (ComponentSampleModel)o;
322         return this.width == model.width && this.height == model.height
323                 && this.numBands == model.numBands && this.dataType == model.dataType
324                 && Arrays.equals(this.bandOffsets, model.bandOffsets)
325                 && Arrays.equals(this.bankIndices, model.bankIndices)
326                 && this.numBands == model.numBands && this.numBanks == model.numBanks
327                 && this.scanlineStride == model.scanlineStride
328                 && this.pixelStride == model.pixelStride;
329     }
330 
331     /**
332      * @see java.awt.image.SampleModel#createSubsetSampleModel(int[])
333      */
334     @Override
createSubsetSampleModel(int bands[])335     public SampleModel createSubsetSampleModel(int bands[]) {
336         if (bands.length > this.numBands) {
337             // awt.64=The number of the bands in the subset is greater than the
338             // number of bands in the sample model
339             throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
340         }
341 
342         int indices[] = new int[bands.length];
343         int offsets[] = new int[bands.length];
344 
345         for (int i = 0; i < bands.length; i++) {
346             indices[i] = bankIndices[bands[i]];
347             offsets[i] = bandOffsets[bands[i]];
348         }
349 
350         return new ComponentSampleModel(dataType, width, height, pixelStride, scanlineStride,
351                 indices, offsets);
352 
353     }
354 
355     @Override
createCompatibleSampleModel(int w, int h)356     public SampleModel createCompatibleSampleModel(int w, int h) {
357         return new ComponentSampleModel(dataType, w, h, pixelStride, pixelStride * w, bankIndices,
358                 bandOffsets);
359     }
360 
361     @Override
getPixel(int x, int y, int iArray[], DataBuffer data)362     public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
363         int pixel[];
364 
365         if (iArray == null) {
366             pixel = new int[numBands];
367         } else {
368             pixel = iArray;
369         }
370 
371         for (int i = 0; i < numBands; i++) {
372             pixel[i] = getSample(x, y, i, data);
373         }
374 
375         return pixel;
376     }
377 
378     @Override
setPixel(int x, int y, int iArray[], DataBuffer data)379     public void setPixel(int x, int y, int iArray[], DataBuffer data) {
380         for (int i = 0; i < numBands; i++) {
381             setSample(x, y, i, iArray[i], data);
382         }
383     }
384 
385     @Override
getSample(int x, int y, int b, DataBuffer data)386     public int getSample(int x, int y, int b, DataBuffer data) {
387         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
388             // awt.63=Coordinates are not in bounds
389             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
390         }
391 
392         return data.getElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b]);
393     }
394 
395     @Override
getSampleFloat(int x, int y, int b, DataBuffer data)396     public float getSampleFloat(int x, int y, int b, DataBuffer data) {
397         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
398             // awt.63=Coordinates are not in bounds
399             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
400         }
401 
402         return data.getElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride
403                 + bandOffsets[b]);
404     }
405 
406     @Override
getSampleDouble(int x, int y, int b, DataBuffer data)407     public double getSampleDouble(int x, int y, int b, DataBuffer data) {
408         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
409             // awt.63=Coordinates are not in bounds
410             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
411         }
412 
413         return data.getElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride
414                 + bandOffsets[b]);
415     }
416 
417     @Override
getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data)418     public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
419         if (x < 0 || y < 0 || x > this.width || x + w > this.width || y > this.height
420                 || y + h > this.height) {
421             // awt.63=Coordinates are not in bounds
422             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
423         }
424         int pixels[] = null;
425         int idx = 0;
426 
427         if (iArray == null) {
428             pixels = new int[w * h * numBands];
429         } else {
430             pixels = iArray;
431         }
432 
433         for (int i = y; i < y + h; i++) {
434             for (int j = x; j < x + w; j++) {
435                 for (int n = 0; n < numBands; n++) {
436                     pixels[idx++] = getSample(j, i, n, data);
437                 }
438             }
439         }
440 
441         return pixels;
442     }
443 
444     @Override
setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data)445     public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
446         if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
447             // awt.63=Coordinates are not in bounds
448             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
449         }
450         int idx = 0;
451         for (int i = y; i < y + h; i++) {
452             for (int j = x; j < x + w; j++) {
453                 for (int n = 0; n < numBands; n++) {
454                     setSample(j, i, n, iArray[idx++], data);
455                 }
456             }
457         }
458     }
459 
460     @Override
setSample(int x, int y, int b, int s, DataBuffer data)461     public void setSample(int x, int y, int b, int s, DataBuffer data) {
462         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
463             // awt.63=Coordinates are not in bounds
464             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
465         }
466 
467         data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s);
468     }
469 
470     @Override
getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data)471     public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
472         if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
473             // awt.63=Coordinates are not in bounds
474             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
475         }
476         int samples[];
477         int idx = 0;
478 
479         if (iArray == null) {
480             samples = new int[w * h];
481         } else {
482             samples = iArray;
483         }
484 
485         if (data == null) {
486             // awt.295=data is null
487             throw new NullPointerException(Messages.getString("awt.295")); //$NON-NLS-1$
488         }
489 
490         for (int i = y; i < y + h; i++) {
491             for (int j = x; j < x + w; j++) {
492                 samples[idx++] = getSample(j, i, b, data);
493             }
494         }
495 
496         return samples;
497     }
498 
499     @Override
setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data)500     public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
501         if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
502             // awt.63=Coordinates are not in bounds
503             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
504         }
505         int idx = 0;
506         for (int i = y; i < y + h; i++) {
507             for (int j = x; j < x + w; j++) {
508                 setSample(j, i, b, iArray[idx++], data);
509             }
510         }
511     }
512 
513     @Override
setSample(int x, int y, int b, float s, DataBuffer data)514     public void setSample(int x, int y, int b, float s, DataBuffer data) {
515         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
516             // awt.63=Coordinates are not in bounds
517             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
518         }
519 
520         data.setElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s);
521     }
522 
523     @Override
setSample(int x, int y, int b, double s, DataBuffer data)524     public void setSample(int x, int y, int b, double s, DataBuffer data) {
525         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
526             // awt.63=Coordinates are not in bounds
527             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
528         }
529 
530         data
531                 .setElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride
532                         + bandOffsets[b], s);
533     }
534 
535     @Override
createDataBuffer()536     public DataBuffer createDataBuffer() {
537         DataBuffer data = null;
538 
539         int maxOffset = bandOffsets[0];
540         for (int i = 1; i < bandOffsets.length; i++) {
541             if (bandOffsets[i] > maxOffset) {
542                 maxOffset = bandOffsets[i];
543             }
544         }
545         int size = (height - 1) * scanlineStride + (width - 1) * pixelStride + maxOffset + 1;
546 
547         switch (dataType) {
548             case DataBuffer.TYPE_BYTE:
549                 data = new DataBufferByte(size, numBanks);
550                 break;
551             case DataBuffer.TYPE_SHORT:
552                 data = new DataBufferShort(size, numBanks);
553                 break;
554             case DataBuffer.TYPE_USHORT:
555                 data = new DataBufferUShort(size, numBanks);
556                 break;
557             case DataBuffer.TYPE_INT:
558                 data = new DataBufferInt(size, numBanks);
559                 break;
560             case DataBuffer.TYPE_FLOAT:
561                 data = new DataBufferFloat(size, numBanks);
562                 break;
563             case DataBuffer.TYPE_DOUBLE:
564                 data = new DataBufferDouble(size, numBanks);
565                 break;
566         }
567 
568         return data;
569 
570     }
571 
572     /**
573      * Gets the offset of the specified band of the specified pixel.
574      *
575      * @param x
576      *            the X coordinate of the pixel.
577      * @param y
578      *            the Y coordinate of the pixel.
579      * @param b
580      *            the band.
581      * @return the offset of the specified band of the specified pixel.
582      */
getOffset(int x, int y, int b)583     public int getOffset(int x, int y, int b) {
584         return y * scanlineStride + x * pixelStride + bandOffsets[b];
585     }
586 
587     /**
588      * Gets the offset of the first band of the specified pixel.
589      *
590      * @param x
591      *            the X coordinate of pixel.
592      * @param y
593      *            the Y coordinate of pixel.
594      * @return the offset of the first band of the specified pixel.
595      */
getOffset(int x, int y)596     public int getOffset(int x, int y) {
597         return y * scanlineStride + x * pixelStride + bandOffsets[0];
598     }
599 
600     @Override
getSampleSize(int band)601     public final int getSampleSize(int band) {
602         return DataBuffer.getDataTypeSize(dataType);
603     }
604 
605     @Override
getSampleSize()606     public final int[] getSampleSize() {
607         int sampleSizes[] = new int[numBands];
608         int size = DataBuffer.getDataTypeSize(dataType);
609 
610         for (int i = 0; i < numBands; i++) {
611             sampleSizes[i] = size;
612         }
613         return sampleSizes;
614     }
615 
616     /**
617      * Gets an array of bank indices corresponding to this ComponentSampleModel.
618      *
619      * @return the array of bank indices.
620      */
getBankIndices()621     public final int[] getBankIndices() {
622         return bankIndices.clone();
623     }
624 
625     /**
626      * Gets an array of the band offsets corresponding to this
627      * ComponentSampleModel.
628      *
629      * @return the array of band offsets.
630      */
getBandOffsets()631     public final int[] getBandOffsets() {
632         return bandOffsets.clone();
633     }
634 
635     /**
636      * Gets a hash code of this ComponentSampleModel object.
637      *
638      * @return a hash code of this ComponentSampleModel object.
639      */
640     @Override
hashCode()641     public int hashCode() {
642         int hash = 0;
643         int tmp = 0;
644 
645         hash = width;
646         tmp = hash >>> 24;
647         hash <<= 8;
648         hash |= tmp;
649         hash ^= height;
650         tmp = hash >>> 24;
651         hash <<= 8;
652         hash |= tmp;
653         hash ^= numBands;
654         tmp = hash >>> 24;
655         hash <<= 8;
656         hash |= tmp;
657         hash ^= dataType;
658         tmp = hash >>> 24;
659         hash <<= 8;
660         hash |= tmp;
661         for (int element : bandOffsets) {
662             hash ^= element;
663             tmp = hash >>> 24;
664             hash <<= 8;
665             hash |= tmp;
666         }
667         for (int element : bankIndices) {
668             hash ^= element;
669             tmp = hash >>> 24;
670             hash <<= 8;
671             hash |= tmp;
672         }
673         hash ^= pixelStride;
674         tmp = hash >>> 24;
675         hash <<= 8;
676         hash |= tmp;
677 
678         hash ^= scanlineStride;
679         return hash;
680     }
681 
682     /**
683      * Gets the scanline stride of this ComponentSampleModel.
684      *
685      * @return the scanline stride of this ComponentSampleModel.
686      */
getScanlineStride()687     public final int getScanlineStride() {
688         return scanlineStride;
689     }
690 
691     /**
692      * Gets the pixel stride.
693      *
694      * @return the pixel stride.
695      */
getPixelStride()696     public final int getPixelStride() {
697         return pixelStride;
698     }
699 
700     @Override
getNumDataElements()701     public final int getNumDataElements() {
702         return numBands;
703     }
704 
705 }
706