]> git.mxchange.org Git - jfinancials-lib.git/blob - src/org/mxchange/addressbook/manager/contact/AddressbookContactManager.java
805c3a41b6faee54c86b7f5fce54c19f561dd210
[jfinancials-lib.git] / src / org / mxchange / addressbook / manager / contact / AddressbookContactManager.java
1 /*
2  * Copyright (C) 2015 Roland Haeder
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 package org.mxchange.addressbook.manager.contact;
18
19 import java.io.IOException;
20 import java.lang.reflect.InvocationTargetException;
21 import java.sql.SQLException;
22 import java.text.MessageFormat;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Iterator;
26 import java.util.List;
27 import org.mxchange.addressbook.client.AddressbookClient;
28 import org.mxchange.addressbook.exceptions.ContactAlreadyAddedException;
29 import org.mxchange.jcore.client.Client;
30 import org.mxchange.jcore.exceptions.UnhandledUserChoiceException;
31 import org.mxchange.jcore.manager.BaseManager;
32 import org.mxchange.jcore.model.contact.Contact;
33 import org.mxchange.jcore.model.contact.gender.Gender;
34
35 /**
36  * A manager for contacts.
37  * <p>
38  * @author Roland Haeder
39  * @version 0.0
40  */
41 public class AddressbookContactManager extends BaseManager implements ManageableContactAddressbook {
42
43         /**
44          * Column name list
45          */
46         private final List<String> columnNames;
47
48         /**
49          * Translated column name list
50          */
51         private final List<String> translatedColumnNames;
52
53         /**
54          * Constructor which accepts maxContacts for maximum (initial) contacts and
55          * a client instance.
56          * <p>
57          * @param client Client instance to use
58          * @throws java.sql.SQLException If an SQL error occurs
59          */
60         public AddressbookContactManager (final Client client) throws SQLException {
61                 // Trace message
62                 this.getLogger().trace(MessageFormat.format("client={1} - CALLED!", client)); //NOI18N
63
64                 // Make sure all parameters are set correctly
65                 if (null == client) {
66                         // Abort here
67                         throw new NullPointerException("client is null"); //NOI18N
68                 }
69
70                 // Set client instance
71                 this.setClient(client);
72
73                 // Init database connection
74                 DatabaseFrontend frontend = new AddressbookContactDatabaseFrontend(this);
75                 this.setFrontend(frontend);
76
77                 // Initialize list
78                 this.columnNames = new ArrayList<>(15);
79                 this.translatedColumnNames = new ArrayList<>(15);
80
81                 // And fill it
82                 this.fillColumnNamesFromBundle();
83
84                 // Debug message
85                 //* NOISY-DEBUG: */ this.getLogger().debug("client=" + client);
86         }
87
88         /**
89          * Adds given Contact instance to list
90          * <p>
91          * @param contact Contact instance to add
92          */
93         @Override
94         public void addContact (final Contact contact) throws ContactAlreadyAddedException {
95                 // Trace message
96                 this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
97
98                 // Contact instance must not be null
99                 if (null == contact) {
100                         // Abort here
101                         throw new NullPointerException("contact is null"); //NOI18N
102                 }
103
104                 // Add it
105                 ((AddressbookContactFrontend) this.getFrontend()).addContact(contact);
106
107                 // Trace message
108                 this.getLogger().trace("EXIT!"); //NOI18N
109         }
110
111         /**
112          * Let the user add a new other address
113          */
114         @Override
115         public void doAddOtherAddress () {
116                 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
117         }
118
119         /**
120          * Let the user change address data
121          * <p>
122          * @param contact Instance to change data
123          */
124         @Override
125         public void doChangeAddressData (final Contact contact) {
126                 // Trace message
127                 this.getLogger().trace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
128
129                 // Contact must not be null
130                 if (null == contact) {
131                         // Abort here
132                         throw new NullPointerException("contact is null"); //NOI18N
133                 }
134                 if (!(this.getClient() instanceof AddressbookClient)) {
135                         // Cannot cast
136                         throw new IllegalArgumentException(MessageFormat.format("this.getClient()={0} does not implement AddressbookClient", this.getClient())); //NOI18N
137                 }
138
139                 // Get and cast client instance
140                 AddressbookClient client = (AddressbookClient) this.getClient();
141
142                 // First display it again
143                 client.displayAddressBox(contact);
144
145                 // Is it own data?
146                 if (contact.isOwnContact()) {
147                         // Deligate to client
148                         client.doChangeOwnAddressData(contact);
149                 } else {
150                         // Other contact's address data to change
151                         throw new UnsupportedOperationException("Changing contact entries not finished."); //NOI18N
152                 }
153
154                 // Trace message
155                 this.getLogger().trace("EXIT!"); //NOI18N
156         }
157
158         /**
159          * Let the user change "name data"
160          * <p>
161          * @param contact Instance to change data
162          */
163         @Override
164         public void doChangeNameData (final Contact contact) {
165                 // Trace message
166                 this.getLogger().trace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
167
168                 // Contact must not be null
169                 if (null == contact) {
170                         // Abort here
171                         throw new NullPointerException("contact is null"); //NOI18N
172                 }
173
174                 // Get and cast client instance
175                 AddressbookClient client = (AddressbookClient) this.getClient();
176
177                 // First display them again
178                 client.displayNameBox(contact);
179
180                 // Is this own data?
181                 if (contact.isOwnContact()) {
182                         // Re-ask own data
183                         client.doChangeOwnNameData(contact);
184                 } else {
185                         // Then re-ask them ...
186                         throw new UnsupportedOperationException("Changing contact entries not finished."); //NOI18N
187                 }
188
189                 // Trace message
190                 this.getLogger().trace("EXIT!"); //NOI18N
191         }
192
193         /**
194          * Let the user change other address
195          */
196         @Override
197         public void doChangeOtherAddress () {
198                 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
199         }
200
201         /**
202          * Let the user change other data
203          * <p>
204          * @param contact Instance to change data TODO Didn't handle birthday
205          */
206         @Override
207         public void doChangeOtherData (final Contact contact) {
208                 // Trace message
209                 this.getLogger().trace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
210
211                 // Contact must not be null
212                 if (null == contact) {
213                         // Abort here
214                         throw new NullPointerException("contact is null"); //NOI18N
215                 }
216
217                 // Get and cast client instance
218                 AddressbookClient client = (AddressbookClient) this.getClient();
219
220                 // First display them again
221                 client.displayOtherDataBox(contact);
222
223                 // Is this own data?
224                 if (contact.isOwnContact()) {
225                         // Re-ask own data
226                         client.doChangeOwnOtherData(contact);
227                 } else {
228                         // Then re-ask them ...
229                         throw new UnsupportedOperationException("Changing contact entries not finished."); //NOI18N
230                 }
231
232                 // Trace message
233                 this.getLogger().trace("EXIT!"); //NOI18N
234         }
235
236         /**
237          * Allows the user to change his/her own data
238          */
239         @Override
240         public void doChangeOwnData () throws IOException, SQLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
241                 // Trace message
242                 this.getLogger().trace("CALLED!"); //NOI18N
243
244                 /*
245                  * First check if the user has registered own contact, before that
246                  * nothing can be changed.
247                  */
248                 if (!this.isOwnContactAdded()) {
249                         // Not added
250                         this.getClient().outputMessage("Sie haben noch nicht Ihre Daten eingegeben."); //NOI18N
251
252                         // Skip any below code
253                         return;
254                 }
255
256                 // Instance
257                 Contact contact = this.getOwnContact();
258
259                 // It must be found
260                 assert (contact instanceof Contact);
261
262                 // Display contact
263                 contact.show(this.getClient());
264
265                 // Get and cast client instance
266                 AddressbookClient client = (AddressbookClient) this.getClient();
267
268                 try {
269                         // Ask user what to change
270                         client.userChooseChangeContactData(contact);
271                 } catch (final UnhandledUserChoiceException ex) {
272                         this.getLogger().catching(ex);
273                 }
274
275                 // Trace message
276                 this.getLogger().trace("EXIT!"); //NOI18N
277         }
278
279         /**
280          * Let the user delete other address
281          */
282         @Override
283         public void doDeleteOtherAddress () {
284                 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
285         }
286
287         /**
288          * Asks user for own data
289          */
290         @Override
291         public void doEnterOwnData () throws ContactAlreadyAddedException, IOException {
292                 // Trace message
293                 this.getLogger().trace("CALLED!"); //NOI18N
294
295                 // Is own contact already added?
296                 if (this.isOwnContactAdded()) {
297                         // Don't continue here
298                         throw new ContactAlreadyAddedException();
299                 }
300
301                 // Get and cast client instance
302                 AddressbookClient client = (AddressbookClient) this.getClient();
303
304                 // Deligate this call to the client
305                 Contact contact = client.doEnterOwnData();
306
307                 // Is it set?
308                 if (contact instanceof Contact) {
309                         // Add it to contact "book"
310                         this.registerContact(contact);
311                 }
312
313                 // Trace message
314                 this.getLogger().trace("EXIT!"); //NOI18N
315         }
316
317         @Override
318         public void doListContacts () {
319                 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
320         }
321
322         @Override
323         public void doSearchContacts () {
324                 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
325         }
326
327         /**
328          * Shuts down this contact manager
329          * <p>
330          * @throws java.sql.SQLException If an SQL error occurs
331          * @throws java.io.IOException If an IO error occurs
332          */
333         @Override
334         public void doShutdown () throws SQLException, IOException {
335                 // Trace message
336                 this.getLogger().trace("CALLED!"); //NOI18N
337
338                 // Shut down the database layer
339                 ((AddressbookContactFrontend) this.getFrontend()).doShutdown();
340
341                 // Trace message
342                 this.getLogger().trace("EXIT!"); //NOI18N
343         }
344
345         /**
346          * Asks the user for his/her cellphone number
347          * <p>
348          * @return User's cellphone number
349          */
350         @Override
351         public String enterOwnCellNumber () {
352                 // Trace message
353                 this.getLogger().trace("CALLED!"); //NOI18N
354
355                 // Get and cast client instance
356                 AddressbookClient client = (AddressbookClient) this.getClient();
357
358                 return client.enterString(5, 30, "Bitte geben Sie Ihre Handynummer an: ", true);
359         }
360
361         /**
362          * Asks the user for his/her city's name
363          * <p>
364          * @return City's name of the user
365          */
366         @Override
367         public String enterOwnCity () {
368                 // Trace message
369                 this.getLogger().trace("CALLED!"); //NOI18N
370
371                 // Get and cast client instance
372                 AddressbookClient client = (AddressbookClient) this.getClient();
373
374                 return client.enterString(3, 50, "Bitte geben Sie Ihre Wohnort ein: ", false);
375         }
376
377         /**
378          * Asks the user for his/her city's name
379          * <p>
380          * @return City's name of the user
381          */
382         @Override
383         public String enterOwnComment () {
384                 // Trace message
385                 this.getLogger().trace("CALLED!"); //NOI18N
386
387                 // Get and cast client instance
388                 AddressbookClient client = (AddressbookClient) this.getClient();
389
390                 return client.enterString(0, 100, "Kommentar zu Ihrem Eintrag: ", true);
391         }
392
393         /**
394          * Asks the user for his/her company name
395          * <p>
396          * @return User's company name
397          */
398         @Override
399         public String enterOwnCompanyName () {
400                 // Trace message
401                 this.getLogger().trace("CALLED!"); //NOI18N
402
403                 // Get and cast client instance
404                 AddressbookClient client = (AddressbookClient) this.getClient();
405
406                 return client.enterString(5, 50, "Bitte geben Sie Ihre Firmenbezeichnung ein: ", true);
407         }
408
409         /**
410          * Asks user for his/her own country code
411          * <p>
412          * @return User's own country code
413          */
414         @Override
415         public String enterOwnCountryCode () {
416                 // Trace message
417                 this.getLogger().trace("CALLED!"); //NOI18N
418
419                 // Get and cast client instance
420                 AddressbookClient client = (AddressbookClient) this.getClient();
421
422                 return client.enterString(2, 2, "Bitte geben Sie den zweistelligen Ländercode von Ihrem Land ein: ", false).toUpperCase();
423         }
424
425         /**
426          * Asks user for his/her own country code
427          * <p>
428          * @return User's own country code
429          */
430         @Override
431         public String enterOwnEmailAddress () {
432                 // Trace message
433                 this.getLogger().trace("CALLED!"); //NOI18N
434
435                 // Get and cast client instance
436                 AddressbookClient client = (AddressbookClient) this.getClient();
437
438                 return client.enterString(10, 50, "Bitte geben Sie Ihre Email-Adresse ein: ", true);
439         }
440
441         /**
442          * Asks the user for family name
443          * <p>
444          * @return Family name of the user
445          */
446         @Override
447         public String enterOwnFamilyName () {
448                 // Trace message
449                 this.getLogger().trace("CALLED!"); //NOI18N
450
451                 // Get and cast client instance
452                 AddressbookClient client = (AddressbookClient) this.getClient();
453
454                 return client.enterString(2, 50, "Bitte geben Sie Ihren Nachnamen ein: ", false);
455         }
456
457         /**
458          * Asks the user for family name
459          * <p>
460          * @return Family name of the user
461          */
462         @Override
463         public String enterOwnFaxNumber () {
464                 // Trace message
465                 this.getLogger().trace("CALLED!"); //NOI18N
466
467                 // Get and cast client instance
468                 AddressbookClient client = (AddressbookClient) this.getClient();
469
470                 return client.enterString(5, 30, "Bitte geben Sie Ihre Faxnummer an: ", true);
471         }
472
473         /**
474          * Asks the user for surname
475          * <p>
476          * @return Surname of the user
477          */
478         @Override
479         public String enterOwnFirstName () {
480                 // Trace message
481                 this.getLogger().trace("CALLED!"); //NOI18N
482
483                 // Get and cast client instance
484                 AddressbookClient client = (AddressbookClient) this.getClient();
485
486                 return client.enterString(2, 50, "Bitte geben Sie Ihren Vornamen ein: ", false);
487         }
488
489         /**
490          * Asks the user for gender, until a valid has been entered
491          * <p>
492          * @return Gender of the user
493          */
494         @Override
495         public Gender enterOwnGender () {
496                 // Trace message
497                 this.getLogger().trace("CALLED!"); //NOI18N
498
499                 // Get and cast client instance
500                 AddressbookClient client = (AddressbookClient) this.getClient();
501
502                 return client.enterGender("Bitte geben Sie die Anrede ein: (M=Herr, F=Frau, C=Firma): ");
503         }
504
505         /**
506          * Asks the user for phone number
507          * <p>
508          * @return Phone number of the user
509          */
510         @Override
511         public String enterOwnPhoneNumber () {
512                 // Trace message
513                 this.getLogger().trace("CALLED!"); //NOI18N
514
515                 // Get and cast client instance
516                 AddressbookClient client = (AddressbookClient) this.getClient();
517
518                 return client.enterString(5, 30, "Bitte geben Sie Ihre Telefonnummer an: ", true);
519         }
520
521         /**
522          * Asks the user for own street (including number)
523          * <p>
524          * @return Own street an number
525          */
526         @Override
527         public String enterOwnStreet () {
528                 // Trace message
529                 this.getLogger().trace("CALLED!"); //NOI18N
530
531                 // Get and cast client instance
532                 AddressbookClient client = (AddressbookClient) this.getClient();
533
534                 return client.enterString(5, 50, "Bitte geben Sie Ihre Strasse und Hausnummer ein: ", false);
535         }
536
537         /**
538          * Asks the user for own ZIP code
539          * <p>
540          * @return ZIP code
541          */
542         @Override
543         public int enterOwnZipCode () {
544                 // Trace message
545                 this.getLogger().trace("CALLED!"); //NOI18N
546
547                 // Get and cast client instance
548                 AddressbookClient client = (AddressbookClient) this.getClient();
549
550                 return client.enterInt(0, 99_999, "Bitte geben Sie Ihre Postleitzahl ein: ");
551         }
552
553         @Override
554         public final int getColumnCount () {
555                 assert (this.columnNames instanceof List) : "this.columnNames is not initialized"; //NOI18N
556
557                 return this.columnNames.size();
558         }
559
560         @Override
561         public String getColumnName (final int columnIndex) {
562                 assert (this.columnNames instanceof List) : "this.columnNames is not initialized"; //NOI18N
563
564                 // Get column name at index
565                 return this.columnNames.get(columnIndex);
566         }
567
568         @Override
569         public String getTranslatedColumnName (final int columnIndex) {
570                 assert (this.translatedColumnNames instanceof List) : "this.translatedColumnNames is not initialized"; //NOI18N
571
572                 // Get column name at index
573                 return this.translatedColumnNames.get(columnIndex);
574         }
575
576         @Override
577         public Object getValueFromRowColumn (final int rowIndex, final int columnIndex) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
578                 // Trace message
579                 this.getLogger().trace(MessageFormat.format("rowIndex={0},columnIndex={1} CALLED!", rowIndex, columnIndex)); //NOI18N
580
581                 // Then get specific row from database which is a Contact instance
582                 Storable storable = this.getFrontend().getStorableAtRow(rowIndex);
583
584                 // Debug message
585                 this.getLogger().debug(MessageFormat.format("storable={0}", storable)); //NOI18N
586
587                 // It may return null
588                 if (null == storable) {
589                         // Nothing found
590                         this.getLogger().warn("contact is null - returning null ..."); //NOI18N
591                         return null;
592                 }
593
594                 // Convert column index -> name
595                 String columnName = this.getColumnName(columnIndex);
596
597                 // Debug message
598                 this.getLogger().debug(MessageFormat.format("columnName={0}", columnName)); //NOI18N
599
600                 // Now get that column
601                 Object value = null;
602                 try {
603                         value = storable.getValueFromColumn(columnName);
604                 } catch (final IllegalArgumentException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
605                         this.abortProgramWithException(ex);
606                 }
607
608                 // Trace message
609                 this.getLogger().trace(MessageFormat.format("value={0} - EXIT!", value)); //NOI18N
610
611                 // Return it
612                 return value;
613         }
614
615         /**
616          * Checks whether own contact is already added by checking all entries for
617          * isOwnContact flag
618          * <p>
619          * @return Whether own contact is already added
620          */
621         @Override
622         public boolean isOwnContactAdded () throws IOException {
623                 // Trace message
624                 this.getLogger().trace("CALLED!"); //NOI18N
625
626                 // Init variable
627                 boolean isAdded = false;
628
629                 try {
630                         // Deligate this call to frontend
631                         isAdded = ((AddressbookContactFrontend) this.getFrontend()).isOwnContactFound();
632                 } catch (final SQLException | IOException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
633                         // Something bad happened
634                         this.abortProgramWithException(ex);
635                 }
636
637                 // Trace message
638                 this.getLogger().trace(MessageFormat.format("isAdded={0} : EXIT!", isAdded)); //NOI18N
639
640                 // Return result
641                 return isAdded;
642         }
643
644         /**
645          * Adds given contact to address book and flushes all entries to database
646          * <p>
647          * @param contact Contact being added TODO Add check for book size
648          */
649         @Override
650         public void registerContact (final Contact contact) {
651                 // Trace message
652                 this.getLogger().trace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
653
654                 // Sanity check
655                 if (null == contact) {
656                         // Abort here
657                         throw new NullPointerException("contact is null"); //NOI18N
658                 }
659                 try {
660
661                         // Debug message
662                         /*
663                          * NOISY-DEBUG:
664                          */ this.getLogger().debug(MessageFormat.format("Adding '{0}' '{1}' at pos '{2}' ...", contact.getFirstName(), contact.getFamilyName(), this.size())); //NOI18N
665
666                         // Check if contact is found
667                         if (((AddressbookContactFrontend) this.getFrontend()).isContactFound(contact)) {
668                                 // Contact already added
669                                 // TODO Do something here
670                         } else if ((contact.isOwnContact()) && (this.isOwnContactAdded())) {
671                                 // Own contact already added
672                                 // TODO Do something
673                         }
674
675                         // Add contact to internal list
676                         this.addContact(contact);
677                 } catch (final ContactAlreadyAddedException | SQLException | IOException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
678                         // Abort here
679                         this.abortProgramWithException(ex);
680                 }
681
682                 // Trace message
683                 this.getLogger().trace("EXIT!"); //NOI18N
684         }
685
686         /**
687          * Fills the column names array with strings from bundle
688          */
689         private void fillColumnNamesFromBundle () {
690                 assert (this.columnNames instanceof List) : "this.columnNames is not initialized"; //NOI18N
691                 assert (this.translatedColumnNames instanceof List) : "this.translatedColumnNames is not initialized"; //NOI18N
692
693                 // Debug message
694                 this.getLogger().trace("CALLED!"); //NOI18N
695
696                 // First get an iterator from key set to iterate over
697                 Iterator<String> iterator = this.getBundle().keySet().iterator();
698
699                 // Then iterate over all
700                 while (iterator.hasNext()) {
701                         // Get next element
702                         String key = iterator.next().toLowerCase();
703
704                         // Does the key start with AddressbookContactManager.columnName ?
705                         if (key.startsWith("ContactManager.columnName")) { //NOI18N
706                                 // This is the wanted entry.
707                                 this.getLogger().debug(MessageFormat.format("key={0}", key)); //NOI18N
708
709                                 // Convert string to array based on delimiter '.'
710                                 String[] tokens = this.getArrayFromString(key, "."); //NOI18N
711
712                                 // Token array must contain 4 elements (AddressbookContactManager.columnName.foo.text)
713                                 assert (tokens.length == 4) : MessageFormat.format("Array tokens contains not 4 elements: {0}", Arrays.toString(tokens)); //NOI18N
714
715                                 // Get pre-last element
716                                 String columnName = tokens[tokens.length - 2];
717
718                                 // Debug message
719                                 this.getLogger().debug(MessageFormat.format("columnName={0} - adding ...", columnName)); //NOI18N
720
721                                 // So add it
722                                 this.columnNames.add(columnName);
723                                 this.translatedColumnNames.add(this.getBundle().getString(key));
724                         }
725                 }
726
727                 // Debug message
728                 this.getLogger().trace(MessageFormat.format("getColumnCount()={0}: EXIT!", this.getColumnCount())); //NOI18N
729         }
730
731         /**
732          * "Getter" for own contact instance or null if not found
733          * <p>
734          * @return Contact instance or null
735          * @throws java.sql.SQLException If an SQL error occurs
736          * @throws java.io.IOException If an IO error occurs
737          * @throws java.lang.NoSuchMethodException If a method cannot be found
738          * @throws java.lang.IllegalAccessException If a method is not accessible
739          * @throws java.lang.reflect.InvocationTargetException Any other problems?
740          */
741         private Contact getOwnContact () throws IOException, SQLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
742                 // Trace message
743                 this.getLogger().trace("CALLED!"); //NOI18N
744
745                 // Deligate this call to database frontend
746                 Contact contact = ((AddressbookContactFrontend) this.getFrontend()).getOwnContact();
747
748                 // Trace message
749                 this.getLogger().trace(MessageFormat.format("contact={0} - EXIT!", contact)); //NOI18N
750
751                 // Return instance or null
752                 return contact;
753         }
754 }