~ubuntu-branches/ubuntu/oneiric/tuxguitar/oneiric

« back to all changes in this revision

Viewing changes to TuxGuitar/src/org/herac/tuxguitar/gui/editors/piano/Piano.java

  • Committer: Bazaar Package Importer
  • Author(s): Philippe Coval
  • Date: 2008-06-19 00:30:30 UTC
  • mto: (5.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20080619003030-h719szrhsngou7c6
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package org.herac.tuxguitar.gui.editors.piano;
 
2
 
 
3
import java.util.Iterator;
 
4
import java.util.List;
 
5
 
 
6
import org.eclipse.swt.SWT;
 
7
import org.eclipse.swt.events.MouseEvent;
 
8
import org.eclipse.swt.events.MouseListener;
 
9
import org.eclipse.swt.events.PaintEvent;
 
10
import org.eclipse.swt.events.PaintListener;
 
11
import org.eclipse.swt.events.SelectionAdapter;
 
12
import org.eclipse.swt.events.SelectionEvent;
 
13
import org.eclipse.swt.graphics.GC;
 
14
import org.eclipse.swt.graphics.Image;
 
15
import org.eclipse.swt.graphics.Point;
 
16
import org.eclipse.swt.layout.GridData;
 
17
import org.eclipse.swt.layout.GridLayout;
 
18
import org.eclipse.swt.widgets.Button;
 
19
import org.eclipse.swt.widgets.Composite;
 
20
import org.eclipse.swt.widgets.Label;
 
21
import org.herac.tuxguitar.gui.TuxGuitar;
 
22
import org.herac.tuxguitar.gui.actions.ActionLock;
 
23
import org.herac.tuxguitar.gui.actions.caret.GoLeftAction;
 
24
import org.herac.tuxguitar.gui.actions.caret.GoRightAction;
 
25
import org.herac.tuxguitar.gui.actions.duration.DecrementDurationAction;
 
26
import org.herac.tuxguitar.gui.actions.duration.IncrementDurationAction;
 
27
import org.herac.tuxguitar.gui.actions.tools.ScaleAction;
 
28
import org.herac.tuxguitar.gui.editors.TGPainter;
 
29
import org.herac.tuxguitar.gui.editors.tab.Caret;
 
30
import org.herac.tuxguitar.gui.editors.tab.TGNoteImpl;
 
31
import org.herac.tuxguitar.gui.undo.undoables.measure.UndoableMeasureGeneric;
 
32
import org.herac.tuxguitar.song.managers.TGSongManager;
 
33
import org.herac.tuxguitar.song.models.TGBeat;
 
34
import org.herac.tuxguitar.song.models.TGDuration;
 
35
import org.herac.tuxguitar.song.models.TGNote;
 
36
import org.herac.tuxguitar.song.models.TGString;
 
37
 
 
38
public class Piano extends Composite{
 
39
        
 
40
        private static final boolean TYPE_NOTES[] = new boolean[]{true,false,true,false,true,true,false,true,false,true,false,true};
 
41
        private static final int NATURAL_NOTES = 7;
 
42
        private static final int MAX_OCTAVES = 8;
 
43
        private static final int NATURAL_WIDTH = 15;
 
44
        private static final int SHARP_WIDTH = 8;
 
45
        private static final int NATURAL_HEIGHT = 60;
 
46
        private static final int SHARP_HEIGHT = 40;
 
47
        
 
48
        private int duration;
 
49
        private boolean changes;
 
50
        private PianoListener listener;
 
51
        private PianoConfig config;
 
52
        private Composite pianoComposite;
 
53
        private Composite toolComposite;
 
54
        private Label durationLabel;
 
55
        private Button scale;
 
56
        private Button settings;
 
57
        protected TGBeat beat;
 
58
        protected Image image;
 
59
        
 
60
        public Piano(Composite parent, int style) {
 
61
                super(parent, style);
 
62
                this.setLayout(new GridLayout());
 
63
                this.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,true));
 
64
                this.listener =  new PianoListener();
 
65
                this.config = new PianoConfig();
 
66
                this.config.load();
 
67
                this.initToolBar();
 
68
                this.makePiano();
 
69
                this.loadIcons();
 
70
                
 
71
                TuxGuitar.instance().getkeyBindingManager().appendListenersTo(this.toolComposite);
 
72
                TuxGuitar.instance().getkeyBindingManager().appendListenersTo(this.pianoComposite);
 
73
        }
 
74
        
 
75
        private void initToolBar() {
 
76
                GridLayout layout = new GridLayout();
 
77
                layout.makeColumnsEqualWidth = false;
 
78
                layout.numColumns = 0;
 
79
                layout.marginWidth = 0;
 
80
                layout.marginHeight = 0;
 
81
                
 
82
                this.toolComposite = new Composite(this, SWT.NONE);
 
83
                
 
84
                // position
 
85
                layout.numColumns ++;
 
86
                Button goLeft = new Button(this.toolComposite, SWT.ARROW | SWT.LEFT);
 
87
                goLeft.addSelectionListener(TuxGuitar.instance().getAction(GoLeftAction.NAME));
 
88
                
 
89
                layout.numColumns ++;
 
90
                Button goRight = new Button(this.toolComposite, SWT.ARROW | SWT.RIGHT);
 
91
                goRight.addSelectionListener(TuxGuitar.instance().getAction(GoRightAction.NAME));
 
92
                
 
93
                // separator
 
94
                layout.numColumns ++;
 
95
                makeToolSeparator(this.toolComposite);
 
96
                
 
97
                // duration
 
98
                layout.numColumns ++;
 
99
                Button decrement = new Button(this.toolComposite, SWT.ARROW | SWT.MIN);
 
100
                decrement.addSelectionListener(TuxGuitar.instance().getAction(DecrementDurationAction.NAME));
 
101
                
 
102
                layout.numColumns ++;
 
103
                this.durationLabel = new Label(this.toolComposite, SWT.BORDER);
 
104
                
 
105
                layout.numColumns ++;
 
106
                Button increment = new Button(this.toolComposite, SWT.ARROW | SWT.MAX);
 
107
                increment.addSelectionListener(TuxGuitar.instance().getAction(IncrementDurationAction.NAME));
 
108
                
 
109
                // separator
 
110
                layout.numColumns ++;
 
111
                makeToolSeparator(this.toolComposite);
 
112
                
 
113
                // escala
 
114
                layout.numColumns ++;
 
115
                this.scale = new Button(this.toolComposite, SWT.PUSH);
 
116
                this.scale.setText(TuxGuitar.getProperty("scale"));
 
117
                this.scale.addSelectionListener(TuxGuitar.instance().getAction(ScaleAction.NAME));
 
118
                
 
119
                // settings
 
120
                layout.numColumns ++;
 
121
                this.settings = new Button(this.toolComposite, SWT.PUSH);
 
122
                this.settings.setImage(TuxGuitar.instance().getIconManager().getSettings());
 
123
                this.settings.setToolTipText(TuxGuitar.getProperty("settings"));
 
124
                this.settings.setLayoutData(new GridData(SWT.RIGHT,SWT.FILL,true,true));
 
125
                this.settings.addSelectionListener(new SelectionAdapter() {
 
126
                        public void widgetSelected(SelectionEvent e) {
 
127
                                configure();
 
128
                        }
 
129
                });
 
130
                
 
131
                this.toolComposite.setLayout(layout);
 
132
                this.toolComposite.setLayoutData(new GridData(SWT.FILL,SWT.TOP,true,true));
 
133
        }
 
134
        
 
135
        private void makeToolSeparator(Composite parent){
 
136
                Label separator = new Label(parent,SWT.SEPARATOR);
 
137
                separator.setLayoutData(new GridData(20,20));
 
138
        }
 
139
        
 
140
        private void loadDurationImage(boolean force) {
 
141
                int duration = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().getDuration().getValue();
 
142
                if(force || this.duration != duration){
 
143
                        this.duration = duration;
 
144
                        this.durationLabel.setImage(TuxGuitar.instance().getIconManager().getDuration(this.duration));
 
145
                }
 
146
        }
 
147
        
 
148
        private void makePiano(){
 
149
                this.image = makePianoImage();
 
150
                this.pianoComposite = new Composite(this,SWT.BORDER | SWT.DOUBLE_BUFFERED);
 
151
                this.pianoComposite.setLayout(new GridLayout());
 
152
                this.pianoComposite.setLayoutData(new GridData((NATURAL_WIDTH * (MAX_OCTAVES * NATURAL_NOTES) ),NATURAL_HEIGHT));
 
153
                this.pianoComposite.addPaintListener(this.listener);
 
154
                this.pianoComposite.addMouseListener(this.listener);
 
155
                this.pianoComposite.setFocus();
 
156
        }
 
157
        
 
158
        /**
 
159
         * Crea la imagen del piano
 
160
         *
 
161
         * @return
 
162
         */
 
163
        private Image makePianoImage(){
 
164
                Image image = new Image(getDisplay(),(NATURAL_WIDTH * (MAX_OCTAVES * NATURAL_NOTES) ),NATURAL_HEIGHT);
 
165
                TGPainter painter = new TGPainter(new GC(image));
 
166
                
 
167
                int x = 0;
 
168
                int y = 0;
 
169
                painter.setBackground(this.config.getColorNatural());
 
170
                painter.initPath(TGPainter.PATH_FILL);
 
171
                painter.addRectangle(x,y,(NATURAL_WIDTH * (MAX_OCTAVES * NATURAL_NOTES) ),NATURAL_HEIGHT);
 
172
                painter.closePath();
 
173
                for(int i = 0; i < (MAX_OCTAVES * TYPE_NOTES.length); i ++){
 
174
                        
 
175
                        if(TYPE_NOTES[i % TYPE_NOTES.length]){
 
176
                                painter.setForeground(this.config.getColorNotNatural());
 
177
                                painter.initPath();
 
178
                                painter.addRectangle(x,y,NATURAL_WIDTH,NATURAL_HEIGHT);
 
179
                                painter.closePath();
 
180
                                x += NATURAL_WIDTH;
 
181
                        }else{
 
182
                                painter.setBackground(this.config.getColorNotNatural());
 
183
                                painter.initPath(TGPainter.PATH_FILL);
 
184
                                painter.addRectangle(x - (SHARP_WIDTH / 2),y,SHARP_WIDTH,SHARP_HEIGHT);
 
185
                                painter.closePath();
 
186
                        }
 
187
                }
 
188
                paintScale(painter);
 
189
                
 
190
                painter.dispose();
 
191
                return image;
 
192
        }
 
193
        
 
194
        /**
 
195
         * Pinta la nota a partir del indice
 
196
         *       
 
197
         * @param gc
 
198
         * @param value
 
199
         */
 
200
        private void paintScale(TGPainter painter){
 
201
                painter.setBackground(this.config.getColorScale());
 
202
                painter.setForeground(this.config.getColorScale());
 
203
                int posX = 0;
 
204
                
 
205
                for(int i = 0; i < (MAX_OCTAVES * TYPE_NOTES.length); i ++){
 
206
                        int width = 0;
 
207
                        
 
208
                        if(TYPE_NOTES[i % TYPE_NOTES.length]){
 
209
                                width = NATURAL_WIDTH;
 
210
                                if(i > 0 && !TYPE_NOTES[(i - 1)  % TYPE_NOTES.length]){
 
211
                                        width -= ((SHARP_WIDTH / 2));
 
212
                                }
 
213
                                if(!TYPE_NOTES[(i + 1)  % TYPE_NOTES.length]){
 
214
                                        width -= ((SHARP_WIDTH / 2));
 
215
                                }
 
216
                        }else{
 
217
                                width = SHARP_WIDTH;
 
218
                        }
 
219
                        
 
220
                        if(TuxGuitar.instance().getScaleManager().getScale().getNote(i)){
 
221
                                if(TYPE_NOTES[i % TYPE_NOTES.length] ){
 
222
                                        int x = posX;
 
223
                                        if(i > 0 && !TYPE_NOTES[(i - 1)  % TYPE_NOTES.length]){
 
224
                                                x -= ((SHARP_WIDTH / 2));
 
225
                                        }
 
226
                                        
 
227
                                        int size = SHARP_WIDTH;
 
228
                                        painter.initPath(TGPainter.PATH_FILL);
 
229
                                        painter.addRectangle( (x + 1 + (((NATURAL_WIDTH - size) / 2))) ,(NATURAL_HEIGHT - size - (((NATURAL_WIDTH - size) / 2))),size,size);
 
230
                                        painter.closePath();
 
231
                                }else{
 
232
                                        painter.initPath(TGPainter.PATH_FILL);
 
233
                                        painter.addRectangle(posX + 1, SHARP_HEIGHT - SHARP_WIDTH + 1,SHARP_WIDTH - 2,SHARP_WIDTH - 2);
 
234
                                        painter.closePath();
 
235
                                }
 
236
                        }
 
237
                        
 
238
                        posX += width;
 
239
                }
 
240
        }
 
241
        
 
242
        /**
 
243
         * Pinta la nota a partir del indice
 
244
         *       
 
245
         * @param gc
 
246
         * @param value
 
247
         */
 
248
        protected void paintNote(TGPainter painter,int value){
 
249
                painter.setBackground(this.config.getColorNote());
 
250
                int posX = 0;
 
251
                int y = 0;
 
252
                
 
253
                for(int i = 0; i < (MAX_OCTAVES * TYPE_NOTES.length); i ++){
 
254
                        int width = 0;
 
255
                        
 
256
                        if(TYPE_NOTES[i % TYPE_NOTES.length]){
 
257
                                width = NATURAL_WIDTH;
 
258
                                if(i > 0 && !TYPE_NOTES[(i - 1)  % TYPE_NOTES.length]){
 
259
                                        width -= ((SHARP_WIDTH / 2));
 
260
                                }
 
261
                                if(!TYPE_NOTES[(i + 1)  % TYPE_NOTES.length]){
 
262
                                        width -= ((SHARP_WIDTH / 2));
 
263
                                }
 
264
                        }else{
 
265
                                width = SHARP_WIDTH;
 
266
                        }
 
267
                        
 
268
                        if(i == value){
 
269
                                if(TYPE_NOTES[i % TYPE_NOTES.length]){
 
270
                                        painter.initPath(TGPainter.PATH_FILL);
 
271
                                        painter.addRectangle(posX + 1,y + 1,width - 1,SHARP_HEIGHT);
 
272
                                        
 
273
                                        int x = posX;
 
274
                                        if(i > 0 && !TYPE_NOTES[(i - 1)  % TYPE_NOTES.length]){
 
275
                                                x -= ((SHARP_WIDTH / 2));
 
276
                                        }
 
277
                                        painter.addRectangle(x + 1,(y + SHARP_HEIGHT) + 1,NATURAL_WIDTH - 1,(NATURAL_HEIGHT - SHARP_HEIGHT) - 1);
 
278
                                        painter.closePath();
 
279
                                }else{
 
280
                                        painter.initPath(TGPainter.PATH_FILL);
 
281
                                        painter.addRectangle(posX + 1,y + 1,width - 1,SHARP_HEIGHT - 1);
 
282
                                        painter.closePath();
 
283
                                }
 
284
                                
 
285
                        }
 
286
                        
 
287
                        posX += width;
 
288
                }
 
289
        }
 
290
        
 
291
        /**
 
292
         * Retorna el indice de la nota seleccionada
 
293
         * 
 
294
         * @param point
 
295
         * @return
 
296
         */
 
297
        private int getSelection(Point point){
 
298
                int posX = 0;
 
299
                
 
300
                for(int i = 0; i < (MAX_OCTAVES * TYPE_NOTES.length); i ++){
 
301
                        int width = 0;
 
302
                        
 
303
                        if(TYPE_NOTES[i % TYPE_NOTES.length]){
 
304
                                width = NATURAL_WIDTH;
 
305
                                if(i > 0 && !TYPE_NOTES[(i - 1)  % TYPE_NOTES.length]){
 
306
                                        width -= ((SHARP_WIDTH / 2));
 
307
                                }
 
308
                                if(!TYPE_NOTES[(i + 1)  % TYPE_NOTES.length]){
 
309
                                        width -= ((SHARP_WIDTH / 2));
 
310
                                }
 
311
                        }else{
 
312
                                width = SHARP_WIDTH;
 
313
                        }
 
314
                        
 
315
                        if(point.x >= posX && point.x < (posX + width)  ){
 
316
                                return i;
 
317
                        }
 
318
                        
 
319
                        posX += width;
 
320
                }
 
321
                return -1;
 
322
        }
 
323
        
 
324
        protected void hit(int x, int y) {
 
325
                int value = getSelection(new Point(x,y));
 
326
                
 
327
                if (!removeNote(value)) {
 
328
                        addNote(value);
 
329
                }
 
330
        }
 
331
        
 
332
        private boolean removeNote(int value) {
 
333
                if(this.beat != null){
 
334
                        Iterator it = this.beat.getNotes().iterator();
 
335
                        while (it.hasNext()) {
 
336
                                TGNoteImpl note = (TGNoteImpl) it.next();
 
337
                                if (note.getRealValue() == value) {
 
338
                                        //comienza el undoable
 
339
                                        UndoableMeasureGeneric undoable = UndoableMeasureGeneric.startUndo();
 
340
                                        
 
341
                                        TGSongManager manager = TuxGuitar.instance().getSongManager();
 
342
                                        manager.getMeasureManager().removeNote(note);
 
343
                                        
 
344
                                        //termia el undoable
 
345
                                        TuxGuitar.instance().getUndoableManager().addEdit(undoable.endUndo());
 
346
                                        TuxGuitar.instance().getFileHistory().setUnsavedFile();
 
347
                                        
 
348
                                        return true;
 
349
                                }
 
350
                        }
 
351
                }
 
352
                return false;
 
353
        }
 
354
        
 
355
        private boolean addNote(int value) {
 
356
                Caret caret = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret();
 
357
                
 
358
                List strings = caret.getTrack().getStrings();
 
359
                for(int i = 0;i < strings.size();i ++){
 
360
                        TGString string = (TGString)strings.get(i);
 
361
                        if(value >= string.getValue()){
 
362
                                boolean emptyString = true;
 
363
                                
 
364
                                if(this.beat != null){
 
365
                                        Iterator it = this.beat.getNotes().iterator();
 
366
                                        while (it.hasNext()) {
 
367
                                                TGNoteImpl note = (TGNoteImpl) it.next();
 
368
                                                if (note.getString() == string.getNumber()) {
 
369
                                                        emptyString = false;
 
370
                                                        break;
 
371
                                                }
 
372
                                        }
 
373
                                }
 
374
                                if(emptyString){
 
375
                                        TGSongManager manager = TuxGuitar.instance().getSongManager();
 
376
                                        
 
377
                                        //comienza el undoable
 
378
                                        UndoableMeasureGeneric undoable = UndoableMeasureGeneric.startUndo();
 
379
                                        
 
380
                                        TGNote note = manager.getFactory().newNote();
 
381
                                        note.setValue((value - string.getValue()));
 
382
                                        note.setVelocity(caret.getVelocity());
 
383
                                        note.setString(string.getNumber());
 
384
                                        
 
385
                                        TGDuration duration = manager.getFactory().newDuration();
 
386
                                        caret.getDuration().copy(duration);
 
387
                                        
 
388
                                        manager.getMeasureManager().addNote(caret.getMeasure(),caret.getPosition(),note,duration);
 
389
                                        
 
390
                                        //termia el undoable
 
391
                                        TuxGuitar.instance().getUndoableManager().addEdit(undoable.endUndo());
 
392
                                        TuxGuitar.instance().getFileHistory().setUnsavedFile();
 
393
                                        
 
394
                                        //reprodusco las notas en el pulso
 
395
                                        caret.getSelectedBeat().play();
 
396
                                        
 
397
                                        return true;
 
398
                                }
 
399
                        }
 
400
                }
 
401
                return false;
 
402
        }
 
403
        
 
404
        protected void afterAction() {
 
405
                int measure = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().getMeasure().getNumber();
 
406
                TuxGuitar.instance().getTablatureEditor().getTablature().getViewLayout().fireUpdate(measure);
 
407
                TuxGuitar.instance().updateCache(true);
 
408
        }
 
409
        
 
410
        public boolean hasChanges(){
 
411
                return this.changes;
 
412
        }
 
413
        
 
414
        public void setChanges(boolean changes){
 
415
                this.changes = changes;
 
416
        }
 
417
        
 
418
        protected void updateEditor(){
 
419
                if(isVisible()){
 
420
                        if(hasChanges()){
 
421
                                this.image.dispose();
 
422
                                this.image = makePianoImage();
 
423
                        }
 
424
                        if(TuxGuitar.instance().getPlayer().isRunning()){
 
425
                                this.beat = TuxGuitar.instance().getEditorCache().getPlayBeat();
 
426
                        }else{
 
427
                                this.beat = TuxGuitar.instance().getEditorCache().getEditBeat();
 
428
                        }
 
429
                }
 
430
        }
 
431
        
 
432
        public void redraw() {
 
433
                if(!super.isDisposed() && !TuxGuitar.instance().isLocked()){
 
434
                        super.redraw();
 
435
                        this.pianoComposite.redraw();
 
436
                        this.loadDurationImage(false);
 
437
                }
 
438
        }
 
439
        
 
440
        public void redrawPlayingMode(){
 
441
                if(!super.isDisposed() && !TuxGuitar.instance().isLocked()){
 
442
                        this.pianoComposite.redraw();
 
443
                }
 
444
        }
 
445
        
 
446
        public void dispose(){
 
447
                super.dispose();
 
448
                this.image.dispose();
 
449
                this.config.dispose();
 
450
        }
 
451
        
 
452
        public void loadProperties(){
 
453
                this.scale.setText(TuxGuitar.getProperty("scale"));
 
454
                this.settings.setToolTipText(TuxGuitar.getProperty("settings"));
 
455
                this.layout(true,true);
 
456
        }
 
457
        
 
458
        public void loadIcons(){
 
459
                this.getShell().setImage(TuxGuitar.instance().getIconManager().getAppIcon());
 
460
                this.settings.setImage(TuxGuitar.instance().getIconManager().getSettings());
 
461
                this.loadDurationImage(true);
 
462
                this.layout(true,true);
 
463
        }
 
464
        
 
465
        protected void configure(){
 
466
                this.config.configure(getShell());
 
467
                this.setChanges(true);
 
468
                this.redraw();
 
469
        }
 
470
        
 
471
        public Composite getPianoComposite() {
 
472
                return this.pianoComposite;
 
473
        }
 
474
        
 
475
        private class PianoListener implements PaintListener,MouseListener {
 
476
                
 
477
                public PianoListener(){
 
478
                        super();
 
479
                }
 
480
                
 
481
                public void paintControl(PaintEvent e) {
 
482
                        if(!TuxGuitar.instance().isLocked()){
 
483
                                TuxGuitar.instance().lock();
 
484
                                updateEditor();
 
485
                                
 
486
                                TGPainter painter = new TGPainter(e.gc);
 
487
                                painter.drawImage(Piano.this.image,0,0);
 
488
                                
 
489
                                //pinto notas
 
490
                                if(Piano.this.beat != null){
 
491
                                        Iterator it = Piano.this.beat.getNotes().iterator();
 
492
                                        while(it.hasNext()){
 
493
                                                TGNoteImpl note = (TGNoteImpl)it.next();
 
494
                                                paintNote(painter,note.getRealValue());
 
495
                                        }
 
496
                                }
 
497
                                TuxGuitar.instance().unlock();
 
498
                        }
 
499
                }
 
500
                
 
501
                public void mouseUp(MouseEvent e) {
 
502
                        getPianoComposite().setFocus();
 
503
                        if(e.button == 1){
 
504
                                if(!TuxGuitar.instance().getPlayer().isRunning() && !TuxGuitar.instance().isLocked() && !ActionLock.isLocked()){
 
505
                                        ActionLock.lock();
 
506
                                        hit(e.x, e.y);
 
507
                                        afterAction();
 
508
                                        ActionLock.unlock();
 
509
                                }
 
510
                        }else{
 
511
                                TuxGuitar.instance().getAction(GoRightAction.NAME).process(e);
 
512
                        }
 
513
                }
 
514
                
 
515
                public void mouseDoubleClick(MouseEvent e) {
 
516
                        //Not implemented
 
517
                }
 
518
                
 
519
                public void mouseDown(MouseEvent e) {
 
520
                        //Not implemented
 
521
                }
 
522
        }
 
523
}