]> git.ipfire.org Git - thirdparty/sarg.git/blob - report.c
Output w3c compliant strict html (almost every output).
[thirdparty/sarg.git] / report.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2010
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
24 *
25 */
26
27 #include "include/conf.h"
28 #include "include/defs.h"
29
30 static void maketmp(const char *user, const char *dirname, int debug, int indexonly);
31 static void maketmp_hour(const char *user, const char *dirname, int indexonly);
32 static void gravatmp_hora(const char *dirname, const char *user, const char *data, const char *hora, long long int elap, long long int accbytes, int indexonly);
33 static void gravatmpf(const char *oldaccuser, const char *dirname, const char *oldurl, long long int nacc, long long int nbytes, const char *oldmsg, long long int nelap, int indexonly, long long int incache, long long int oucache);
34 static void gravaporuser(const char *user, const char *dirname, const char *url, const char *ip, const char *data, const char *hora, long long int tam, long long int elap, int indexonly);
35 static void gravager(FILE *fp_gen, const char *user, long long int nacc, const char *url, long long int nbytes, const char *ip, const char *hora, const char *dia, long long int nelap, long long int incache, long long int oucache);
36 static void grava_SmartFilter(const char *dirname, const char *user, const char *ip, const char *data, const char *hora, const char *url, const char *smart);
37
38 void gerarel(void)
39 {
40
41 FILE *fp_in;
42 FILE *fp_gen;
43
44 char accdia[11], acchora[9], accuser[MAXLEN], accip[MAXLEN], accurl[MAXLEN];
45 char oldaccdia[11], oldacchora[9], oldaccip[MAXLEN];
46 char wdirname[MAXLEN], oldurl[MAXLEN], oldaccuser[MAXLEN];
47 char olduser[MAXLEN], oldmsg[50], acccode[MAXLEN/2 - 1], oldacccode[MAXLEN/2 - 1], user[MAXLEN];
48 char ipantes[MAXLEN], nameantes[MAXLEN];
49 char accsmart[MAXLEN];
50 char crc2[MAXLEN/2 -1];
51 long long int nbytes=0;
52 long long int nelap=0;
53 long long int nacc=0;
54 long long int rtotal=0;
55 long long int incache=0;
56 long long int oucache=0;
57 long long int accbytes, accelap;
58 char *str;
59 DIR *dirp;
60 struct dirent *direntp;
61 const char logext[]=".log";
62 int dlen;
63 char siteind[MAXLEN];
64 struct getwordstruct gwarea;
65
66 ipantes[0]='\0';
67 nameantes[0]='\0';
68 smartfilter=0;
69
70 sprintf(dirname, "%s%s", outdir, period);
71 vrfydir(period, addr, site, us, email);
72
73 if(debugz){
74 debugaz("dirname",dirname);
75 }
76
77 gperiod(dirname,period);
78
79 if(UserAgentLog[0] != '\0' && email[0] == '\0') useragent();
80
81 sprintf(wdirname,"%s/sarg-general",dirname);
82 if((fp_gen=MY_FOPEN(wdirname,"a"))==NULL){
83 fprintf(stderr, "SARG: (report) %s: %s\n",text[45],wdirname);
84 exit(1);
85 }
86
87 olduser[0]='\0';
88 strncat(tmp,"/sarg",5);
89
90 dirp = opendir(tmp);
91 while ((direntp = readdir( dirp )) != NULL ) {
92 dlen=strlen(direntp->d_name)-(sizeof(logext)-1);
93 if (dlen<0) continue;
94 if((strcmp(direntp->d_name+dlen,logext) != 0) ||
95 (strncmp(direntp->d_name,"download.log",12) == 0) ||
96 (strncmp(direntp->d_name,"denied.log",10) == 0) ||
97 (strncmp(direntp->d_name,"authfail.log.unsort",19) == 0))
98 continue;
99 if (snprintf(tmp3,sizeof(tmp3),"%s/%s",tmp,direntp->d_name)>=sizeof(tmp3)) {
100 fprintf(stderr, "SARG: (report) directory entry too long: %s/%s\n",tmp,direntp->d_name);
101 exit(1);
102 }
103 if((fp_in=MY_FOPEN(tmp3,"r"))==NULL){
104 fprintf(stderr, "SARG: (report) %s: %s\n",text[45],tmp);
105 exit(1);
106 }
107
108 if (dlen>0) {
109 if (dlen>=sizeof(user)) continue;
110 strncpy(user,direntp->d_name,dlen);
111 user[dlen]=0;
112 } else {
113 user[0]='\0';
114 }
115
116 strcpy(wdirname,dirname);
117 maketmp(user,tmp,debug,indexonly);
118 maketmp_hour(user,tmp,indexonly);
119
120 strcpy(u2,user);
121 if(Ip2Name)
122 ip2name(u2,sizeof(u2));
123 user_find(name,sizeof(name), u2);
124
125 if(dotinuser && strchr(name,'_')) {
126 subs(name,sizeof(name),"_",".");
127 }
128
129 ttopen=0;
130 bzero(html_old, MAXLEN);
131
132 while(fgets(buf,sizeof(buf),fp_in)!=NULL) {
133 getword_start(&gwarea,buf);
134 if (getword(accdia,sizeof(accdia),&gwarea,'\t')<0 || getword(acchora,sizeof(acchora),&gwarea,'\t')<0 ||
135 getword(accuser,sizeof(accuser),&gwarea,'\t')<0 || getword(accip,sizeof(accip),&gwarea,'\t')<0 ||
136 getword(accurl,sizeof(accurl),&gwarea,'\t')<0 || getword_atoll(&accbytes,&gwarea,'\t')<0 ||
137 getword(acccode,sizeof(acccode),&gwarea,'\t')<0) {
138 printf("SARG: Maybe you have a broken record or garbage in your %s file (%d).\n",tmp3,__LINE__);
139 exit(1);
140 }
141 if(strncmp(acccode,"TCP_DENIED/407",14) == 0) continue;
142 if (getword_atoll(&accelap,&gwarea,'\t')<0 || getword_skip(20000,&gwarea,'\t')<0) {
143 printf("SARG: Maybe you have a broken elapsed time in your %s file (%d).\n",tmp3,__LINE__);
144 exit(1);
145 }
146 if (getword(accsmart,sizeof(accsmart),&gwarea,'"')<0) {
147 printf("SARG: Maybe you have a broken smart info in your %s file (%d).\n",tmp3,__LINE__);
148 exit(1);
149 }
150
151 if(accsmart[0] != '\0') {
152 smartfilter++;
153 strcpy(wdirname,dirname);
154 grava_SmartFilter(wdirname,accuser,accip,accdia,acchora,accurl,accsmart);
155 }
156
157 if(Ip2Name) {
158 if(strcmp(accip,ipantes) != 0) {
159 strcpy(ipantes,accip);
160 ip2name(accip,sizeof(accip));
161 strcpy(nameantes,accip);
162 } else strcpy(accip,nameantes);
163 }
164
165 strcpy(wdirname,dirname);
166 gravatmp_hora(wdirname,accuser,accdia,acchora,accelap,accbytes,indexonly);
167
168 if(iprel){
169 strcpy(wdirname,dirname);
170 gravaporuser(accuser,wdirname,accurl,accip,accdia,acchora,accbytes,accelap,indexonly);
171 }
172
173 if(!rtotal){
174 strcpy(oldurl,accurl);
175 strcpy(oldacccode,acccode);
176 strcpy(oldaccuser,accuser);
177 strcpy(oldaccip,accip);
178 strcpy(oldaccdia,accdia);
179 strcpy(oldacchora,acchora);
180 rtotal++;
181 }
182
183 if(site[0] != '\0') {
184 if(strcmp(oldaccuser,accuser) != 0){
185 strcpy(oldmsg,"OK");
186 if(strstr(oldacccode,"DENIED") != 0)
187 sprintf(oldmsg,"%s",text[46]);
188 gravatmp(oldaccuser,oldurl,nacc,nbytes,oldmsg,nelap,indexonly,incache,oucache);
189 gravager(fp_gen,oldaccuser,nacc,oldurl,nbytes,oldaccip,oldacchora,oldaccdia,nelap,incache,oucache);
190 nacc=0;
191 nbytes=0;
192 nelap=0;
193 incache=0;
194 oucache=0;
195 }
196 } else {
197 if(strcmp(oldurl,accurl) != 0 || strcmp(oldaccuser,accuser) != 0){
198 strcpy(oldmsg,"OK");
199 if(strstr(oldacccode,"DENIED") != 0)
200 sprintf(oldmsg,"%s",text[46]);
201 gravatmp(oldaccuser,oldurl,nacc,nbytes,oldmsg,nelap,indexonly,incache,oucache);
202 gravager(fp_gen,oldaccuser,nacc,oldurl,nbytes,oldaccip,oldacchora,oldaccdia,nelap,incache,oucache);
203 nacc=0;
204 nbytes=0;
205 nelap=0;
206 incache=0;
207 oucache=0;
208 if(strcmp(oldaccuser,accuser) != 0)
209 ind2=0;
210 }
211 }
212 nacc++;
213 nbytes+=accbytes;
214 nelap+=accelap;
215
216 if((ReportType & REPORT_TYPE_SITE_USER_TIME_DATE) != 0) {
217 if(!ttopen) {
218 ind2++;
219 strcpy(siteind,accurl);
220 for(str=siteind; *str; str++) {
221 if(*str=='?' || *str=='-' || *str=='.' || *str==':' || *str=='/' || *str=='\\' || *str=='*' ||
222 *str=='\'' || *str=='\"' || *str=='$' || *str=='@')
223 *str='_';
224 }
225 sprintf(arqtt,"%s/%s",dirname,accuser);
226 if(access(arqtt, R_OK) != 0)
227 my_mkdir(arqtt);
228 sprintf(arqtt,"%s/%s/tt%s-%s.html",dirname,accuser,accuser,siteind);
229 if(strlen(arqtt) > 255) {
230 arqtt[255]='\0';
231 }
232 if ((fp_tt = fopen(arqtt, "w")) == 0) {
233 fprintf(stderr, "SARG: (report) %s: %s\n",text[45],arqtt);
234 exit(1);
235 }
236 ttopen=1;
237
238 /*
239 if(Privacy)
240 sprintf(httplink,"<font size=%s color=%s><href=http://%s>%s", \
241 FontSize,PrivacyStringColor,PrivacyString,PrivacyString);
242 else
243 sprintf(httplink,"<font size=%s><a href=\"http://%s\">%s</a>",FontSize,accurl,accurl);
244 */
245
246 sprintf(ltext110,"%s",text[110]);
247 for(str=ltext110; *str; ++str)
248 *str=tolower(*str);
249
250 write_html_header(fp_tt,(IndexTree == INDEX_TREE_DATE) ? 4 : 2,_("Site access report"));
251 fprintf(fp_tt,"<tr><td class=\"header_l\">%s:&nbsp;%s</td></tr>\n",text[89],period);
252 fprintf(fp_tt,"<tr><td class=\"header_l\">%s:&nbsp;%s</td></tr>\n",text[90],name);
253 fprintf(fp_tt,"<tr><td class=\"header_l\">%s:&nbsp;%s, %s</td></tr>\n",text[104],UserSortField,UserSortOrder);
254 fprintf(fp_tt,"<tr><th class=\"header_c\">%s</th></tr>\n",text[32]);
255 close_html_header(fp_tt);
256
257 fputs("<div class=\"report\"><table cellpadding=\"0\" cellspacing=\"2\">\n",fp_tt);
258 fputs("<tr><td></td><td></td></tr>",fp_tt);
259 bzero(tmp4, MAXLEN);
260 strncpy(tmp4,text[110],4);
261 fprintf(fp_tt,"<tr><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th></tr>\n",text[91],tmp4,text[110]+5);
262 }
263
264 sprintf(html,"<tr><td class=\"data\">%s</td><td class=\"data\">%s</td><td class=\"data\">%s</td></tr>\n",accurl,accdia,acchora);
265
266 if(strcmp(html,html_old) != 0)
267 fputs(html,fp_tt);
268 strcpy(html_old, html);
269 } else bzero(ltext110, 50);
270
271 strcpy(crc2,acccode);
272 str=strchr(crc2,'/');
273 if (str) *str='\0';
274
275 if(strstr(crc2,"MISS") != 0)
276 oucache+=accbytes;
277 else incache+=accbytes;
278
279 strcpy(oldurl,accurl);
280
281 if(strcmp(accuser,oldaccuser) != 0) {
282 strcpy(wdirname,dirname);
283 day_totalize(tmp,oldaccuser,indexonly);
284 }
285
286 strcpy(oldaccuser,accuser);
287 strcpy(oldacccode,acccode);
288 strcpy(oldaccip,accip);
289 strcpy(oldaccdia,accdia);
290 strcpy(oldacchora,acchora);
291
292 }
293 bzero(user,MAXLEN);
294 fclose(fp_in);
295 unlink(tmp3);
296 }
297 closedir(dirp);
298
299 strcpy(oldmsg,"OK");
300 if(strstr(oldacccode,"DENIED") != 0)
301 sprintf(oldmsg,"%s",text[46]);
302 strcpy(wdirname,dirname);
303 if(strlen(oldaccuser) == 0)
304 strcpy(oldaccuser,accuser);
305 gravatmpf(oldaccuser,wdirname,oldurl,nacc,nbytes,oldmsg,nelap,indexonly,incache,oucache);
306 strcpy(wdirname,dirname);
307 gravager(fp_gen,oldaccuser,nacc,oldurl,nbytes,oldaccip,oldacchora,oldaccdia,nelap,incache,oucache);
308 fclose(fp_gen);
309 day_totalize(tmp,oldaccuser,indexonly);
310
311 tmpsort();
312
313 strcpy(wdirname,dirname);
314 totalger(wdirname, debug, outdir);
315
316 if(email[0] == '\0') {
317 if((ReportType & REPORT_TYPE_DOWNLOADS) != 0) download_report();
318
319 if(DansGuardianConf[0] != '\0') {
320 strcpy(wdirname,dirname);
321 dansguardian_log();
322 }
323
324 strcpy(wdirname,dirname);
325 squidguard_log();
326
327 strcpy(wdirname,dirname);
328 topuser();
329
330 if((ReportType & REPORT_TYPE_TOPSITES) != 0) topsites();
331
332 if((ReportType & REPORT_TYPE_SITES_USERS) != 0) siteuser();
333 gen_denied_report();
334
335 strcpy(wdirname,dirname);
336 authfail_report();
337
338 if(smartfilter) smartfilter_report();
339
340 if(DansGuardianConf[0] != '\0') dansguardian_report();
341
342 squidguard_report();
343
344 if((ReportType & REPORT_TYPE_USERS_SITES) != 0) htmlrel();
345
346 make_index();
347
348 if(SuccessfulMsg) fprintf(stderr, "SARG: %s %s\n",text[47],dirname);
349 } else {
350 strcpy(wdirname,dirname);
351 geramail(wdirname, debug, outdir, userip, email, TempDir);
352
353 if((strcmp(email,"stdout") != 0) && SuccessfulMsg)
354 fprintf(stderr, "SARG: %s %s\n",text[48],email);
355 }
356
357 if(indexonly) {
358 strcpy(wdirname,dirname);
359 index_only(wdirname, debug);
360 }
361
362 /*
363 2009-10-13(Frederic) This piece of code is never called so it is commented out for good.
364 if(strlen(email) < 0)
365 removetmp(dirname);
366 */
367
368 return;
369 }
370
371 static void maketmp(const char *user, const char *dirname, int debug, int indexonly)
372 {
373
374 FILE *fp_ou;
375
376 char wdirname[MAXLEN];
377
378 if(indexonly) return;
379 if((ReportType & REPORT_TYPE_USERS_SITES) == 0) return;
380
381 strcpy(wdirname,tmp);
382 strcat(wdirname,"/");
383 strcat(wdirname,user);
384
385 if(debug){
386 debuga("%s: %s",text[49],wdirname);
387 }
388
389 strcat(wdirname,".utmp");
390 if((fp_ou=fopen(wdirname,"w"))==NULL){
391 fprintf(stderr, "SARG: (report) %s: %s\n",text[45],wdirname);
392 exit(1);
393 }
394
395 fclose(fp_ou);
396 return;
397 }
398
399
400 static void maketmp_hour(const char *user, const char *dirname, int indexonly)
401 {
402
403 FILE *fp_ou;
404
405 char wdirname[MAXLEN];
406
407 if(indexonly) return;
408 if((ReportType & REPORT_TYPE_USERS_SITES) == 0) return;
409
410 strcpy(wdirname,tmp);
411 strcat(wdirname,"/");
412 strcat(wdirname,user);
413
414 strcat(wdirname,".htmp");
415 if((fp_ou=fopen(wdirname,"w"))==NULL){
416 fprintf(stderr, "SARG: (report-1) %s: %s - %s\n",text[45],wdirname,strerror(errno));
417 exit(1);
418 }
419
420 fclose(fp_ou);
421 return;
422 }
423
424
425 void gravatmp(const char *oldaccuser, const char *oldurl, long long int nacc, long long int nbytes, const char *oldmsg, long long int nelap, int indexonly, long long int incache, long long int oucache)
426 {
427
428 FILE *fp_ou;
429 char val1[16];
430 char val2[16];
431 char val3[16];
432 char val4[16];
433 char val5[16];
434 char wdirname[MAXLEN];
435
436 if(indexonly) return;
437 if((ReportType & REPORT_TYPE_USERS_SITES) == 0) return;
438
439 if (snprintf(wdirname,sizeof(wdirname),"%s/%s.utmp",tmp,oldaccuser)>=sizeof(wdirname)) {
440 fprintf(stderr,"SARG: Path too long %s/%s.utmp\n",tmp,oldaccuser);
441 exit(1);
442 }
443
444 if((fp_ou=MY_FOPEN(wdirname,"a"))==NULL){
445 fprintf(stderr, "SARG: (report) %s: %s\n",text[45],wdirname);
446 exit(1);
447 }
448
449 my_lltoa(nacc,val1,0);
450 my_lltoa(nbytes,val2,0);
451 my_lltoa(nelap,val3,0);
452 my_lltoa(incache,val4,0);
453 my_lltoa(oucache,val5,0);
454 fprintf(fp_ou,"%s\t%s\t%s\t%s\t%s\t%s\t%s\n",val1,val2,oldurl,oldmsg,val3,val4,val5);
455
456 fclose(fp_ou);
457 ttopen=0;
458
459 if(fp_tt) {
460 fputs("</table>\n</div>\n",fp_tt);
461 fputs("</body>\n</html>\n",fp_tt);
462 fclose(fp_tt);
463 }
464
465 return;
466
467 }
468
469
470 static void gravatmp_hora(const char *dirname, const char *user, const char *data, const char *hora, long long int elap, long long int bytes, int indexonly)
471 {
472
473 FILE *fp_ou;
474 char wdirname[MAXLEN];
475
476 if(indexonly || ((ReportType & REPORT_TYPE_USERS_SITES) == 0)) return;
477
478 if (snprintf(wdirname,sizeof(wdirname),"%s/%s.htmp",tmp,user)>=sizeof(wdirname)) {
479 fprintf(stderr,"SARG: Path too long %s/%s.htmp\n",tmp,user);
480 exit(1);
481 }
482
483 if((fp_ou=MY_FOPEN(wdirname,"a"))==NULL){
484 fprintf(stderr, "SARG: (report-2) %s: %s - %s\n",text[45],wdirname,strerror(errno));
485 exit(1);
486 }
487
488 if(strcmp(datetimeby,"bytes") == 0) fprintf(fp_ou,"%s\t%s\t%lld\n",data,hora,bytes);
489 else fprintf(fp_ou,"%s\t%s\t%lld\n",data,hora,elap);
490
491 fclose(fp_ou);
492
493 return;
494 }
495
496
497 static void gravaporuser(const char *user, const char *dirname, const char *url, const char *ip, const char *data, const char *hora, long long int tam, long long int elap, int indexonly)
498 {
499
500 FILE *fp_ou;
501 char wdirname[MAXLEN];
502
503 if(indexonly || ((ReportType & REPORT_TYPE_USERS_SITES) == 0)) return;
504
505 if (snprintf(wdirname,sizeof(wdirname),"%s/%s.ip",tmp,user)>=sizeof(wdirname)) {
506 fprintf(stderr,"SARG: Path too long %s/%s.ip\n",tmp,user);
507 exit(1);
508 }
509
510 if((fp_ou=MY_FOPEN(wdirname,"a"))==NULL){
511 fprintf(stderr, "SARG: (report) %s: %s\n",text[45],wdirname);
512 exit(1);
513 }
514
515 fprintf(fp_ou,"%s\t%s\t%s\t%s\t%lld\t%lld\n",ip,url,data,hora,tam,elap);
516
517 fclose(fp_ou);
518
519 return;
520
521 }
522
523
524 static void gravatmpf(const char *oldaccuser, const char *dirname, const char *oldurl, long long int nacc, long long int nbytes, const char *oldmsg, long long int nelap, int indexonly, long long int incache, long long int oucache)
525 {
526
527 FILE *fp_ou;
528 char wdirname[MAXLEN];
529
530 if(indexonly || ((ReportType & REPORT_TYPE_USERS_SITES) == 0)) return;
531
532 if (snprintf(wdirname,sizeof(wdirname),"%s/%s.utmp",tmp,oldaccuser)>=sizeof(wdirname)) {
533 fprintf(stderr,"SARG: Path too long %s/%s.utmp\n",tmp,oldaccuser);
534 exit(1);
535 }
536
537 if((fp_ou=MY_FOPEN(wdirname,"a"))==NULL){
538 fprintf(stderr, "SARG: (report) %s: %s\n",text[45],wdirname);
539 exit(1);
540 }
541
542 my_lltoa(nacc,val1,0);
543 my_lltoa(nbytes,val2,0);
544 my_lltoa(nelap,val3,0);
545 my_lltoa(incache,val4,0);
546 my_lltoa(oucache,val5,0);
547 fprintf(fp_ou,"%s\t%s\t%s\t%s\t%s\t%s\t%s\n",val1,val2,oldurl,oldmsg,val3,val4,val5);
548
549 fclose(fp_ou);
550 ttopen=0;
551 ind2=0;
552
553 if(fp_tt) {
554 fputs("</table>\n",fp_tt);
555 fputs("</body>\n</html>\n",fp_tt);
556 fclose(fp_tt);
557 }
558
559 return;
560
561 }
562
563
564 static void gravager(FILE *fp_gen, const char *user, long long int nacc, const char *url, long long int nbytes, const char *ip, const char *hora, const char *dia, long long int nelap, long long int incache, long long int oucache)
565 {
566 my_lltoa(nacc,val1,0);
567 my_lltoa(nbytes,val2,0);
568 my_lltoa(nelap,val3,0);
569 my_lltoa(incache,val4,0);
570 my_lltoa(oucache,val5,0);
571 fprintf(fp_gen,"%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",user,val1,val2,url,ip,hora,dia,val3,val4,val5);
572 return;
573
574 }
575
576 static void grava_SmartFilter(const char *dirname, const char *user, const char *ip, const char *data, const char *hora, const char *url, const char *smart)
577 {
578
579 FILE *fp_ou;
580 char wdirname[MAXLEN];
581
582 sprintf(wdirname,"%s/smartfilter.unsort",dirname);
583
584 if((fp_ou=MY_FOPEN(wdirname,"a"))==NULL){
585 fprintf(stderr, "SARG: (report) %s: %s\n",text[45],wdirname);
586 exit(1);
587 }
588
589 fprintf(fp_ou,"%s\t%s\t%s\t%s\t%s\t%s\n",user,data,hora,ip,url,smart);
590 fputs("</body>\n</html>\n",fp_tt);
591
592 fclose(fp_ou);
593
594 return;
595
596 }