Conservation colour scheme is no more
[jalview.git] / src / jalview / appletgui / SeqPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 \r
20 package jalview.appletgui;\r
21 \r
22 import java.util.*;\r
23 \r
24 import java.awt.*;\r
25 import java.awt.event.*;\r
26 \r
27 import jalview.datamodel.*;\r
28 import jalview.schemes.*;\r
29 \r
30 public class SeqPanel\r
31     extends Panel\r
32 {\r
33 \r
34   public SeqCanvas seqCanvas;\r
35   public AlignmentPanel ap;\r
36 \r
37   protected int lastres;\r
38   protected int startseq;\r
39   int startEdit = -1;\r
40   int endEdit = -1;\r
41 \r
42   protected AlignViewport av;\r
43 \r
44   // if character is inserted or deleted, we will need to recalculate the conservation\r
45   int seqEditOccurred = -1;\r
46 \r
47   ScrollThread scrollThread = null;\r
48   boolean mouseDragging = false;\r
49 \r
50   boolean editingSeqs = false;\r
51   boolean groupEditing = false;\r
52 \r
53   public SeqPanel(AlignViewport avp, AlignmentPanel p)\r
54   {\r
55     this.av = avp;\r
56 \r
57     seqCanvas = new SeqCanvas(avp);\r
58     setLayout(new BorderLayout());\r
59     add(seqCanvas);\r
60 \r
61     ap = p;\r
62 \r
63     seqCanvas.addMouseMotionListener(new MouseMotionAdapter()\r
64     {\r
65       public void mouseMoved(MouseEvent evt)\r
66       {\r
67         if (av.getWrapAlignment())\r
68         {\r
69           return;\r
70         }\r
71         doMouseMoved(evt);\r
72       }\r
73 \r
74       public void mouseDragged(MouseEvent evt)\r
75       {\r
76         if (av.getWrapAlignment())\r
77         {\r
78           return;\r
79         }\r
80         if (editingSeqs)\r
81         {\r
82           doMouseDragged(evt);\r
83         }\r
84         else\r
85         {\r
86           doMouseDraggedDefineMode(evt);\r
87         }\r
88       }\r
89     });\r
90 \r
91     seqCanvas.addMouseListener(new MouseAdapter()\r
92     {\r
93       public void mouseReleased(MouseEvent evt)\r
94       {\r
95         if (av.getWrapAlignment())\r
96         {\r
97           return;\r
98         }\r
99         if (editingSeqs)\r
100         {\r
101           doMouseReleased(evt);\r
102         }\r
103         else\r
104         {\r
105           doMouseReleasedDefineMode(evt);\r
106         }\r
107 \r
108       }\r
109 \r
110       public void mousePressed(MouseEvent evt)\r
111       {\r
112         if (av.getWrapAlignment())\r
113         {\r
114           return;\r
115         }\r
116         if (evt.isShiftDown() || evt.isAltDown() || evt.isControlDown())\r
117         {\r
118           if (evt.isAltDown() || evt.isControlDown())\r
119           {\r
120             groupEditing = true;\r
121           }\r
122 \r
123           editingSeqs = true;\r
124           doMousePressed(evt);\r
125         }\r
126         else\r
127         {\r
128           doMousePressedDefineMode(evt);\r
129         }\r
130       }\r
131 \r
132       public void mouseExited(MouseEvent evt)\r
133       {\r
134         if (av.getWrapAlignment() || editingSeqs)\r
135         {\r
136           return;\r
137         }\r
138         doMouseExitedDefineMode(evt);\r
139 \r
140       }\r
141 \r
142       public void mouseEntered(MouseEvent evt)\r
143       {\r
144         if (av.getWrapAlignment() || editingSeqs)\r
145         {\r
146           return;\r
147         }\r
148         doMouseEnteredDefineMode(evt);\r
149       }\r
150 \r
151     });\r
152     seqCanvas.repaint();\r
153   }\r
154 \r
155   public void doMouseReleased(MouseEvent evt)\r
156   {\r
157 \r
158     if (seqEditOccurred > -1)\r
159     {\r
160       editOccurred(seqEditOccurred);\r
161     }\r
162 \r
163     startseq = -1;\r
164     lastres = -1;\r
165     seqEditOccurred = -1;\r
166     editingSeqs = false;\r
167     groupEditing = false;\r
168     ap.repaint();\r
169   }\r
170 \r
171   public void doMousePressed(MouseEvent evt)\r
172   {\r
173     ap.alignFrame.addHistoryItem(new HistoryItem(\r
174         "Edit Sequence", av.alignment, HistoryItem.EDIT));\r
175     int seq;\r
176     int res;\r
177 \r
178     int x = evt.getX();\r
179     int y = evt.getY();\r
180 \r
181     res = x / av.getCharWidth() + av.getStartRes();\r
182     seq = y / av.getCharHeight() + av.getStartSeq();\r
183 \r
184     if (seq < av.getAlignment().getHeight() &&\r
185         res < av.getAlignment().getSequenceAt(seq).getLength())\r
186     {\r
187       //char resstr = align.getSequenceAt(seq).getSequence().charAt(res);\r
188       // Find the residue's position in the sequence (res is the position\r
189       // in the alignment\r
190 \r
191       startseq = seq;\r
192       lastres = res;\r
193     }\r
194     else\r
195     {\r
196       startseq = -1;\r
197       lastres = -1;\r
198     }\r
199 \r
200     return;\r
201   }\r
202 \r
203   public void doMouseMoved(MouseEvent evt)\r
204   {\r
205     int res = 0, seq = 0;\r
206     int x = evt.getX();\r
207     int y = evt.getY();\r
208     if (av.wrapAlignment)\r
209     {\r
210       y -= 2 * av.charHeight;\r
211       int chunkHeight = (av.getAlignment().getHeight() + 2) * av.charHeight;\r
212 \r
213       res = (int) ( (y / chunkHeight) * (getSize().width / av.charWidth)) +\r
214           x / av.getCharWidth() + av.getStartRes();\r
215 \r
216       y %= chunkHeight;\r
217       seq = y / av.getCharHeight() + av.getStartSeq();\r
218 \r
219     }\r
220     else\r
221     {\r
222       res = x / av.getCharWidth() + av.getStartRes();\r
223       seq = y / av.getCharHeight() + av.getStartSeq();\r
224     }\r
225 \r
226     if (seq >= av.getAlignment().getHeight())\r
227     {\r
228       return;\r
229     }\r
230 \r
231     SequenceI sequence = av.getAlignment().getSequenceAt(seq);\r
232     if (res > sequence.getLength())\r
233     {\r
234       return;\r
235     }\r
236 \r
237     Object obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");\r
238     String aa = "";\r
239     if (obj != null)\r
240     {\r
241       aa = obj.toString();\r
242     }\r
243 \r
244     StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: " +\r
245                                          sequence.getName());\r
246     if (aa != "")\r
247     {\r
248       text.append("  Residue: " + aa + " (" +\r
249                   av.getAlignment().getSequenceAt(seq).findPosition(res) + ")");\r
250     }\r
251 \r
252     ap.alignFrame.statusBar.setText(text.toString());\r
253 \r
254     // use aa to see if the mouse pointer is on a\r
255     if (av.showSequenceFeatures)\r
256     {\r
257       Vector features = sequence.getSequenceFeatures();\r
258       Enumeration e = features.elements();\r
259       StringBuffer sbuffer = new StringBuffer();\r
260 \r
261       while (e.hasMoreElements())\r
262       {\r
263         SequenceFeature sf = (SequenceFeature) e.nextElement();\r
264         if (sf.getStart() <= sequence.findPosition(res) &&\r
265             sf.getEnd() >= sequence.findPosition(res))\r
266         {\r
267           if (sbuffer.length() > 0)\r
268           {\r
269             sbuffer.append("; ");\r
270           }\r
271           sbuffer.append(sf.getType() + " " + sf.getDescription());\r
272           if (sf.getStatus().length() > 0)\r
273           {\r
274             sbuffer.append(" (" + sf.getStatus() + ")");\r
275           }\r
276         }\r
277 \r
278       }\r
279     }\r
280 \r
281   }\r
282 \r
283   public void doMouseDragged(MouseEvent evt)\r
284   {\r
285 \r
286     // If we're dragging we're editing\r
287     int res = evt.getX() / av.getCharWidth() + av.getStartRes();\r
288     if (res < 0)\r
289     {\r
290       res = 0;\r
291     }\r
292 \r
293     if (lastres == -1 || lastres == res)\r
294     {\r
295       return;\r
296     }\r
297 \r
298     boolean dragRight = true;\r
299     if (res < av.getAlignment().getWidth() && res < lastres)\r
300     {\r
301       dragRight = false;\r
302     }\r
303 \r
304     if (res != lastres)\r
305     {\r
306       // Group editing\r
307       if (groupEditing)\r
308       {\r
309         SequenceGroup sg = av.getSelectionGroup();\r
310         if (sg == null)\r
311         {\r
312           lastres = -1;\r
313           return;\r
314         }\r
315 \r
316         // drag to right\r
317         if (dragRight)\r
318         {\r
319           sg.setEndRes(sg.getEndRes() + (res - lastres));\r
320         }\r
321 \r
322         // drag to left\r
323         else\r
324         {\r
325           /// Are we able to delete?\r
326           // ie are all columns blank?\r
327           boolean deleteAllowed = false;\r
328           for (int s = 0; s < sg.getSize(); s++)\r
329           {\r
330             SequenceI seq = sg.getSequenceAt(s);\r
331             for (int j = res; j < lastres; j++)\r
332             {\r
333               if (seq.getSequence().length() <= j)\r
334               {\r
335                 continue;\r
336               }\r
337 \r
338               if (!jalview.util.Comparison.isGap(seq.getSequence().charAt(j)))\r
339               {\r
340                 // Not a gap, block edit not valid\r
341                 res = j + 1;\r
342                 deleteAllowed = false;\r
343                 continue;\r
344               }\r
345               deleteAllowed = true;\r
346             }\r
347           }\r
348 \r
349           if (!deleteAllowed)\r
350           {\r
351             lastres = -1;\r
352             return;\r
353           }\r
354 \r
355           sg.setEndRes(sg.getEndRes() - (lastres - res));\r
356         }\r
357 \r
358         for (int i = 0; i < sg.getSize(); i++)\r
359         {\r
360           SequenceI s = sg.getSequenceAt(i);\r
361           int k = av.alignment.findIndex(s);\r
362 \r
363           // drag to right\r
364           if (dragRight)\r
365           {\r
366             for (int j = lastres; j < res; j++)\r
367             {\r
368               insertChar(j, k);\r
369             }\r
370           }\r
371 \r
372           // drag to left\r
373           else\r
374           {\r
375             for (int j = res; j < lastres; j++)\r
376             {\r
377               if (s.getLength() > j)\r
378               {\r
379                 deleteChar(res, k);\r
380               }\r
381             }\r
382           }\r
383         }\r
384       }\r
385       else /////Editing a single sequence///////////\r
386       {\r
387         if (res < av.getAlignment().getWidth() && res > lastres)\r
388         {\r
389           // dragging to the right\r
390           for (int j = lastres; j < res; j++)\r
391           {\r
392             insertChar(j, startseq);\r
393           }\r
394         }\r
395         else if (res < av.getAlignment().getWidth() && res < lastres)\r
396         {\r
397           // dragging to the left\r
398           for (int j = lastres; j > res; j--)\r
399           {\r
400             if (jalview.util.Comparison.isGap(\r
401                 av.alignment.getSequenceAt(startseq).getSequence().charAt(res)))\r
402             {\r
403 \r
404               deleteChar(res, startseq);\r
405             }\r
406             else\r
407             {\r
408 \r
409               break;\r
410             }\r
411           }\r
412         }\r
413 \r
414       }\r
415     }\r
416 \r
417     endEdit = res;\r
418     lastres = res;\r
419     seqCanvas.repaint();\r
420   }\r
421 \r
422   public void drawChars(int seqstart, int seqend, int start)\r
423   {\r
424     seqCanvas.drawPanel(seqCanvas.gg, start, av.getEndRes(), seqstart, seqend,\r
425                         av.getStartRes(), av.getStartSeq(), 0);\r
426     seqCanvas.repaint();\r
427   }\r
428 \r
429   public void insertChar(int j, int seq)\r
430   {\r
431     av.alignment.getSequenceAt(seq).insertCharAt(j, av.getGapCharacter());\r
432     seqEditOccurred = seq;\r
433   }\r
434 \r
435   public void deleteChar(int j, int seq)\r
436   {\r
437 \r
438     av.alignment.getSequenceAt(seq).deleteCharAt(j);\r
439     seqEditOccurred = seq;\r
440     av.alignment.getWidth();\r
441     repaint();\r
442   }\r
443 \r
444   void editOccurred(int i)\r
445   {\r
446     if (endEdit == startEdit)\r
447     {\r
448       ap.alignFrame.historyList.pop();\r
449       ap.alignFrame.updateEditMenuBar();\r
450     }\r
451 \r
452     av.updateConservation();\r
453     av.updateConsensus();\r
454 \r
455     // Y O Y CLUSTALX\r
456     ColourSchemeI cs = av.getGlobalColourScheme();\r
457     if (cs.conservationApplied())\r
458     {\r
459       if (cs instanceof ClustalxColourScheme)\r
460       {\r
461         jalview.analysis.Conservation c = new jalview.analysis.Conservation\r
462             ("All",\r
463              ResidueProperties.propHash, 3,\r
464              av.alignment.getSequences(), 0,\r
465              av.alignment.getWidth() - 1);\r
466         c.calculate();\r
467         c.verdict(false, av.ConsPercGaps);\r
468 \r
469         ((ClustalxColourScheme)cs).resetClustalX(av.alignment.getSequences(), av.alignment.getWidth());\r
470         cs.setConservation(c);\r
471         av.setGlobalColourScheme(cs);\r
472       }\r
473     }\r
474 \r
475     if (cs instanceof ClustalxColourScheme)\r
476     {\r
477       ( (ClustalxColourScheme) cs).resetClustalX(av.alignment.getSequences(),\r
478                                                  av.alignment.getWidth());\r
479       av.setGlobalColourScheme(cs);\r
480     }\r
481 \r
482   }\r
483 \r
484 //////////////////////////////////////////\r
485 /////Everything below this is for defining the boundary of the rubberband\r
486 //////////////////////////////////////////\r
487   int oldSeq = -1;\r
488   public void doMousePressedDefineMode(MouseEvent evt)\r
489   {\r
490     int res = evt.getX() / av.getCharWidth() + av.getStartRes();\r
491     int seq = evt.getY() / av.getCharHeight() + av.getStartSeq();\r
492     oldSeq = seq;\r
493 \r
494     SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(seq);\r
495 \r
496     if (sequence == null || res > sequence.getLength())\r
497     {\r
498       return;\r
499     }\r
500 \r
501     stretchGroup = av.getSelectionGroup();\r
502 \r
503     if (stretchGroup == null)\r
504     {\r
505       stretchGroup = av.alignment.findGroup(sequence);\r
506       if (stretchGroup != null && res > stretchGroup.getStartRes() &&\r
507           res < stretchGroup.getEndRes())\r
508       {\r
509         av.setSelectionGroup(stretchGroup);\r
510       }\r
511       else\r
512       {\r
513         stretchGroup = null;\r
514       }\r
515     }\r
516 \r
517     else if (!stretchGroup.sequences.contains(sequence)\r
518              || stretchGroup.getStartRes() > res\r
519              || stretchGroup.getEndRes() < res)\r
520     {\r
521       stretchGroup = null;\r
522 \r
523       SequenceGroup[] allGroups = av.alignment.findAllGroups(sequence);\r
524 \r
525       if (allGroups != null)\r
526       {\r
527         for (int i = 0; i < allGroups.length; i++)\r
528         {\r
529           if (allGroups[i].getStartRes() <= res &&\r
530               allGroups[i].getEndRes() >= res)\r
531           {\r
532             stretchGroup = allGroups[i];\r
533             av.setSelectionGroup(stretchGroup);\r
534             break;\r
535           }\r
536         }\r
537       }\r
538     }\r
539 \r
540     if (stretchGroup == null)\r
541     {\r
542       // define a new group here\r
543       SequenceGroup sg = new SequenceGroup();\r
544       sg.setStartRes(res);\r
545       sg.setEndRes(res);\r
546       sg.addSequence(sequence, false);\r
547       av.setSelectionGroup(sg);\r
548       stretchGroup = sg;\r
549 \r
550       if (av.getConservationSelected())\r
551       {\r
552         SliderPanel.setConservationSlider(ap, av.getGlobalColourScheme(),\r
553                                           "Background");\r
554       }\r
555       if (av.getAbovePIDThreshold())\r
556       {\r
557         SliderPanel.setPIDSliderSource(ap, av.getGlobalColourScheme(),\r
558                                        "Background");\r
559       }\r
560 \r
561     }\r
562 \r
563     // DETECT RIGHT MOUSE BUTTON IN AWT\r
564     else if ( (evt.getModifiers() & InputEvent.BUTTON3_MASK) ==\r
565              InputEvent.BUTTON3_MASK)\r
566     {\r
567       APopupMenu popup = new APopupMenu(ap, null, null);\r
568       this.add(popup);\r
569       popup.show(this, evt.getX(), evt.getY());\r
570     }\r
571 \r
572     if (stretchGroup != null && stretchGroup.getEndRes() == res)\r
573     {\r
574       // Edit end res position of selected group\r
575       changeEndRes = true;\r
576     }\r
577 \r
578     else if (stretchGroup != null && stretchGroup.getStartRes() == res)\r
579     {\r
580       // Edit end res position of selected group\r
581       changeStartRes = true;\r
582     }\r
583 \r
584   }\r
585 \r
586   boolean changeEndSeq = false;\r
587   boolean changeStartSeq = false;\r
588   boolean changeEndRes = false;\r
589   boolean changeStartRes = false;\r
590   SequenceGroup stretchGroup = null;\r
591 \r
592   public void doMouseReleasedDefineMode(MouseEvent evt)\r
593   {\r
594     if(mouseDragging)\r
595      {\r
596        stretchGroup.recalcConservation();\r
597        mouseDragging = false;\r
598      }\r
599 \r
600     if (stretchGroup == null)\r
601     {\r
602       return;\r
603     }\r
604 \r
605     if(stretchGroup.cs!=null)\r
606     {\r
607       if (stretchGroup.cs.conservationApplied())\r
608       {\r
609         SliderPanel.setConservationSlider(ap, stretchGroup.cs,\r
610                                           stretchGroup.getName());\r
611       }\r
612       else\r
613       {\r
614         SliderPanel.setPIDSliderSource(ap, stretchGroup.cs,\r
615                                        stretchGroup.getName());\r
616       }\r
617     }\r
618     changeEndRes = false;\r
619     changeStartRes = false;\r
620     stretchGroup = null;\r
621     seqCanvas.repaint();\r
622     ap.repaint();\r
623   }\r
624 \r
625   boolean remove = false;\r
626   public void doMouseDraggedDefineMode(MouseEvent evt)\r
627   {\r
628     int res = evt.getX() / av.getCharWidth() + av.getStartRes();\r
629     int y = evt.getY() / av.getCharHeight() + av.getStartSeq();\r
630 \r
631     if (stretchGroup == null)\r
632     {\r
633       return;\r
634     }\r
635 \r
636     if (res > av.alignment.getWidth())\r
637     {\r
638       res = av.alignment.getWidth() - 1;\r
639     }\r
640 \r
641     if (stretchGroup.getEndRes() == res)\r
642     {\r
643       // Edit end res position of selected group\r
644       changeEndRes = true;\r
645     }\r
646 \r
647     else if (stretchGroup.getStartRes() == res)\r
648     {\r
649       // Edit start res position of selected group\r
650       changeStartRes = true;\r
651     }\r
652 \r
653     if (res < av.getStartRes())\r
654     {\r
655       res = av.getStartRes();\r
656     }\r
657     else if (res > av.getEndRes())\r
658     {\r
659       res = av.getEndRes();\r
660     }\r
661 \r
662     if (changeEndRes)\r
663     {\r
664       if (res > stretchGroup.getStartRes() - 1)\r
665       {\r
666         stretchGroup.setEndRes(res);\r
667       }\r
668     }\r
669     else if (changeStartRes)\r
670     {\r
671       if (res < stretchGroup.getEndRes() + 1)\r
672       {\r
673         stretchGroup.setStartRes(res);\r
674       }\r
675     }\r
676 \r
677     int dragDirection = 0;\r
678     if (y > oldSeq)\r
679     {\r
680       dragDirection = 1;\r
681     }\r
682     else if (y < oldSeq)\r
683     {\r
684       dragDirection = -1;\r
685     }\r
686 \r
687     while (y != oldSeq && oldSeq > 0 && y < av.alignment.getHeight())\r
688     {\r
689       // This routine ensures we don't skip any sequences, as the\r
690       // selection is quite slow.\r
691       Sequence seq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
692 \r
693       oldSeq += dragDirection;\r
694       Sequence nextSeq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
695 \r
696       if (stretchGroup.sequences.contains(nextSeq))\r
697       {\r
698         stretchGroup.deleteSequence(seq, false);\r
699       }\r
700       else\r
701       {\r
702         if (seq != null)\r
703         {\r
704           stretchGroup.addSequence(seq, false);\r
705         }\r
706         stretchGroup.addSequence(nextSeq, false);\r
707       }\r
708     }\r
709     oldSeq = y;\r
710     mouseDragging = true;\r
711     if (scrollThread != null)\r
712     {\r
713       scrollThread.setEvent(evt);\r
714     }\r
715 \r
716     seqCanvas.repaint();\r
717   }\r
718 \r
719   public void doMouseEnteredDefineMode(MouseEvent e)\r
720   {\r
721     if (scrollThread != null)\r
722     {\r
723       scrollThread.running = false;\r
724     }\r
725   }\r
726 \r
727   public void doMouseExitedDefineMode(MouseEvent e)\r
728   {\r
729     if (av.getWrapAlignment())\r
730     {\r
731       return;\r
732     }\r
733 \r
734     if (mouseDragging)\r
735     {\r
736       scrollThread = new ScrollThread();\r
737     }\r
738 \r
739   }\r
740 \r
741   // this class allows scrolling off the bottom of the visible alignment\r
742   class ScrollThread\r
743       extends Thread\r
744   {\r
745     MouseEvent evt;\r
746     boolean running = false;\r
747     public ScrollThread()\r
748     {\r
749       start();\r
750     }\r
751 \r
752     public void setEvent(MouseEvent e)\r
753     {\r
754       evt = e;\r
755     }\r
756 \r
757     public void stopScrolling()\r
758     {\r
759       running = false;\r
760     }\r
761 \r
762     public void run()\r
763     {\r
764       running = true;\r
765       while (running)\r
766       {\r
767         if (evt != null)\r
768         {\r
769 \r
770           if (mouseDragging && evt.getY() < 0 && av.getStartSeq() > 0)\r
771           {\r
772             running = ap.scrollUp(true);\r
773           }\r
774 \r
775           if (mouseDragging && evt.getY() >= getSize().height &&\r
776               av.alignment.getHeight() > av.getEndSeq())\r
777           {\r
778             running = ap.scrollUp(false);\r
779           }\r
780 \r
781           if (mouseDragging && evt.getX() < 0)\r
782           {\r
783             running = ap.scrollRight(true);\r
784           }\r
785 \r
786           else if (mouseDragging && evt.getX() >= getSize().width)\r
787           {\r
788             running = ap.scrollRight(false);\r
789           }\r
790         }\r
791 \r
792         try\r
793         {\r
794           Thread.sleep(75);\r
795         }\r
796         catch (Exception ex)\r
797         {}\r
798       }\r
799     }\r
800   }\r
801 \r
802 }\r