00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "stat.h"
00030
00031
00032 static void stat_window_connect_signals(heraia_plugin_t *plugin);
00033 static void statw_close_clicked(GtkWidget *widget, gpointer data);
00034 static void destroy_stat_window(GtkWidget *widget, GdkEvent *event, gpointer data);
00035 static void statw_save_as_clicked(GtkWidget *widget, gpointer data);
00036 static gchar *stat_select_file_to_save(void);
00037 static void histo_radiobutton_toggled(GtkWidget *widget, gpointer data);
00038 static gboolean delete_stat_window_event(GtkWidget *widget, GdkEvent *event, gpointer data );
00039 static void realize_some_numerical_stat(heraia_window_t *main_struct, heraia_plugin_t *plugin);
00040 static void init_stats_histos(heraia_plugin_t *plugin);
00041 static void populate_stats_histos(heraia_window_t *main_struct, heraia_plugin_t *plugin);
00042 static void calc_infos_histo_1D(stat_t *extra);
00043 static void calc_infos_histo_2D(stat_t *extra);
00044 static void init_stats_pixbufs(stat_t *extra);
00045 static void make_pixbufs_from_histos(stat_t *extra);
00046 static void plot_in_pixbuf(GdkPixbuf *pixbuf, gint64 x, gint64 y, guchar red, guchar green, guchar blue, guchar alpha);
00047 static void do_pixbuf_1D_from_histo1D(stat_t *extra);
00048 static void do_pixbuf_2D_from_histo2D(stat_t *extra, guint max_2D);
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 heraia_plugin_t *heraia_plugin_init(heraia_plugin_t *plugin)
00059 {
00060 stat_t *extra = NULL;
00061 window_prop_t *stat_prop = NULL;
00062
00063 plugin->state = PLUGIN_STATE_INITIALIZING;
00064 plugin->xml = NULL;
00065
00066 plugin->info->api_version = API_VERSION;
00067 plugin->info->type = PLUGIN_TYPE;
00068 plugin->info->priority = HERAIA_PRIORITY_DEFAULT;
00069 plugin->info->name = PLUGIN_NAME;
00070 plugin->info->version = PLUGIN_VERSION;
00071 plugin->info->summary = PLUGIN_SUMMARY;
00072 plugin->info->description = PLUGIN_DESCRIPTION;
00073 plugin->info->author = PLUGIN_AUTHOR;
00074 plugin->info->homepage = PLUGIN_HOMEPAGE;
00075
00076 plugin->init_proc = init;
00077 plugin->quit_proc = quit;
00078 plugin->run_proc = run;
00079 plugin->refresh_proc = refresh;
00080
00081 plugin->filter->extensions = NULL;
00082 plugin->filter->import = NULL;
00083 plugin->filter->export = NULL;
00084
00085
00086 extra = (stat_t *) g_malloc0 (sizeof(stat_t));
00087 extra->infos_1D = (histo_infos_t *) g_malloc0 (sizeof(histo_infos_t));
00088 extra->infos_2D = (histo_infos_t *) g_malloc0 (sizeof(histo_infos_t));
00089
00090
00091 stat_prop = (window_prop_t *) g_malloc0(sizeof(window_prop_t));
00092 stat_prop->displayed = FALSE;
00093 stat_prop->x = 0;
00094 stat_prop->y = 0;
00095
00096 plugin->win_prop = stat_prop;
00097
00098 plugin->extra = extra;
00099
00100
00101 return plugin;
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 void init(heraia_window_t *main_struct)
00113 {
00114 heraia_plugin_t *plugin = NULL;
00115
00116 log_message(main_struct, G_LOG_LEVEL_INFO, "Initializing plugin %s", PLUGIN_NAME);
00117
00118 plugin = find_plugin_by_name(main_struct->plugins_list, PLUGIN_NAME);
00119
00120 if (plugin != NULL)
00121 {
00122
00123 log_message(main_struct, G_LOG_LEVEL_INFO, "Plugin from %s found !", plugin->info->author);
00124 if (load_plugin_glade_xml(main_struct, plugin) == TRUE)
00125 {
00126 log_message(main_struct, G_LOG_LEVEL_INFO, "%s xml interface loaded.", plugin->info->name);
00127 }
00128 else
00129 {
00130 log_message(main_struct, G_LOG_LEVEL_WARNING, "Unable to load %s xml interface.", plugin->info->name);
00131 }
00132
00133
00134 if (plugin->win_prop->displayed == FALSE)
00135 {
00136 gtk_widget_hide(GTK_WIDGET(glade_xml_get_widget(plugin->xml, "stat_window")));
00137 }
00138 else
00139 {
00140 gtk_check_menu_item_set_active(plugin->cmi_entry, TRUE);
00141 }
00142
00143
00144 stat_window_connect_signals(plugin);
00145
00146 }
00147 }
00148
00149
00150
00151
00152
00153
00154
00155 void quit(void)
00156 {
00157 g_print("Quitting %s\n", PLUGIN_NAME);
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 void run(GtkWidget *widget, gpointer data)
00169 {
00170 heraia_window_t *main_struct = (heraia_window_t *) data;
00171 heraia_plugin_t *plugin = NULL;
00172
00173
00174 plugin = find_plugin_by_name(main_struct->plugins_list, PLUGIN_NAME);
00175
00176 if (plugin != NULL)
00177 {
00178 show_hide_widget(GTK_WIDGET(glade_xml_get_widget(plugin->xml, "stat_window")),
00179 gtk_check_menu_item_get_active(plugin->cmi_entry), plugin->win_prop);
00180 if (gtk_check_menu_item_get_active(plugin->cmi_entry) == TRUE)
00181 {
00182 plugin->state = PLUGIN_STATE_RUNNING;
00183 realize_some_numerical_stat(main_struct, plugin);
00184 }
00185 else
00186 plugin->state = PLUGIN_STATE_NONE;
00187 }
00188
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 void refresh(heraia_window_t *main_struct, void *data)
00202 {
00203 heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00204
00205 if (main_struct != NULL && plugin != NULL)
00206 {
00207 if (main_struct->event == HERAIA_REFRESH_NEW_FILE && plugin->state == PLUGIN_STATE_RUNNING)
00208 {
00209 plugin->run_proc(NULL, (gpointer) main_struct);
00210 }
00211 }
00212 }
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 static gboolean delete_stat_window_event(GtkWidget *widget, GdkEvent *event, gpointer data)
00230 {
00231 statw_close_clicked(widget, data);
00232
00233 return TRUE;
00234 }
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 static void destroy_stat_window(GtkWidget *widget, GdkEvent *event, gpointer data)
00245 {
00246 statw_close_clicked(widget, data);
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256 static void statw_close_clicked(GtkWidget *widget, gpointer data)
00257 {
00258 heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00259
00260 if (plugin != NULL)
00261 {
00262 show_hide_widget(GTK_WIDGET(glade_xml_get_widget(plugin->xml, "stat_window")), FALSE, plugin->win_prop);
00263 gtk_check_menu_item_set_active(plugin->cmi_entry, FALSE);
00264 }
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274 static void statw_save_as_clicked(GtkWidget *widget, gpointer data)
00275 {
00276 heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00277
00278 if (plugin != NULL)
00279 {
00280 GtkImage *image = GTK_IMAGE(glade_xml_get_widget(plugin->xml, "histo_image"));
00281 GdkPixbuf *pixbuf = gtk_image_get_pixbuf(image);
00282 gchar *filename = NULL;
00283 GError **error = NULL;
00284
00285 filename = stat_select_file_to_save();
00286 gdk_pixbuf_save(pixbuf, filename, "png", error, "compression", "9", NULL);
00287
00288 if (filename != NULL)
00289 g_free(filename);
00290 }
00291 }
00292
00293
00294
00295
00296
00297
00298 static gchar *stat_select_file_to_save(void)
00299 {
00300 GtkFileSelection *file_selector = NULL;
00301 gint response_id = 0;
00302 gchar *filename;
00303
00304 file_selector = GTK_FILE_SELECTION (gtk_file_selection_new ("Entrez le nom du fichier image"));
00305
00306
00307 gtk_file_selection_set_select_multiple(file_selector, FALSE);
00308
00309 response_id = gtk_dialog_run(GTK_DIALOG (file_selector));
00310
00311 switch (response_id)
00312 {
00313 case GTK_RESPONSE_OK:
00314 filename = g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_selector)));
00315 break;
00316 case GTK_RESPONSE_CANCEL:
00317 default:
00318 filename = NULL;
00319 break;
00320 }
00321
00322 gtk_widget_destroy (GTK_WIDGET(file_selector));
00323
00324 return filename;
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334 static void histo_radiobutton_toggled(GtkWidget *widget, gpointer data)
00335 {
00336 heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00337
00338 if (plugin != NULL)
00339 {
00340 GtkImage *image = GTK_IMAGE(glade_xml_get_widget(plugin->xml, "histo_image"));
00341 stat_t *extra = (stat_t *) plugin->extra;
00342
00343 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(plugin->xml, "rb_1D"))) == TRUE)
00344 gtk_image_set_from_pixbuf(image, extra->pixbuf_1D);
00345 else
00346 {
00347 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(plugin->xml, "rb_2D"))) == TRUE)
00348 gtk_image_set_from_pixbuf(image, extra->pixbuf_2D);
00349 }
00350 }
00351 }
00352
00353
00354
00355
00356
00357
00358
00359 static void stat_window_connect_signals(heraia_plugin_t *plugin)
00360 {
00361
00362 g_signal_connect(G_OBJECT(glade_xml_get_widget(plugin->xml, "stat_window")), "delete_event",
00363 G_CALLBACK(delete_stat_window_event), plugin);
00364
00365 g_signal_connect(G_OBJECT(glade_xml_get_widget(plugin->xml, "stat_window")), "destroy",
00366 G_CALLBACK(destroy_stat_window), plugin);
00367
00368
00369 g_signal_connect(G_OBJECT(glade_xml_get_widget(plugin->xml, "statw_close_b")), "clicked",
00370 G_CALLBACK(statw_close_clicked), plugin);
00371
00372
00373 g_signal_connect(G_OBJECT(glade_xml_get_widget(plugin->xml, "rb_1D")), "toggled",
00374 G_CALLBACK(histo_radiobutton_toggled), plugin);
00375
00376 g_signal_connect(G_OBJECT(glade_xml_get_widget(plugin->xml, "rb_2D")), "toggled",
00377 G_CALLBACK(histo_radiobutton_toggled), plugin);
00378
00379
00380 g_signal_connect(G_OBJECT(glade_xml_get_widget(plugin->xml, "statw_save_as")), "clicked",
00381 G_CALLBACK(statw_save_as_clicked), plugin);
00382
00383
00384
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394 static void realize_some_numerical_stat(heraia_window_t *main_struct, heraia_plugin_t *plugin)
00395 {
00396 struct stat *stat_buf;
00397 gchar buf[42];
00398 stat_t *extra = NULL;
00399 GtkTextView *textview = GTK_TEXT_VIEW(glade_xml_get_widget(plugin->xml, "statw_textview"));
00400
00401 if (main_struct->filename != NULL)
00402 {
00403 log_message(main_struct, G_LOG_LEVEL_INFO, "Calculating stats on %s", main_struct->filename);
00404
00405 stat_buf = (struct stat *) g_malloc0 (sizeof(struct stat));
00406 lstat(main_struct->filename, stat_buf);
00407 if (S_ISREG(stat_buf->st_mode))
00408 {
00409 kill_text_from_textview(textview);
00410 add_text_to_textview(textview, "File size : %Ld bytes\n\n", stat_buf->st_size);
00411 ctime_r(&(stat_buf->st_mtime), buf);
00412 add_text_to_textview(textview, "Last intern modification : %s", buf);
00413 ctime_r(&(stat_buf->st_atime), buf);
00414 add_text_to_textview(textview, "Last acces to the file : %s", buf);
00415 ctime_r(&(stat_buf->st_ctime), buf);
00416 add_text_to_textview(textview, "Last extern modification : %s", buf);
00417
00418 populate_stats_histos(main_struct, plugin);
00419
00420 extra = (stat_t *) plugin->extra;
00421
00422 add_text_to_textview(textview, "\n1D histogram statistics :\n");
00423 add_text_to_textview(textview, " . minimum : %lld\n", extra->infos_1D->min);
00424 add_text_to_textview(textview, " . maximum : %lld\n", extra->infos_1D->max);
00425 add_text_to_textview(textview, " . mean : %lld\n", extra->infos_1D->mean);
00426 add_text_to_textview(textview, " . number of values : %lld\n", extra->infos_1D->nb_val);
00427 add_text_to_textview(textview, "\n2D histogram statistics :\n");
00428 add_text_to_textview(textview, " . minimum : %lld\n", extra->infos_2D->min);
00429 add_text_to_textview(textview, " . maximum : %lld\n", extra->infos_2D->max);
00430 add_text_to_textview(textview, " . mean : %lld\n", extra->infos_2D->mean);
00431 add_text_to_textview(textview, " . number of values : %lld\n", extra->infos_2D->nb_val);
00432 log_message(main_struct, G_LOG_LEVEL_INFO, "Histos calculated !");
00433 }
00434 }
00435 }
00436
00437
00438
00439
00440
00441 static void init_stats_histos(heraia_plugin_t *plugin)
00442 {
00443 guint i = 0;
00444 guint j = 0;
00445 stat_t *extra = NULL;
00446
00447
00448 extra = (stat_t *) plugin->extra;
00449 for (i=0; i<=255; i++)
00450 {
00451 extra->histo1D[i] = 0 ;
00452 for (j=0; j<=255; j++)
00453 extra->histo2D[i][j] = 0 ;
00454 }
00455 }
00456
00457
00458
00459
00460
00461 static void populate_stats_histos(heraia_window_t *main_struct, heraia_plugin_t *plugin)
00462 {
00463 GtkHex *gh = GTK_HEX(main_struct->current_DW->current_hexwidget);
00464 guint64 i = 0;
00465 guint64 taille = ghex_file_size(gh);
00466 guchar c1, c2;
00467 stat_t *extra = (stat_t *) plugin->extra;
00468 GtkImage *image = GTK_IMAGE(glade_xml_get_widget(plugin->xml, "histo_image"));
00469 GtkToggleButton *rb_1D = GTK_TOGGLE_BUTTON(glade_xml_get_widget(plugin->xml, "rb_1D"));
00470 GtkToggleButton *rb_2D = GTK_TOGGLE_BUTTON(glade_xml_get_widget(plugin->xml, "rb_2D"));
00471
00472 init_stats_histos(plugin);
00473
00474 while (i < taille)
00475 {
00476 c1 = gtk_hex_get_byte(gh, i);
00477 extra->histo1D[c1]++;
00478 if (i+1 < taille)
00479 {
00480 i++;
00481 c2 = gtk_hex_get_byte(gh, i);
00482 extra->histo1D[c2]++;
00483 extra->histo2D[c1][c2]++;
00484 }
00485 i++;
00486 }
00487
00488 make_pixbufs_from_histos(extra);
00489
00490 if (gtk_toggle_button_get_active(rb_1D) == TRUE)
00491 gtk_image_set_from_pixbuf(image, extra->pixbuf_1D);
00492 else
00493 if (gtk_toggle_button_get_active(rb_2D) == TRUE)
00494 gtk_image_set_from_pixbuf(image, extra->pixbuf_2D);
00495 }
00496
00497
00498
00499
00500
00501 static void calc_infos_histo_1D(stat_t *extra)
00502 {
00503 guint i = 0;
00504 gint64 n = 1;
00505 guint64 max = 0;
00506 guint64 min = G_MAXUINT64;
00507 gint64 mean = extra->histo1D[0];
00508 gint64 diff = 0;
00509
00510 extra->infos_1D->nb_val = 0;
00511
00512 for (i=0; i<=255; i++)
00513 {
00514
00515 if (extra->histo1D[i] > max)
00516 max = extra->histo1D[i];
00517
00518
00519 if (extra->histo1D[i] < min)
00520 min = extra->histo1D[i];
00521
00522
00523 if (extra->histo1D[i] > 0)
00524 extra->infos_1D->nb_val++;
00525
00526
00527 diff = extra->histo1D[i] - mean;
00528 mean = mean + diff/n;
00529 n++;
00530 }
00531
00532 extra->infos_1D->min = min;
00533 extra->infos_1D->max = max;
00534 extra->infos_1D->mean = (guint64) mean;
00535 }
00536
00537
00538
00539
00540
00541 static void calc_infos_histo_2D(stat_t *extra)
00542 {
00543 guint i = 0;
00544 guint j = 0;
00545 gint64 n = 1;
00546 guint64 max = 0;
00547 guint64 min = G_MAXUINT;
00548 gint64 mean = extra->histo2D[0][0];
00549 gint64 diff = 0;
00550
00551 extra->infos_2D->nb_val = 0;
00552
00553 for (i=0; i<=255; i++)
00554 {
00555 for (j=0; j<=255; j++)
00556 {
00557
00558 if (extra->histo2D[i][j] > max)
00559 max = extra->histo2D[i][j];
00560
00561
00562 if (extra->histo2D[i][j] < min)
00563 min = extra->histo2D[i][j];
00564
00565
00566 if (extra->histo2D[i][j] > 0)
00567 extra->infos_2D->nb_val++;
00568
00569
00570 diff = extra->histo2D[i][j] - mean;
00571 mean = mean + diff/n;
00572 n++;
00573 }
00574 }
00575
00576 extra->infos_2D->min = min;
00577 extra->infos_2D->max = max;
00578 extra->infos_2D->mean = (guint64) mean;
00579 }
00580
00581
00582
00583
00584
00585 static void init_stats_pixbufs(stat_t *extra)
00586 {
00587
00588 extra->pixbuf_1D = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 255, 255);
00589 gdk_pixbuf_fill(extra->pixbuf_1D, 0xFFFFFF00);
00590 gdk_pixbuf_add_alpha(extra->pixbuf_1D, TRUE, (guchar) 255, (guchar) 255, (guchar) 255);
00591
00592 extra->pixbuf_2D = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 255, 255);
00593 gdk_pixbuf_fill(extra->pixbuf_2D, 0xFFFFFF00);
00594 gdk_pixbuf_add_alpha(extra->pixbuf_2D, TRUE, (guchar) 255, (guchar) 255, (guchar) 255);
00595
00596 }
00597
00598
00599
00600
00601
00602 static void make_pixbufs_from_histos(stat_t *extra)
00603 {
00604 init_stats_pixbufs(extra);
00605 calc_infos_histo_1D(extra);
00606 calc_infos_histo_2D(extra);
00607
00608 if (extra->infos_1D->max > 0)
00609 do_pixbuf_1D_from_histo1D(extra);
00610 if (extra->infos_2D->max > 0)
00611 do_pixbuf_2D_from_histo2D(extra, extra->infos_2D->max);
00612 }
00613
00614
00615
00616
00617
00618 static void plot_in_pixbuf(GdkPixbuf *pixbuf, gint64 x, gint64 y, guchar red, guchar green, guchar blue, guchar alpha)
00619 {
00620 guchar *pixels = NULL;
00621 guchar *p = NULL;
00622
00623 pixels = gdk_pixbuf_get_pixels(pixbuf);
00624
00625 p = pixels + y * gdk_pixbuf_get_rowstride(pixbuf) + x * gdk_pixbuf_get_n_channels(pixbuf);
00626
00627 p[0] = red;
00628 p[1] = green;
00629 p[2] = blue;
00630 p[3] = alpha;
00631
00632 }
00633
00634
00635
00636
00637
00638 static void line_in_pixbuf(GdkPixbuf *pixbuf, gint64 x, gint64 y)
00639 {
00640 guchar *pixels = NULL;
00641 guchar *p = NULL;
00642
00643 if (pixbuf != NULL)
00644 {
00645
00646 gint rowstride = gdk_pixbuf_get_rowstride(pixbuf);
00647 gint n_channels = gdk_pixbuf_get_n_channels(pixbuf);
00648
00649 pixels = gdk_pixbuf_get_pixels(pixbuf);
00650
00651 while (y<255)
00652 {
00653 p = pixels + y * rowstride + x * n_channels;
00654 p[0] = (guchar) 255-(y/2);
00655 p[1] = (guchar) 16;
00656 p[2] = (guchar) y/2;
00657 p[3] = (guchar) 255;
00658 y++;
00659 }
00660 }
00661 }
00662
00663
00664
00665
00666
00667
00668 static void do_pixbuf_1D_from_histo1D(stat_t *extra)
00669 {
00670 guint i = 0;
00671 gint64 y = 0;
00672 gdouble inter = 0;
00673 gdouble y_norm = 0;
00674
00675 for (i=0; i<=255; i++)
00676 {
00677
00678 y_norm = (gdouble) extra->infos_1D->max - (gdouble) extra->histo1D[i];
00679 inter = (gdouble) (y_norm*255) / (gdouble)(extra->infos_1D->max);
00680 y = (gint64) inter;
00681 line_in_pixbuf(extra->pixbuf_1D, i, y);
00682 }
00683 }
00684
00685
00686
00687
00688
00689
00690
00691
00692 static void do_pixbuf_2D_from_histo2D(stat_t *extra, guint max_2D)
00693 {
00694
00695 guint i = 0;
00696 guint j = 0;
00697 guchar red;
00698 guchar green;
00699 guchar blue;
00700 gdouble height = 0;
00701 gdouble max = 0;
00702 gdouble min = 0;
00703 gdouble mean = 0;
00704 gdouble threshold1 = 0;
00705 gdouble threshold2 = 0;
00706 guchar ceill;
00707 guchar floor;
00708
00709 max = extra->infos_2D->max;
00710 min = extra->infos_2D->min;
00711 mean = extra->infos_2D->mean;
00712
00713 threshold1 = min + (mean - min) / 2;
00714 threshold2 = mean + (max - mean) / 2;
00715
00716 floor = (guchar) 50;
00717 ceill = (guchar) 200;
00718
00719 for (i=0; i<=255; i++)
00720 {
00721 for (j=0; j<=255; j++)
00722 {
00723 height = extra->histo2D[i][j];
00724
00725 if (height > 0)
00726 {
00727
00728 if (height >= min && height <= threshold1)
00729 {
00730 red = floor;
00731 green = floor;
00732 blue = (guchar) (height - min)*(ceill-floor) / threshold1;
00733
00734
00735
00736
00737
00738
00739 plot_in_pixbuf(extra->pixbuf_2D, i, 255-j, red, green, blue, (guchar) 255);
00740 }
00741 else if (height > threshold1 && height <= threshold2)
00742 {
00743 red = (guchar) floor;
00744 green = (guchar) (height - threshold1)*(ceill-floor) / (threshold2 - threshold1);
00745 blue = (guchar) floor;
00746 plot_in_pixbuf(extra->pixbuf_2D, i, 255-j, red, green, blue, (guchar) 255);
00747 }
00748 else if (height > threshold2 && height <= max)
00749 {
00750 red = (guchar) (height - threshold2)*(ceill-floor) / (max - threshold2);
00751 green = floor;
00752 blue = floor;
00753
00754
00755
00756
00757
00758
00759 plot_in_pixbuf(extra->pixbuf_2D, i, 255-j, red, green, blue, (guchar) 255);
00760 }
00761 }
00762 }
00763 }
00764 }
00765
00766