Statistics
| Revision:

root / trunk / extensions / extRasterTools-SE / src / org / gvsig / rastertools / colortable / ui / tabs / TabInterpolated.java @ 22364

History | View | Annotate | Download (18.3 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2007 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 */
19
package org.gvsig.rastertools.colortable.ui.tabs;
20

    
21
import java.awt.Color;
22
import java.awt.GridBagConstraints;
23
import java.awt.GridBagLayout;
24
import java.awt.Insets;
25
import java.awt.event.FocusEvent;
26
import java.awt.event.FocusListener;
27
import java.awt.event.KeyEvent;
28
import java.awt.event.KeyListener;
29
import java.util.ArrayList;
30
import java.util.Iterator;
31

    
32
import javax.swing.JLabel;
33
import javax.swing.JPanel;
34
import javax.swing.JTextField;
35

    
36
import org.gvsig.gui.beans.colorbutton.ColorButton;
37
import org.gvsig.gui.beans.colorbutton.ColorButtonEvent;
38
import org.gvsig.gui.beans.colorbutton.ColorButtonListener;
39
import org.gvsig.gui.beans.colorslideredition.ColorSliderEdition;
40
import org.gvsig.gui.beans.colorslideredition.ColorSliderEvent;
41
import org.gvsig.gui.beans.colorslideredition.ColorSliderListener;
42
import org.gvsig.gui.beans.colorslideredition.ItemColorSlider;
43
import org.gvsig.raster.beans.previewbase.IUserPanelInterface;
44
import org.gvsig.raster.datastruct.ColorItem;
45
import org.gvsig.raster.datastruct.ColorTable;
46
import org.gvsig.raster.util.MathUtils;
47
import org.gvsig.raster.util.BasePanel;
48
import org.gvsig.raster.util.RasterToolsUtil;
49
/**
50
 * Pesta?a para las interpolaciones de la tabla de color, aqui se tratar?n
51
 * los gradientes de color, etc...
52
 *
53
 * @version 27/06/2007
54
 * @author BorSanZa - Borja S?nchez Zamorano (borja.sanchez@iver.es)
55
 */
56
public class TabInterpolated extends BasePanel implements IColorTableUI, ColorSliderListener, ColorButtonListener, FocusListener, KeyListener, IUserPanelInterface {
57
        private static final long serialVersionUID = -5208861410196059899L;
58

    
59
        private ArrayList          actionCommandListeners = new ArrayList();
60
        private boolean            listenerEnabled        = true;
61
        private double             min                    = Double.POSITIVE_INFINITY;
62
        private double             max                    = Double.NEGATIVE_INFINITY;
63
        
64
        /**
65
         * Tabla de color interna que se esta utilizando actualmente
66
         */        
67
        private ColorTable         colorTable             = new ColorTable();
68

    
69
        private ColorSliderEdition colorSliderEdition     = null;
70
        private ColorButton        colorButton            = null;
71
        private JTextField         jTextClassName         = null;
72
        private JTextField         jTextValue             = null;
73
        private JLabel             jLabelColor            = null;
74
        private JLabel             jLabelClassName        = null;
75
        private JLabel             jLabelValue            = null;
76

    
77
        /**
78
         *Inicializa componentes gr?ficos y traduce
79
         */
80
        public TabInterpolated() {
81
                init();
82
                translate();
83
        }
84
        
85
        /*
86
         * (non-Javadoc)
87
         * @see org.gvsig.raster.util.BasePanel#init()
88
         */
89
        protected void init() {
90
                setLayout(new GridBagLayout());
91

    
92
                GridBagConstraints gridBagConstraints = new GridBagConstraints();
93
                gridBagConstraints.gridwidth = 2;
94
                gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
95
                gridBagConstraints.weightx = 1.0;
96
                gridBagConstraints.insets = new Insets(5, 5, 2, 5);
97
                add(getColorSliderEdition(), gridBagConstraints);
98

    
99
                gridBagConstraints = new GridBagConstraints();
100
                gridBagConstraints.gridx = 0;
101
                gridBagConstraints.gridy = 1;
102
                gridBagConstraints.anchor = GridBagConstraints.EAST;
103
                gridBagConstraints.weightx = 0.5;
104
                gridBagConstraints.insets = new Insets(2, 5, 2, 2);
105
                add(getJLabelColor(), gridBagConstraints);
106

    
107
                gridBagConstraints = new GridBagConstraints();
108
                gridBagConstraints.gridx = 1;
109
                gridBagConstraints.gridy = 1;
110
                gridBagConstraints.anchor = GridBagConstraints.WEST;
111
                gridBagConstraints.weightx = 0.5;
112
                gridBagConstraints.insets = new Insets(2, 2, 2, 5);
113
                add(getColorButton(), gridBagConstraints);
114
                
115
                gridBagConstraints = new GridBagConstraints();
116
                gridBagConstraints.gridx = 0;
117
                gridBagConstraints.gridy = 2;
118
                gridBagConstraints.anchor = GridBagConstraints.EAST;
119
                gridBagConstraints.insets = new Insets(2, 5, 2, 2);
120
                add(getJLabelClassName(), gridBagConstraints);
121
                
122
                gridBagConstraints = new GridBagConstraints();
123
                gridBagConstraints.gridx = 1;
124
                gridBagConstraints.gridy = 2;
125
                gridBagConstraints.anchor = GridBagConstraints.WEST;
126
                gridBagConstraints.weightx = 1.0;
127
                gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
128
                gridBagConstraints.insets = new Insets(2, 2, 2, 5);
129
                add(getJTextClassName(), gridBagConstraints);
130

    
131
                gridBagConstraints = new GridBagConstraints();
132
                gridBagConstraints.gridx = 0;
133
                gridBagConstraints.gridy = 3;
134
                gridBagConstraints.anchor = GridBagConstraints.EAST;
135
                gridBagConstraints.insets = new Insets(2, 5, 2, 2);
136
                add(getJLabelValue(), gridBagConstraints);
137

    
138
                gridBagConstraints = new GridBagConstraints();
139
                gridBagConstraints.gridx = 1;
140
                gridBagConstraints.gridy = 3;
141
                gridBagConstraints.anchor = GridBagConstraints.WEST;
142
                gridBagConstraints.weightx = 1.0;
143
                gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
144
                gridBagConstraints.insets = new Insets(2, 2, 2, 5);
145
                add(getJTextValue(), gridBagConstraints);
146
        }
147
        
148
        /*
149
         * (non-Javadoc)
150
         * @see org.gvsig.raster.util.BasePanel#translate()
151
         */
152
        protected void translate() {
153
        }
154

    
155
        private JLabel getJLabelColor() {
156
                if (jLabelColor == null) {
157
                        jLabelColor = new JLabel(getText(this, "tabinterpolated_color") + ": ");
158
                        jLabelColor.setEnabled(false);
159
                }
160
                return jLabelColor;
161
        }
162
        
163
        private JLabel getJLabelClassName() {
164
                if (jLabelClassName == null) {
165
                        jLabelClassName = new JLabel(getText(this, "clase") + ": ");
166
                        jLabelClassName.setEnabled(false);
167
                }
168
                return jLabelClassName;
169
        }
170

    
171
        private JLabel getJLabelValue() {
172
                if (jLabelValue == null) {
173
                        jLabelValue = new JLabel(getText(this, "value") + ": ");
174
                        jLabelValue.setEnabled(false);
175
                }
176
                return jLabelValue;
177
        }
178

    
179
        private ColorSliderEdition getColorSliderEdition() {
180
                if (colorSliderEdition == null) {
181
                        colorSliderEdition = new ColorSliderEdition();
182
                        colorSliderEdition.addValueChangedListener(this);
183
                        colorSliderEdition.addSelectionChangedListener(this);
184
                }
185
                return colorSliderEdition;
186
        }
187

    
188
        private ColorButton getColorButton() {
189
                if (colorButton == null) {
190
                        colorButton = new ColorButton();
191
                        colorButton.addValueChangedListener(this);
192
                }
193
                return colorButton;
194
        }
195

    
196
        private JTextField getJTextClassName() {
197
                if (jTextClassName == null) {
198
                        jTextClassName = new JTextField();
199
                        jTextClassName.setEnabled(false);
200
                        jTextClassName.addKeyListener(this);
201
                }
202
                return jTextClassName;
203
        }
204

    
205
        private JTextField getJTextValue() {
206
                if (jTextValue == null) {
207
                        jTextValue = new JTextField();
208
                        jTextValue.setEnabled(false);
209
                        jTextValue.addKeyListener(this);
210
                        jTextValue.addFocusListener(this);
211
                }
212
                return jTextValue;
213
        }
214

    
215
        /*
216
         * (non-Javadoc)
217
         * @see org.gvsig.gui.beans.colorslideredition.ColorSliderListener#actionSelectionChanged(org.gvsig.gui.beans.colorslideredition.ColorSliderEvent)
218
         */
219
        public void actionSelectionChanged(ColorSliderEvent e) {
220
                ItemColorSlider itemColorSlider = getColorSliderEdition().getSelectedItem();
221
                boolean enabled = false;
222
                if ((itemColorSlider != null) && (itemColorSlider.getSelected() == 1)) {
223
                        getColorButton().setColor(itemColorSlider.getColor());
224
                        getJTextClassName().setText(itemColorSlider.getName());
225
                        enabled = true;
226
                }
227
                setControlsEnabled(enabled);
228
        }
229

    
230
        /**
231
         * Acci?n que se ejecuta cuando cambia el color el usuario. Este metodo
232
         * actualiza el color del ItemColorSlider segun la seleccion del usuario.
233
         */
234
        private void updateItemSelectedToColorSlider() {
235
                ItemColorSlider itemColorSlider = getColorSliderEdition().getSelectedItem();
236
                if (itemColorSlider != null) {
237
                        itemColorSlider.setColor(getColorButton().getColor());
238
                        itemColorSlider.setName(getJTextClassName().getText());
239
                        getColorSliderEdition().repaint();
240
                }
241
        }
242

    
243
        /*
244
         * (non-Javadoc)
245
         * @see org.gvsig.gui.beans.colorbutton.ColorButtonListener#actionValueDragged(org.gvsig.gui.beans.colorbutton.ColorButtonEvent)
246
         */
247
        public void actionValueDragged(ColorButtonEvent e) {
248
                updateItemSelectedToColorSlider();
249
        }
250

    
251
        /**
252
         * Convierte el slider de la paleta en un array de objetos para poder crear
253
         * con ?l el objeto Palette
254
         * @return
255
         */
256
        private ArrayList getPalette() {
257
                double min2 = min;
258
                double max2 = max;
259

    
260
                if (min2 > max2) {
261
                        double aux = min2;
262
                        min2 = max2;
263
                        max2 = aux;
264
                }
265

    
266
                ArrayList arrayList = new ArrayList();
267
                ArrayList items = getColorSliderEdition().getItemsShowed();
268

    
269
                // A?adir el minimo
270
                ItemColorSlider item;
271
                if (items.size() > 0)
272
                        item = (ItemColorSlider) items.get(0);
273
                else
274
                        item = new ItemColorSlider(0, Color.black);
275
                ColorItem colorItem = new ColorItem();
276
                colorItem.setColor(item.getColor());
277
                colorItem.setInterpolated(50);
278
                colorItem.setNameClass("");
279
                colorItem.setValue(min2);
280
                arrayList.add(colorItem);
281

    
282
                for (int i = 0; i < items.size(); i++) {
283
                        item = (ItemColorSlider) items.get(i);
284
                        colorItem = new ColorItem();
285
                        colorItem.setColor(item.getColor());
286
                        colorItem.setInterpolated((int) item.getInterpolated());
287
                        colorItem.setNameClass(item.getName());
288

    
289
                        colorItem.setValue(min2 + ((item.getValue() * (max2 - min2)) / 100.0d));
290

    
291
                        arrayList.add(colorItem);
292
                }
293

    
294
                // A?adir el maximo
295
                if (items.size() > 0)
296
                        item = (ItemColorSlider) items.get(items.size() - 1);
297
                else
298
                        item = new ItemColorSlider(255, Color.white);
299
                colorItem = new ColorItem();
300
                colorItem.setColor(item.getColor());
301
                colorItem.setInterpolated(50);
302
                colorItem.setNameClass("");
303
                colorItem.setValue(max2);
304
                arrayList.add(colorItem);
305

    
306

    
307
                return arrayList;
308
        }        
309
        
310
        /**
311
         * Refresco de los items del panel de color
312
         * @param colorItems
313
         */
314
        private void refreshItems() {
315
                colorTable.createPaletteFromColorItems(getPalette(), false);
316
        }
317
        
318
        /*
319
         * (non-Javadoc)
320
         * @see org.gvsig.gui.beans.colorbutton.ColorButtonListener#actionValueChanged(org.gvsig.gui.beans.colorbutton.ColorButtonEvent)
321
         */
322
        public void actionValueChanged(ColorButtonEvent e) {
323
                updateItemSelectedToColorSlider();
324
                refreshItems();
325
                callColorTableUIChangedListener();
326
        }
327

    
328
        /*
329
         * (non-Javadoc)
330
         * @see org.gvsig.gui.beans.colorslideredition.ColorSliderListener#actionValueChanged(org.gvsig.gui.beans.colorslideredition.ColorSliderEvent)
331
         */
332
        public void actionValueChanged(ColorSliderEvent e) {
333
                refreshItems();
334
                changeTextValue();
335
                callColorTableUIChangedListener();
336
        }
337

    
338
        private void initialState() {
339
                getColorSliderEdition().repaint();
340
                setControlsEnabled(false);
341
        }
342
        
343
        private void setControlsEnabled(boolean value) {
344
                getColorButton().setEnabled(value);
345
                getJLabelColor().setEnabled(value);
346
                getJLabelClassName().setEnabled(value);
347
                getJTextClassName().setEnabled(value);
348
                getJLabelValue().setEnabled(value);
349
                getJTextValue().setEnabled(value);
350
                if (value == false)
351
                        getJTextClassName().setText("");
352
        }
353

    
354
        /**
355
         * Carga inicial de los items del panel de color
356
         * @param colorItems
357
         */
358
        private void reloadItems() {
359
                ArrayList colorItems = colorTable.getColorItems();
360

    
361
                min = Double.POSITIVE_INFINITY;
362
                max = Double.NEGATIVE_INFINITY;
363
                for (int i = 0; i < colorItems.size(); i++) {
364
                        ColorItem c1 = (ColorItem) colorItems.get(i);
365
                        if (c1.getValue() > max)
366
                                max = c1.getValue();
367
                        if (c1.getValue() < min)
368
                                min = c1.getValue();
369
                }
370

    
371
                clearTable();
372
                for (int i = 0; i < colorItems.size(); i++) {
373
                        ColorItem c1 = (ColorItem) colorItems.get(i);
374
                        double percent = (((c1.getValue() - min) * 100) / (max - min));
375

    
376
                        ItemColorSlider aux = new ItemColorSlider(percent, c1.getColor());
377
                        aux.setInterpolated(c1.getInterpolated());
378
                        aux.setName(c1.getNameClass());
379

    
380
                        getColorSliderEdition().addItem(aux, false);
381
                }
382
                initialState();
383
                if (min > max) {
384
                        min = 0;
385
                        max = 255;
386
                }
387
                refreshItems();
388
        }
389

    
390
        /**
391
         * Borra todas las filas de la tabla.
392
         */
393
        private void clearTable() {
394
                getColorSliderEdition().removeAllItems();
395
        }
396

    
397
        private void updateChangedValue() {
398
                double min2 = Double.POSITIVE_INFINITY;
399
                double max2 = Double.NEGATIVE_INFINITY;
400
                ArrayList list = getColorSliderEdition().getItems();
401
                for (int i = 0; i < list.size(); i++) {
402
                        ItemColorSlider itemColorSlider = (ItemColorSlider) list.get(i);
403
                        
404
                        double value = SliderToValue(itemColorSlider.getValue());
405
                        
406
                        itemColorSlider.setTag(new Double(value));
407
                        
408
                        if (itemColorSlider.getSelected() != 1) {
409
                                if (min2 > value)
410
                                        min2 = value;
411
        
412
                                if (max2 < value)
413
                                        max2 = value;
414
                        }
415
                }
416
                
417
                double value;
418
                try {
419
                        value = Double.parseDouble(getJTextValue().getText());
420
                        if (min2 > value)
421
                                min2 = value;
422
                        if (max2 < value)
423
                                max2 = value;
424
                } catch (NumberFormatException e1) {
425
                }
426
                
427
                min = min2;
428
                max = max2;
429

    
430
                for (int i = 0; i < list.size(); i++) {
431
                        ItemColorSlider itemColorSlider = (ItemColorSlider) list.get(i);
432
                        
433
                        value = ValueToSlider(((Double) itemColorSlider.getTag()).doubleValue());
434
                        
435
                        itemColorSlider.setValue(value);
436

    
437
                        if (itemColorSlider.getSelected() == 1) {
438
                                try {
439
                                        value = Double.parseDouble(getJTextValue().getText());
440
                                        itemColorSlider.setValue(ValueToSlider(value));
441
                                } catch (NumberFormatException e1) {
442
                                }
443
                        }
444
                }
445
        }
446
        
447
        /*
448
         * (non-Javadoc)
449
         * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
450
         */
451
        public void focusLost(FocusEvent e) {
452
                if (e.getSource() == getJTextValue())
453
                        updateChangedValue();
454

    
455
                updateItemSelectedToColorSlider();
456
                refreshItems();
457
                callColorTableUIChangedListener();
458
        }
459

    
460
        /*
461
         * (non-Javadoc)
462
         * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
463
         */
464
        public void keyReleased(KeyEvent e) {
465
                if (e.getSource() == getJTextValue()) {
466
                        updateChangedValue();
467
                        updateItemSelectedToColorSlider();
468
                        refreshItems();
469
                        callColorTableUIChangedListener();
470
                }
471
                
472
                if (e.getSource() == getJTextClassName()) {
473
                        updateItemSelectedToColorSlider();
474
                        refreshItems();
475
                        callColorTableUIChangedListener();
476
                }
477
        }
478

    
479
        private void changeTextValue() {
480
                if (getColorSliderEdition().getSelectedItem() != null) {
481
                        double value = SliderToValue(getColorSliderEdition().getSelectedItem().getValue());
482
                        getJTextValue().setText(MathUtils.format(value, 3) + "");
483
                }
484
        }
485

    
486
        /*
487
         * (non-Javadoc)
488
         * @see org.gvsig.gui.beans.colorslideredition.ColorSliderListener#actionValueDragged(org.gvsig.gui.beans.colorslideredition.ColorSliderEvent)
489
         */
490
        public void actionValueDragged(ColorSliderEvent e) {
491
                changeTextValue();
492
        }
493
        
494
        /**
495
         * Devuelve los limites de la tabla de color, minimo y maximo
496
         * @return
497
         */
498
        private double[] getLimits() {
499
                double min2 = min;
500
                double max2 = max;
501

    
502
                if (min2 > max2) {
503
                        double aux = min2;
504
                        min2 = max2;
505
                        max2 = aux;
506
                }
507
                
508
                if (min2 == max2)
509
                        max2++;
510

    
511
                double limits[] = {min2, max2};
512
                
513
                return limits;
514
        }
515
        
516
        /**
517
         * Convierte un valor de la tabla de color a un porcentaje para el Slider
518
         * @param value
519
         * @return
520
         */
521
        private double ValueToSlider(double value) {
522
                double limits[] = getLimits();
523
                return ((value - limits[0]) * 100.0d) / (limits[1] - limits[0]);
524
        }
525

    
526
        /**
527
         * Convierte un porcentaje del slider a un valor de la tabla de color
528
         * @param value
529
         * @return
530
         */
531
        private double SliderToValue(double value) {
532
                double limits[] = getLimits();
533
                return limits[0] + ((value * (limits[1] - limits[0])) / 100.0d);                
534
        }
535

    
536
        /*
537
         * (non-Javadoc)
538
         * @see org.gvsig.rastertools.colortable.panels.IColorTableUI#getColorTable()
539
         */
540
        public ColorTable getColorTable() {
541
                return colorTable;
542
        }
543

    
544
        /*
545
         * (non-Javadoc)
546
         * @see org.gvsig.rastertools.colortable.panels.IColorTableUI#setColorTable(org.gvsig.raster.datastruct.ColorTable)
547
         */
548
        public void setColorTable(ColorTable colorTable) {
549
                listenerEnabled = false;
550
                this.colorTable = colorTable;
551
                reloadItems();
552
                getColorSliderEdition().setInterpolated(colorTable.isInterpolated());
553
                listenerEnabled = true;
554
        }
555
        
556
        /*
557
         * (non-Javadoc)
558
         * @see org.gvsig.rastertools.colortable.panels.IColorTableUI#addColorTableUIChangedListener(org.gvsig.rastertools.colortable.panels.ColorTableUIListener)
559
         */
560
        public void addColorTableUIChangedListener(ColorTableUIListener listener) {
561
                if (!actionCommandListeners.contains(listener))
562
                        actionCommandListeners.add(listener);
563
        }
564

    
565
        /*
566
         * (non-Javadoc)
567
         * @see org.gvsig.rastertools.colortable.panels.IColorTableUI#removeColorTableUIChangedListener(org.gvsig.rastertools.colortable.panels.ColorTableUIListener)
568
         */
569
        public void removeColorTableUIChangedListener(ColorTableUIListener listener) {
570
                actionCommandListeners.remove(listener);
571
        }
572

    
573
        /**
574
         * Invoca el evento de cambio de un ColorTable
575
         * @param colorTable
576
         */
577
        private void callColorTableUIChangedListener() {
578
                if (!listenerEnabled)
579
                        return;
580

    
581
                Iterator acIterator = actionCommandListeners.iterator();
582
                while (acIterator.hasNext()) {
583
                        ColorTableUIListener listener = (ColorTableUIListener) acIterator.next();
584
                        listener.actionColorTableUIChanged(this);
585
                }
586
        }
587
        
588
        /*
589
         * (non-Javadoc)
590
         * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
591
         */
592
        public void keyPressed(KeyEvent e) {
593
                if (e.getKeyCode() == 38) {
594
                        try {
595
                                double value = Double.parseDouble(getJTextValue().getText());
596
                                value+=10;
597
                                getJTextValue().setText(Double.valueOf(value).toString());
598
                                updateChangedValue();
599
                                updateItemSelectedToColorSlider();
600
                                refreshItems();
601
                                callColorTableUIChangedListener();
602
                        } catch (NumberFormatException e1) {
603
                        }
604
                }
605
                if (e.getKeyCode() == 40) {
606
                        try {
607
                                double value = Double.parseDouble(getJTextValue().getText());
608
                                value-=10;
609
                                getJTextValue().setText(Double.valueOf(value).toString());
610
                                updateChangedValue();
611
                                updateItemSelectedToColorSlider();
612
                                refreshItems();
613
                                callColorTableUIChangedListener();
614
                        } catch (NumberFormatException e1) {
615
                        }
616
                }
617
        }
618

    
619
        /*
620
         * (non-Javadoc)
621
         * @see org.gvsig.raster.beans.previewbase.IUserPanelInterface#getTitle()
622
         */
623
        public String getTitle() {
624
                return RasterToolsUtil.getText(this, "rampa");
625
        }
626
        
627
        public void focusGained(FocusEvent e) {}
628
        public void keyTyped(KeyEvent e) {}
629

    
630
        /*
631
         * (non-Javadoc)
632
         * @see org.gvsig.rastertools.colortable.ui.tabs.IColorTableUI#getPanel()
633
         */
634
        public JPanel getPanel() {
635
                return this;
636
        }
637
}