1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2014
3 // David Freese, W1HKJ
4 //
5 // This file is part of flmsg
6 //
7 // flrig is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // flrig is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 // ----------------------------------------------------------------------------
20
21 #include <stdlib.h>
22 #include <iostream>
23 #include <fstream>
24 #include <cstring>
25 #include <ctime>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <stdio.h>
29 #include <errno.h>
30
31 #include <FL/Fl.H>
32 #include <FL/Enumerations.H>
33 #include <FL/Fl_Window.H>
34 #include <FL/Fl_Button.H>
35 #include <FL/Fl_Group.H>
36 #include <FL/Fl_Sys_Menu_Bar.H>
37 #include <FL/x.H>
38 #include <FL/Fl_Help_Dialog.H>
39 #include <FL/Fl_Menu_Item.H>
40 #include <FL/Fl_File_Icon.H>
41
42 #include "config.h"
43 #include "flmsg_config.h"
44
45 #include "flmsg.h"
46 #include "templates.h"
47 #include "debug.h"
48 #include "util.h"
49 #include "gettext.h"
50 #include "flmsg_dialog.h"
51 #include "flinput2.h"
52 #include "date.h"
53 #include "calendar.h"
54 #include "icons.h"
55 #include "fileselect.h"
56 #include "wrap.h"
57 #include "status.h"
58 #include "parse_xml.h"
59 #include "flmsg_strings.h"
60
61 #ifdef WIN32
62 # include "flmsgrc.h"
63 # include "compat.h"
64 # define dirent fl_dirent_no_thanks
65 #endif
66
67 #include <FL/filename.H>
68 #include "dirent-check.h"
69
70 #include <FL/x.H>
71 #include <FL/Fl_Pixmap.H>
72 #include <FL/Fl_Image.H>
73
74 using namespace std;
75
76 // ---------------------------------------------------------------------
77 // ics 110 field variables and template variables
78 // ---------------------------------------------------------------------
79
80 string cap110_mission_nbr = ":mnbr:";
81 string cap110_station = ":sta:";
82 string cap110_date = ":date:";
83 string cap110_ds_a = ":ds_a:";
84 string cap110_ds_b = ":ds_b:";
85 string cap110_ds_c = ":ds_c:";
86 string cap110_ds_d = ":ds_d:";
87 string cap110_ds_e = ":ds_e:";
88 string cap110_ds_f = ":ds_f:";
89
90 string cap110_comm_time = ":time[n]:"; // 23
91 string cap110_comm_chref = ":chref[n]:"; // 23
92 string cap110_comm_call = ":call[n]:"; // 23
93 string cap110_comm_rem = ":rem[n]:"; // 23
94
95 string s110_mission_nbr;
96 string s110_station;
97 string s110_date;
98 string s110_ds_a;
99 string s110_ds_b;
100 string s110_ds_c;
101 string s110_ds_d;
102 string s110_ds_e;
103 string s110_ds_f;
104
105 string s110_comm_time[23];
106 string s110_comm_call[23];
107 string s110_comm_chref[23];
108 string s110_comm_rem[23];
109
110 // =====================================================================
111
112 string buff_c110;
113 string cap110_def_filename= "";
114 string cap110_base_filename = "";
115 string cap110_def_template_name = "";
116 bool using_cap110_template = false;
117
cap110_set_date()118 void cap110_set_date()
119 {
120 string date = szCAPDateTime();
121 date.erase(2,6);
122 txt_110_date->value(date.c_str());
123 }
124
clear_110fields()125 void clear_110fields()
126 {
127 s110_mission_nbr.clear();
128 s110_station.clear();
129 s110_date.clear();
130 s110_ds_a.clear();
131 s110_ds_b.clear();
132 s110_ds_c.clear();
133 s110_ds_d.clear();
134 s110_ds_e.clear();
135 s110_ds_f.clear();
136
137 for (int i = 0; i < 23; i++) {
138 s110_comm_time[i].clear();
139 s110_comm_call[i].clear();
140 s110_comm_chref[i].clear();
141 s110_comm_rem[i].clear();
142 }
143 }
144
check_110fields()145 bool check_110fields()
146 {
147 if (s110_mission_nbr != txt_110_mission_nbr->value())
148 return true;
149 if (s110_station != txt_110_station->value())
150 return true;
151 if (s110_date != txt_110_date->value())
152 return true;
153 if (s110_ds_a != txt_110_ds_a->value())
154 return true;
155 if (s110_ds_b != txt_110_ds_b->value())
156 return true;
157 if (s110_ds_c != txt_110_ds_c->value())
158 return true;
159 if (s110_ds_d != txt_110_ds_d->value())
160 return true;
161 if (s110_ds_e != txt_110_ds_e->value())
162 return true;
163 if (s110_ds_f != txt_110_ds_f->value())
164 return true;
165 for (int i = 0; i < 23; i++) {
166 if (s110_comm_time[i] != txt_110_comm_time[i]->value())
167 return true;
168 if (s110_comm_call[i] != txt_110_comm_call[i]->value())
169 return true;
170 if (s110_comm_chref[i] != txt_110_comm_chref[i]->value())
171 return true;
172 if (s110_comm_rem[i] != txt_110_comm_rem[i]->value())
173 return true;
174 }
175 return false;
176 }
177
update_110fields()178 void update_110fields()
179 {
180 s110_mission_nbr = txt_110_mission_nbr->value();
181 s110_station = txt_110_station->value();
182 s110_date = txt_110_date->value();
183 s110_ds_a = txt_110_ds_a->value();
184 s110_ds_b = txt_110_ds_b->value();
185 s110_ds_c = txt_110_ds_c->value();
186 s110_ds_d = txt_110_ds_d->value();
187 s110_ds_e = txt_110_ds_e->value();
188 s110_ds_f = txt_110_ds_f->value();
189 for (int i = 0; i < 23; i++) {
190 s110_comm_time[i] = txt_110_comm_time[i]->value();
191 s110_comm_call[i] = txt_110_comm_call[i]->value();
192 s110_comm_chref[i] = txt_110_comm_chref[i]->value();
193 s110_comm_rem[i] = txt_110_comm_rem[i]->value();
194 }
195 }
196
update_110form()197 void update_110form()
198 {
199 txt_110_mission_nbr->value(s110_mission_nbr.c_str());
200 txt_110_station->value(s110_station.c_str());
201 txt_110_date->value(s110_date.c_str());
202 txt_110_ds_a->value(s110_ds_a.c_str());
203 txt_110_ds_b->value(s110_ds_b.c_str());
204 txt_110_ds_c->value(s110_ds_c.c_str());
205 txt_110_ds_d->value(s110_ds_d.c_str());
206 txt_110_ds_e->value(s110_ds_e.c_str());
207 txt_110_ds_f->value(s110_ds_f.c_str());
208
209 for (int i = 0; i < 23; i++) {
210 txt_110_comm_time[i]->value(s110_comm_time[i].c_str());
211 txt_110_comm_call[i]->value(s110_comm_call[i].c_str());
212 txt_110_comm_chref[i]->value(s110_comm_chref[i].c_str());
213 txt_110_comm_rem[i]->value(s110_comm_rem[i].c_str());
214 }
215 }
216
clear_110_form()217 void clear_110_form()
218 {
219 clear_110fields();
220 update_110form();
221 }
222
cap110_nn(string & subst,int n)223 string &cap110_nn(string & subst, int n)
224 {
225 static string garbage = "#$^*!";
226 static string ics;
227 ics.clear();
228 ics = subst;
229 size_t pos = ics.find("[");
230 if (pos == string::npos) return garbage;
231 pos++;
232 if (n < 10)
233 ics[pos] = '0' + n;
234 else {
235 ics[pos] = n > 19 ? '2' : '1';
236 ics[pos+1] = '0' + n % 10;
237 ics[pos+2] = ']';
238 ics += ':';
239 }
240 return ics;
241 }
242
make_buff_c110(bool compress=false)243 void make_buff_c110(bool compress = false)
244 {
245 string mbuff;
246 mbuff.clear();
247 mbuff.append( lineout( cap110_mission_nbr, s110_mission_nbr ) );
248 mbuff.append( lineout( cap110_station, s110_station ) );
249 mbuff.append( lineout( cap110_date, s110_date ) );
250 mbuff.append( lineout( cap110_ds_a, s110_ds_a ) );
251 mbuff.append( lineout( cap110_ds_b, s110_ds_b ) );
252 mbuff.append( lineout( cap110_ds_c, s110_ds_c ) );
253 mbuff.append( lineout( cap110_ds_d, s110_ds_d ) );
254 mbuff.append( lineout( cap110_ds_e, s110_ds_e ) );
255 mbuff.append( lineout( cap110_ds_f, s110_ds_f ) );
256
257 for (int i = 0; i < 23; i++) {
258 mbuff.append( lineout( cap110_nn( cap110_comm_time, i ), s110_comm_time[i] ) );
259 mbuff.append( lineout( cap110_nn( cap110_comm_call, i ), s110_comm_call[i] ) );
260 mbuff.append( lineout( cap110_nn( cap110_comm_chref, i ), s110_comm_chref[i] ) );
261 mbuff.append( lineout( cap110_nn( cap110_comm_rem, i ), s110_comm_rem[i] ) );
262 }
263 if (compress) compress_maybe(mbuff);
264 buff_c110.append(mbuff);
265 }
266
read_c110_buffer(string data)267 void read_c110_buffer(string data)
268 {
269 clear_110fields();
270 read_header(data);
271
272 s110_mission_nbr = findstr( data, cap110_mission_nbr );
273 s110_station = findstr( data, cap110_station );
274 s110_date = findstr( data, cap110_date );
275 s110_ds_a = findstr( data, cap110_ds_a );
276 s110_ds_b = findstr( data, cap110_ds_b );
277 s110_ds_c = findstr( data, cap110_ds_c );
278 s110_ds_d = findstr( data, cap110_ds_d );
279 s110_ds_e = findstr( data, cap110_ds_e );
280 s110_ds_f = findstr( data, cap110_ds_f );
281
282 for (int i = 0; i < 23; i++) {
283 s110_comm_time[i] = findstr( data, cap110_nn( cap110_comm_time, i ) );
284 s110_comm_call[i] = findstr( data, cap110_nn( cap110_comm_call, i ) );
285 s110_comm_chref[i] = findstr( data, cap110_nn( cap110_comm_chref, i ) );
286 s110_comm_rem[i] = findstr( data, cap110_nn( cap110_comm_rem, i ) );
287 }
288
289 update_110form();
290
291 }
292
cap110_cb_load_template(string data)293 void cap110_cb_load_template(string data)
294 {
295 clear_110fields();
296 read_header(data);
297
298 s110_mission_nbr = findstr( data, cap110_mission_nbr );
299 s110_station = findstr( data, cap110_station );
300 s110_date = findstr( data, cap110_date );
301 s110_ds_a = findstr( data, cap110_ds_a );
302 s110_ds_b = findstr( data, cap110_ds_b );
303 s110_ds_c = findstr( data, cap110_ds_c );
304 s110_ds_d = findstr( data, cap110_ds_d );
305 s110_ds_e = findstr( data, cap110_ds_e );
306 s110_ds_f = findstr( data, cap110_ds_f );
307
308 for (int i = 0; i < 23; i++) {
309 s110_comm_time[i] = findstr( data, cap110_nn( cap110_comm_time, i ) );
310 s110_comm_call[i] = findstr( data, cap110_nn( cap110_comm_call, i ) );
311 s110_comm_chref[i] = findstr( data, cap110_nn( cap110_comm_chref, i ) );
312 s110_comm_rem[i] = findstr( data, cap110_nn( cap110_comm_rem, i ) );
313 }
314
315 update_110form();
316 }
317
cap110_cb_new()318 void cap110_cb_new()
319 {
320 if (check_110fields()) {
321 if (fl_choice2(xMODIFIED, "No", xMODIFIED, NULL) == 1) {
322 update_header(CHANGED);
323 cap110_cb_save();
324 }
325 }
326 clear_110_form();
327 clear_header();
328 cap110_def_filename= ICS_msg_dir;
329 cap110_def_filename.append(xNEW).append(CAP110_FILE_EXT);
330 show_filename(cap110_def_filename);
331 using_cap110_template = false;
332 }
333
cap110_cb_import()334 void cap110_cb_import()
335 {
336 fl_alert2(xNOTIMPLEMENTED);
337 }
338
cap110_cb_export()339 void cap110_cb_export()
340 {
341 fl_alert2(xNOTIMPLEMENTED);
342 }
343
cap110_cb_wrap_import(string wrapfilename,string inpbuffer)344 void cap110_cb_wrap_import(string wrapfilename, string inpbuffer)
345 {
346 clear_110_form();
347 cap110_cb_load_template(inpbuffer);
348 cap110_def_filename= ICS_msg_dir;
349 cap110_def_filename.append(wrapfilename);
350 show_filename(cap110_def_filename);
351 using_cap110_template = false;
352 }
353
eval_cap110_fsize()354 int eval_cap110_fsize()
355 {
356 Ccrc16 chksum;
357 evalstr.assign("[WRAP:beg][WRAP:lf][WRAP:fn ");
358 evalstr.append(cap110_base_filename).append("]");
359 update_110fields();
360 update_header(FROM);
361 evalstr.append(header("<cap110>"));
362 buff_c110.clear();
363 make_buff_c110(true);
364 if (buff_c110.empty()) return 0;
365 compress_maybe( buff_c110 );
366 evalstr.append( buff_c110 );
367 evalstr.append("[WRAP:chksum ").append(chksum.scrc16(evalstr)).append("][WRAP:end]");
368 return evalstr.length();
369 }
370
cap110_cb_wrap_export()371 void cap110_cb_wrap_export()
372 {
373 if (check_110fields()) {
374 if (fl_choice2(xMODIFIED, "No", xMODIFIED, NULL) == 0)
375 return;
376 update_header(CHANGED);
377 }
378 update_110fields();
379
380 if (cap110_base_filename == string(xNEW).append(CAP110_FILE_EXT) ||
381 cap110_base_filename == string(xDEFAULT).append(CAP110_FILE_EXT) )
382 if (!cap110_cb_save_as()) return;
383
384 string wrapfilename = WRAP_send_dir;
385 wrapfilename.append(cap110_base_filename);
386 wrapfilename.append(".wrap");
387 const char *p = FSEL::saveas(
388 xSAVEASWRAP,
389 xWRAPFILE,
390 wrapfilename.c_str());
391 if (p) {
392 string pext = fl_filename_ext(p);
393 wrapfilename = p;
394 update_header(FROM);
395 buff_c110.assign(header("<cap110>"));
396 make_buff_c110(true);
397 export_wrapfile(cap110_base_filename, wrapfilename, buff_c110, pext != ".wrap");
398 write_110(cap110_def_filename);
399 }
400 }
401
cap110_cb_wrap_autosend()402 void cap110_cb_wrap_autosend()
403 {
404 if (check_110fields()) {
405 if (fl_choice2(xMODIFIED, "No", xMODIFIED, NULL) == 0)
406 return;
407 update_header(CHANGED);
408 }
409 update_110fields();
410
411 if (cap110_base_filename == string(xNEW).append(CAP110_FILE_EXT) ||
412 cap110_base_filename == string(xDEFAULT).append(CAP110_FILE_EXT) )
413 cap110_cb_save_as();
414
415 update_header(FROM);
416 buff_c110.assign(header("<cap110>"));
417 make_buff_c110(true);
418
419 xfr_via_socket(cap110_base_filename, buff_c110);
420 write_110(cap110_def_filename);
421 }
422
cap110_cb_load_template()423 void cap110_cb_load_template()
424 {
425 string cap110_def_filename= cap110_def_template_name;
426 const char *p = FSEL::select(
427 xOPENTEMPLATE,
428 string(xTEMPLATEFILE).append(CAP110_TEMP_EXT).c_str(),
429 cap110_def_filename.c_str());
430 if (p) {
431 clear_110_form();
432 read_data_file(p);
433 cap110_def_template_name = p;
434 show_filename(cap110_def_template_name);
435 using_cap110_template = true;
436 }
437 }
438
cap110_cb_save_template()439 void cap110_cb_save_template()
440 {
441 if (!using_cap110_template) {
442 cap110_cb_save_as_template();
443 return;
444 }
445 string cap110_def_filename= cap110_def_template_name;
446 const char *p = FSEL::saveas(
447 xSAVEASTEMPLATE,
448 string(xTEMPLATEFILE).append(CAP110_TEMP_EXT).c_str(),
449 cap110_def_filename.c_str());
450 if (p) {
451 update_header(CHANGED);
452 buff_c110.assign(header("<cap110>"));
453 make_buff_c110();
454 write_110(p);
455 }
456 }
457
cap110_cb_save_as_template()458 void cap110_cb_save_as_template()
459 {
460 string cap110_def_filename= cap110_def_template_name;
461 const char *p = FSEL::saveas(
462 xSAVEASTEMPLATE,
463 string(xTEMPLATEFILE).append(CAP110_TEMP_EXT).c_str(),
464 cap110_def_filename.c_str());
465 if (p) {
466 const char *pext = fl_filename_ext(p);
467 cap110_def_template_name = p;
468 if (strlen(pext) == 0) cap110_def_template_name.append(CAP110_TEMP_EXT);
469 remove_spaces_from_filename(cap110_def_template_name);
470 clear_header();
471 update_header(CHANGED);
472 buff_c110.assign(header("<cap110>"));
473 make_buff_c110();
474 write_110(cap110_def_template_name);
475 show_filename(cap110_def_template_name);
476 using_cap110_template = true;
477 }
478 }
479
cap110_cb_open()480 void cap110_cb_open()
481 {
482 const char *p = FSEL::select(
483 _(xOPENDATAFILE),
484 string("CAP-110\t*").append(CAP110_FILE_EXT).c_str(),
485 cap110_def_filename.c_str());
486 if (!p) return;
487 if (strlen(p) == 0) return;
488 clear_110_form();
489 read_data_file(p);
490 using_cap110_template = false;
491 cap110_def_filename= p;
492 show_filename(cap110_def_filename);
493 }
494
write_110(string s)495 void write_110(string s)
496 {
497 FILE *file110 = fopen(s.c_str(), "w");
498 if (!file110) return;
499
500 fwrite(buff_c110.c_str(), buff_c110.length(), 1, file110);
501 fclose(file110);
502 }
503
cap110_cb_save_as()504 bool cap110_cb_save_as()
505 {
506 const char *p;
507 string newfilename;
508
509 string name = named_file();
510 if (!name.empty()) {
511 name.append(CAP110_FILE_EXT);
512 newfilename = ICS_msg_dir;
513 newfilename.append(name);
514 } else
515 newfilename = cap110_def_filename;
516
517 p = FSEL::saveas(
518 _(xSAVEDATAFILE),
519 string("CAP-110\t*").append(CAP110_FILE_EXT).c_str(),
520 newfilename.c_str());
521
522 if (!p) return false;
523 if (strlen(p) == 0) return false;
524
525 if (progStatus.sernbr_fname) update_sernbr();
526
527 const char *pext = fl_filename_ext(p);
528 cap110_def_filename= p;
529 if (strlen(pext) == 0) cap110_def_filename.append(CAP110_FILE_EXT);
530
531 remove_spaces_from_filename(cap110_def_filename);
532 update_110fields();
533 update_header(NEW);
534 buff_c110.assign(header("<cap110>"));
535 make_buff_c110();
536 write_110(cap110_def_filename);
537
538 using_cap110_template = false;
539 show_filename(cap110_def_filename);
540 return true;
541 }
542
cap110_cb_save()543 void cap110_cb_save()
544 {
545 if (cap110_base_filename == string(xNEW).append(CAP110_FILE_EXT) ||
546 cap110_base_filename == string(xDEFAULT).append(CAP110_FILE_EXT) ||
547 using_cap110_template == true) {
548 cap110_cb_save_as();
549 return;
550 }
551 if (check_110fields()) update_header(CHANGED);
552 update_110fields();
553 buff_c110.assign(header("<cap110>"));
554 make_buff_c110();
555 write_110(cap110_def_filename);
556 using_cap110_template = false;
557 }
558
cap110_cb_html()559 void cap110_cb_html()
560 {
561 string fname_name = fl_filename_name(cap110_def_filename.c_str());
562 size_t p = fname_name.rfind('.');
563 if (p != string::npos) fname_name.erase(p);
564
565 string cap110_fname = ICS_dir;
566 cap110_fname.append(fname_name);
567 cap110_fname.append(".html");
568
569 string html_text = "";
570 string empty = "<br>";
571
572 update_110fields();
573 string form110 = cap110_html_template;
574
575 replacestr(form110, TITLE, fname_name);
576 replacestr(form110, cap110_mission_nbr, s110_mission_nbr );
577 replacestr(form110, cap110_station, s110_station );
578 replacestr(form110, cap110_date, s110_date );
579 replacestr(form110, cap110_ds_a, s110_ds_a );
580 replacestr(form110, cap110_ds_b, s110_ds_b );
581 replacestr(form110, cap110_ds_c, s110_ds_c );
582 replacestr(form110, cap110_ds_d, s110_ds_d );
583 replacestr(form110, cap110_ds_e, s110_ds_e );
584 replacestr(form110, cap110_ds_f, s110_ds_f );
585
586 for (int i = 0; i < 23; i++) {
587 replacestr(form110, cap110_nn( cap110_comm_time, i ),
588 s110_comm_time[i].empty() ? empty : s110_comm_time[i] );
589 replacestr(form110, cap110_nn( cap110_comm_call, i ),
590 s110_comm_call[i].empty() ? empty : s110_comm_call[i] );
591 replacestr(form110, cap110_nn( cap110_comm_chref, i ),
592 s110_comm_chref[i].empty() ? empty : s110_comm_chref[i] );
593 replacestr(form110, cap110_nn( cap110_comm_rem, i ),
594 s110_comm_rem[i].empty() ? empty : s110_comm_rem[i] );
595 }
596
597 FILE *file110 = fopen(cap110_fname.c_str(), "w");
598 fprintf(file110,"%s", form110.c_str());
599 fclose(file110);
600
601 open_url(cap110_fname.c_str());
602 }
603
cap110_cb_msg_type()604 void cap110_cb_msg_type()
605 {
606 if (tabs_msg_type->value() == tab_cap110 )
607 show_filename(cap110_def_filename);
608 }
609
cap110_cb_textout()610 void cap110_cb_textout()
611 {
612 string cap110_fname = ICS_dir;
613 cap110_fname.append("cap110.txt");
614
615 update_110fields();
616 string form110 = cap110_text_template;
617
618 replacestr(form110, cap110_mission_nbr, s110_mission_nbr );
619 replacestr(form110, cap110_station, s110_station );
620 replacestr(form110, cap110_date, s110_date );
621 replacestr(form110, cap110_ds_a, s110_ds_a );
622 replacestr(form110, cap110_ds_b, s110_ds_b );
623 replacestr(form110, cap110_ds_c, s110_ds_c );
624 replacestr(form110, cap110_ds_d, s110_ds_d );
625 replacestr(form110, cap110_ds_e, s110_ds_e );
626 replacestr(form110, cap110_ds_f, s110_ds_f );
627
628 string logdata;
629 string lgdata = xLOGDATA;
630 const char *fmt = "%-7s|%-12s|%-15s|%s\n";
631 char tempstr[200];
632 snprintf(tempstr, sizeof(tempstr), fmt, "TIME", "CALL", "CH REF", "REMARKS");
633
634 logdata = tempstr;
635 for (int i = 0; i < 23; i++) {
636 if (!s110_comm_time[i].empty() ||
637 !s110_comm_call[i].empty() ||
638 !s110_comm_chref[i].empty() ||
639 !s110_comm_rem[i].empty() ) {
640 snprintf(tempstr, sizeof(tempstr), fmt,
641 s110_comm_time[i].c_str(),
642 s110_comm_call[i].c_str(),
643 s110_comm_chref[i].c_str(),
644 s110_comm_rem[i].c_str());
645 logdata.append(tempstr);
646 }
647 }
648 replacestr(form110, lgdata, logdata);
649
650 FILE *file110 = fopen(cap110_fname.c_str(), "w");
651 fprintf(file110,"%s", form110.c_str());
652 fclose(file110);
653
654 open_url(cap110_fname.c_str());
655 }
656
657