void weechat_display_keys () { struct t_gui_key *ptr_key; char *expanded_name; int i; for (i = 0; i < GUI_KEY_NUM_CONTEXTS; i++) { gui_key_default_bindings (i); string_iconv_fprintf (stdout, /* TRANSLATORS: first "%s" is "weechat" */ _("%s default keys (context: \"%s\"):\n"), (gui_key_context_string[i] && gui_key_context_string[i][0]) ? _(gui_key_context_string[i]) : "", PACKAGE_NAME); string_iconv_fprintf (stdout, "\n"); for (ptr_key = gui_keys[i]; ptr_key; ptr_key = ptr_key->next_key) { expanded_name = gui_key_get_expanded_name (ptr_key->key); string_iconv_fprintf (stdout, "* %s => %s\n", (expanded_name) ? expanded_name : ptr_key->key, ptr_key->command); if (expanded_name) free (expanded_name); } } }
void debug_sigsegv () { debug_dump (1); unhook_all (); gui_main_end (0); string_iconv_fprintf ( stderr, "\n" "*** Very bad! WeeChat is crashing (SIGSEGV received)\n"); if (!log_crash_rename ()) { string_iconv_fprintf ( stderr, "*** Full crash dump was saved to %s/weechat.log file.\n", weechat_home); } string_iconv_fprintf ( stderr, "***\n" "*** Please help WeeChat developers to fix this bug:\n" "*** 1. If you have a core file, please run: gdb /path/to/weechat core\n" "*** then issue command: \"bt full\" and send result to developers\n" "*** (see user's guide for more info about report of crashes).\n" "*** 2. Otherwise send backtrace (below), only if it is a complete trace.\n" "*** Keep the crash log file, just in case developers ask you some info\n" "*** (be careful, private info like passwords may be in this file).\n\n"); weechat_backtrace (); /* shutdown with error code */ weechat_shutdown (EXIT_FAILURE, 1); }
void weechat_display_usage (char *exec_name) { weechat_display_copyright (); string_iconv_fprintf (stdout, "\n"); string_iconv_fprintf (stdout, _("Usage: %s [option...] [plugin:option...]\n"), exec_name, exec_name); string_iconv_fprintf (stdout, "\n"); string_iconv_fprintf (stdout, _(" -a, --no-connect disable auto-connect to servers at startup\n" " -c, --colors display default colors in terminal\n" " -d, --dir <path> set WeeChat home directory (default: ~/.weechat)\n" " -h, --help this help\n" " -k, --keys display WeeChat default keys\n" " -l, --license display WeeChat license\n" " -p, --no-plugin don't load any plugin at startup\n" " -r, --run-command run command(s) after startup\n" " (many commands can be separated by semicolons)\n" " -s, --no-script don't load any script at startup\n" " -v, --version display WeeChat version\n" " plugin:option option for plugin\n" " for example, irc plugin can connect\n" " to server with url like:\n" " irc[6][s]://[nickname[:password]@]" "irc.example.org[:port][/#channel1][,#channel2[...]]\n" " (look at plugins documentation for more information\n" " about possible options)\n")); string_iconv_fprintf(stdout, "\n"); }
TEST(String, Iconv) { const char *noel_utf8 = "no\xc3\xabl"; /* noël */ const char *noel_iso = "no\xebl"; char *str; FILE *f; /* string_iconv */ WEE_TEST_STR(NULL, string_iconv (0, NULL, NULL, NULL)); WEE_TEST_STR("", string_iconv (0, NULL, NULL, "")); WEE_TEST_STR("abc", string_iconv (0, NULL, NULL, "abc")); WEE_TEST_STR("abc", string_iconv (1, "UTF-8", "ISO-8859-15", "abc")); WEE_TEST_STR(noel_iso, string_iconv (1, "UTF-8", "ISO-8859-15", noel_utf8)); WEE_TEST_STR(noel_utf8, string_iconv (0, "ISO-8859-15", "UTF-8", noel_iso)); /* string_iconv_to_internal */ WEE_TEST_STR(NULL, string_iconv_to_internal (NULL, NULL)); WEE_TEST_STR("", string_iconv_to_internal (NULL, "")); WEE_TEST_STR("abc", string_iconv_to_internal (NULL, "abc")); WEE_TEST_STR(noel_utf8, string_iconv_to_internal ("ISO-8859-15", noel_iso)); /* string_iconv_from_internal */ WEE_TEST_STR(NULL, string_iconv_from_internal (NULL, NULL)); WEE_TEST_STR("", string_iconv_from_internal (NULL, "")); WEE_TEST_STR("abc", string_iconv_from_internal (NULL, "abc")); WEE_TEST_STR(noel_iso, string_iconv_from_internal ("ISO-8859-15", noel_utf8)); /* string_iconv_fprintf */ f = fopen ("/dev/null", "w"); LONGS_EQUAL(0, string_iconv_fprintf (f, NULL)); LONGS_EQUAL(1, string_iconv_fprintf (f, "abc")); LONGS_EQUAL(1, string_iconv_fprintf (f, noel_utf8)); LONGS_EQUAL(1, string_iconv_fprintf (f, noel_iso)); fclose (f); }
void weechat_display_copyright () { string_iconv_fprintf (stdout, "\n"); string_iconv_fprintf (stdout, /* TRANSLATORS: "%s %s" after "compiled on" is date and time */ _("WeeChat %s Copyright %s, compiled on %s %s\n" "Developed by Sebastien Helleu <*****@*****.**> " "- %s"), PACKAGE_VERSION, WEECHAT_COPYRIGHT_DATE, __DATE__, __TIME__, WEECHAT_WEBSITE); string_iconv_fprintf (stdout, "\n"); }
void log_printf (const char *message, ...) { char *ptr_buffer; static time_t seconds; struct tm *date_tmp; if (!weechat_log_file) return; weechat_va_format (message); if (vbuffer) { /* keep only valid chars */ ptr_buffer = vbuffer; while (ptr_buffer[0]) { if ((ptr_buffer[0] != '\n') && (ptr_buffer[0] != '\r') && ((unsigned char)(ptr_buffer[0]) < 32)) ptr_buffer[0] = '.'; ptr_buffer++; } if (weechat_log_use_time) { seconds = time (NULL); date_tmp = localtime (&seconds); if (date_tmp) { string_iconv_fprintf (weechat_log_file, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n", date_tmp->tm_year + 1900, date_tmp->tm_mon + 1, date_tmp->tm_mday, date_tmp->tm_hour, date_tmp->tm_min, date_tmp->tm_sec, vbuffer); } else string_iconv_fprintf (weechat_log_file, "%s\n", vbuffer); } else string_iconv_fprintf (weechat_log_file, "%s\n", vbuffer); fflush (weechat_log_file); free (vbuffer); } }
void gui_chat_print_lines_waiting_buffer (FILE *f) { char **lines; int num_lines, i; if (gui_chat_lines_waiting_buffer) { lines = string_split (gui_chat_lines_waiting_buffer, "\n", 0, 0, &num_lines); if (lines) { for (i = 0; i < num_lines; i++) { if (!f && gui_init_ok) gui_chat_printf (NULL, "%s", lines[i]); else string_iconv_fprintf ((f) ? f : stdout, "%s\n", lines[i]); } string_free_split (lines); } /* * gui_chat_lines_waiting_buffer may be NULL after call to * gui_chat_printf (if not enough memory) */ } if (gui_chat_lines_waiting_buffer) { free (gui_chat_lines_waiting_buffer); gui_chat_lines_waiting_buffer = NULL; } }
void weechat_display_copyright () { string_iconv_fprintf (stdout, "\n"); string_iconv_fprintf (stdout, /* TRANSLATORS: "%s %s" after "compiled on" is date and time */ _("WeeChat %s Copyright %s, compiled on %s %s\n" "Developed by Sébastien Helleu <*****@*****.**> " "- %s"), version_get_version_with_git (), WEECHAT_COPYRIGHT_DATE, version_get_compilation_date (), version_get_compilation_time (), WEECHAT_WEBSITE); string_iconv_fprintf (stdout, "\n"); }
void log_printf (const char *message, ...) { static char buffer[4096]; char *ptr_buffer; va_list argptr; static time_t seconds; struct tm *date_tmp; if (!weechat_log_file) return; va_start (argptr, message); vsnprintf (buffer, sizeof (buffer) - 1, message, argptr); va_end (argptr); /* keep only valid chars */ ptr_buffer = buffer; while (ptr_buffer[0]) { if ((ptr_buffer[0] != '\n') && (ptr_buffer[0] != '\r') && ((unsigned char)(ptr_buffer[0]) < 32)) ptr_buffer[0] = '.'; ptr_buffer++; } if (!weechat_log_use_time) string_iconv_fprintf (weechat_log_file, "%s\n", buffer); else { seconds = time (NULL); date_tmp = localtime (&seconds); if (date_tmp) string_iconv_fprintf (weechat_log_file, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n", date_tmp->tm_year + 1900, date_tmp->tm_mon + 1, date_tmp->tm_mday, date_tmp->tm_hour, date_tmp->tm_min, date_tmp->tm_sec, buffer); else string_iconv_fprintf (weechat_log_file, "%s\n", buffer); } fflush (weechat_log_file); }
void gui_chat_printf_y (struct t_gui_buffer *buffer, int y, const char *message, ...) { va_list argptr; struct t_gui_line *ptr_line; if (gui_init_ok) { if (!buffer) buffer = gui_buffer_search_main (); if (buffer->type != GUI_BUFFER_TYPE_FREE) buffer = gui_buffers; if (buffer->type != GUI_BUFFER_TYPE_FREE) return; } if (!gui_chat_buffer) gui_chat_buffer = malloc (GUI_CHAT_BUFFER_PRINTF_SIZE); if (!gui_chat_buffer) return; va_start (argptr, message); vsnprintf (gui_chat_buffer, GUI_CHAT_BUFFER_PRINTF_SIZE, message, argptr); va_end (argptr); utf8_normalize (gui_chat_buffer, '?'); /* no message: delete line */ if (!gui_chat_buffer[0]) { if (gui_init_ok) { for (ptr_line = buffer->own_lines->first_line; ptr_line; ptr_line = ptr_line->next_line) { if (ptr_line->data->y >= y) break; } if (ptr_line && (ptr_line->data->y == y)) { gui_line_free (buffer, ptr_line); gui_buffer_ask_chat_refresh (buffer, 2); } } } else { if (gui_init_ok) { gui_line_add_y (buffer, y, gui_chat_buffer); gui_buffer_ask_chat_refresh (buffer, 1); } else string_iconv_fprintf (stdout, "%s\n", gui_chat_buffer); } }
void dogechat_backtrace_printf (const char *message, ...) { dogechat_va_format (message); if (vbuffer) { string_iconv_fprintf (stderr, "%s\n", vbuffer); log_printf ("%s", vbuffer); free (vbuffer); } }
void log_init () { if (!log_open (NULL, "w")) { string_iconv_fprintf (stderr, _("Error: unable to create/append to log file (weechat.log)\n" "If another WeeChat process is using this file, try to run WeeChat\n" "with another home using \"--dir\" command line option.\n")); exit (1); } log_printf ("%s (%s %s %s)", PACKAGE_STRING, _("compiled on"), __DATE__, __TIME__); }
void weechat_display_usage (char *exec_name) { weechat_display_copyright (); string_iconv_fprintf (stdout, "\n"); string_iconv_fprintf (stdout, _("Usage: %s [option...] [plugin:option...]\n"), exec_name, exec_name); string_iconv_fprintf (stdout, "\n"); string_iconv_fprintf (stdout, _(" -a, --no-connect disable auto-connect to servers at startup\n" " -c, --colors display default colors in terminal\n" " -d, --dir <path> set WeeChat home directory (default: ~/.weechat)\n" " -h, --help display this help\n" " -l, --license display WeeChat license\n" " -p, --no-plugin don't load any plugin at startup\n" " -r, --run-command <cmd> run command(s) after startup\n" " (many commands can be separated by semicolons)\n" " -s, --no-script don't load any script at startup\n" " --upgrade upgrade WeeChat using session files (see /help upgrade in WeeChat)\n" " -v, --version display WeeChat version\n" " plugin:option option for plugin (see man weechat)\n")); string_iconv_fprintf(stdout, "\n"); }
int log_crash_rename () { char *old_name, *new_name; int length; time_t time_now; struct tm *local_time; if (!weechat_log_filename) return 0; old_name = strdup (weechat_log_filename); if (!old_name) return 0; log_close (); length = strlen (weechat_home) + 128; new_name = malloc (length); if (new_name) { time_now = time (NULL); local_time = localtime (&time_now); snprintf (new_name, length, "%s/weechat_crash_%04d%02d%02d_%d.log", weechat_home, local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday, getpid()); if (rename (old_name, new_name) == 0) { string_iconv_fprintf (stderr, "*** Full crash dump was saved to %s file.\n", new_name); log_open (new_name, "a"); free (old_name); free (new_name); return 1; } free (new_name); } free (old_name); log_open (NULL, "a"); return 0; }
void log_init () { if (!log_open (NULL, "w")) { string_iconv_fprintf (stderr, _("Error: unable to create/append to log file (weechat.log)\n" "If another WeeChat process is using this file, try to run WeeChat\n" "with another home using \"--dir\" command line option.\n")); exit (1); } log_printf ("WeeChat %s (%s %s %s)", version_get_version_with_git (), _("compiled on"), version_get_compilation_date (), version_get_compilation_time ()); }
void weechat_parse_args (int argc, char *argv[]) { int i; weechat_argv0 = (argv && argv[0]) ? strdup (argv[0]) : NULL; weechat_upgrading = 0; weechat_home = NULL; weechat_server_cmd_line = 0; weechat_auto_load_plugins = 1; weechat_plugin_no_dlclose = 0; for (i = 1; i < argc; i++) { if ((strcmp (argv[i], "-c") == 0) || (strcmp (argv[i], "--colors") == 0)) { gui_color_display_terminal_colors (); weechat_shutdown (EXIT_SUCCESS, 0); } else if ((strcmp (argv[i], "-d") == 0) || (strcmp (argv[i], "--dir") == 0)) { if (i + 1 < argc) weechat_home = strdup (argv[++i]); else { string_iconv_fprintf (stderr, _("Error: missing argument for \"%s\" " "option\n"), argv[i]); weechat_shutdown (EXIT_FAILURE, 0); } } else if ((strcmp (argv[i], "-h") == 0) || (strcmp (argv[i], "--help") == 0)) { weechat_display_usage (argv[0]); weechat_shutdown (EXIT_SUCCESS, 0); } else if ((strcmp (argv[i], "-l") == 0) || (strcmp (argv[i], "--license") == 0)) { weechat_display_copyright (); string_iconv_fprintf (stdout, "\n"); string_iconv_fprintf (stdout, "%s%s", WEECHAT_LICENSE_TEXT); weechat_shutdown (EXIT_SUCCESS, 0); } else if (strcmp (argv[i], "--no-dlclose") == 0) { /* * Valgrind works better when dlclose() is not done after plugins * are unloaded, it can display stack for plugins,* otherwise * you'll see "???" in stack for functions of unloaded plugins. * This option disables the call to dlclose(), * it must NOT be used for other purposes! */ weechat_plugin_no_dlclose = 1; } else if (strcmp (argv[i], "--no-gnutls") == 0) { /* * Electric-fence is not working fine when gnutls loads * certificates and Valgrind reports many memory errors with gnutls. * This option disables the init/deinit of gnutls, * it must NOT be used for other purposes! */ weechat_no_gnutls = 1; } else if (strcmp (argv[i], "--no-gcrypt") == 0) { /* * Valgrind reports many memory errors with gcrypt. * This option disables the init/deinit of gcrypt, * it must NOT be used for other purposes! */ weechat_no_gcrypt = 1; } else if ((strcmp (argv[i], "-p") == 0) || (strcmp (argv[i], "--no-plugin") == 0)) { weechat_auto_load_plugins = 0; } else if ((strcmp (argv[i], "-r") == 0) || (strcmp (argv[i], "--run-command") == 0)) { if (i + 1 < argc) weechat_startup_commands = strdup (argv[++i]); else { string_iconv_fprintf (stderr, _("Error: missing argument for \"%s\" " "option\n"), argv[i]); weechat_shutdown (EXIT_FAILURE, 0); } } else if (strcmp (argv[i], "--upgrade") == 0) { weechat_upgrading = 1; } else if ((strcmp (argv[i], "-v") == 0) || (strcmp (argv[i], "--version") == 0)) { string_iconv_fprintf (stdout, version_get_version ()); fprintf (stdout, "\n"); weechat_shutdown (EXIT_SUCCESS, 0); } } }
void gui_chat_printf_y (struct t_gui_buffer *buffer, int y, const char *message, ...) { struct t_gui_line *ptr_line; int i, num_lines_to_add; if (gui_init_ok) { if (!buffer) buffer = gui_buffer_search_main (); if (buffer->type != GUI_BUFFER_TYPE_FREE) buffer = gui_buffers; if (buffer->type != GUI_BUFFER_TYPE_FREE) return; } weechat_va_format (message); if (!vbuffer) return; utf8_normalize (vbuffer, '?'); /* no message: delete line */ if (!vbuffer[0]) { if (gui_init_ok) { for (ptr_line = buffer->own_lines->first_line; ptr_line; ptr_line = ptr_line->next_line) { if (ptr_line->data->y >= y) break; } if (ptr_line && (ptr_line->data->y == y)) { if (ptr_line->next_line) gui_line_clear (ptr_line); else gui_line_free (buffer, ptr_line); gui_buffer_ask_chat_refresh (buffer, 2); } } } else { if (gui_init_ok) { num_lines_to_add = 0; if (buffer->own_lines && buffer->own_lines->last_line) num_lines_to_add = y - buffer->own_lines->last_line->data->y - 1; else num_lines_to_add = y; if (num_lines_to_add > 0) { /* * add empty line(s) before asked line, to ensure there is at * least "y" lines in buffer, and then be able to scroll * properly buffer page by page */ for (i = y - num_lines_to_add; i < y; i++) { gui_line_add_y (buffer, i, ""); } } gui_line_add_y (buffer, y, vbuffer); gui_buffer_ask_chat_refresh (buffer, 1); } else string_iconv_fprintf (stdout, "%s\n", vbuffer); } free (vbuffer); }
void debug_sigsegv () { debug_dump (1); unhook_all (); gui_main_end (0); string_iconv_fprintf (stderr, "\n"); string_iconv_fprintf (stderr, "*** Very bad! WeeChat is crashing (SIGSEGV received)\n"); if (!log_crash_rename ()) string_iconv_fprintf (stderr, "*** Full crash dump was saved to %s/weechat.log file.\n", weechat_home); string_iconv_fprintf (stderr, "***\n"); string_iconv_fprintf (stderr, "*** Please help WeeChat developers to fix this bug:\n"); string_iconv_fprintf (stderr, "*** 1. If you have a core file, please run: gdb weechat-curses core\n"); string_iconv_fprintf (stderr, "*** then issue \"bt\" command and send result to developers\n"); string_iconv_fprintf (stderr, "*** To enable core files with bash shell: ulimit -c 10000\n"); string_iconv_fprintf (stderr, "*** 2. Otherwise send backtrace (below) and weechat.log\n"); string_iconv_fprintf (stderr, "*** (be careful, private info may be in this file since\n"); string_iconv_fprintf (stderr, "*** part of chats are displayed, so remove lines if needed)\n\n"); weechat_backtrace (); /* shutdown with error code */ weechat_shutdown (EXIT_FAILURE, 1); }
void gui_chat_printf_date_tags (struct t_gui_buffer *buffer, time_t date, const char *tags, const char *message, ...) { va_list argptr; time_t date_printed; int display_time, length, at_least_one_message_printed; char *pos, *pos_prefix, *pos_tab, *pos_end; char *modifier_data, *new_msg, *ptr_msg; struct t_gui_line *ptr_line; if (!gui_buffer_valid (buffer)) return; if (!message) return; if (gui_init_ok) { if (!buffer) buffer = gui_buffer_search_main (); if (!buffer) return; if (buffer->type != GUI_BUFFER_TYPE_FORMATTED) buffer = gui_buffers; if (buffer->type != GUI_BUFFER_TYPE_FORMATTED) return; } if (!gui_chat_buffer) gui_chat_buffer = malloc (GUI_CHAT_BUFFER_PRINTF_SIZE); if (!gui_chat_buffer) return; va_start (argptr, message); vsnprintf (gui_chat_buffer, GUI_CHAT_BUFFER_PRINTF_SIZE, message, argptr); va_end (argptr); utf8_normalize (gui_chat_buffer, '?'); date_printed = time (NULL); if (date <= 0) date = date_printed; at_least_one_message_printed = 0; pos = gui_chat_buffer; while (pos) { /* display until next end of line */ pos_end = strchr (pos, '\n'); if (pos_end) pos_end[0] = '\0'; /* call modifier for message printed ("weechat_print") */ new_msg = NULL; if (buffer) { length = strlen (plugin_get_name (buffer->plugin)) + 1 + strlen (buffer->name) + 1 + ((tags) ? strlen (tags) : 0) + 1; modifier_data = malloc (length); if (modifier_data) { snprintf (modifier_data, length, "%s;%s;%s", plugin_get_name (buffer->plugin), buffer->name, (tags) ? tags : ""); new_msg = hook_modifier_exec (NULL, "weechat_print", modifier_data, pos); /* no changes in new message */ if (new_msg && (strcmp (message, new_msg) == 0)) { free (new_msg); new_msg = NULL; } free (modifier_data); } } pos_prefix = NULL; display_time = 1; ptr_msg = (new_msg) ? new_msg : pos; /* space followed by tab => prefix ignored */ if ((ptr_msg[0] == ' ') && (ptr_msg[1] == '\t')) { ptr_msg += 2; } else { /* if two first chars are tab, then do not display time */ if ((ptr_msg[0] == '\t') && (ptr_msg[1] == '\t')) { display_time = 0; ptr_msg += 2; } else { /* if tab found, use prefix (before tab) */ pos_tab = strchr (ptr_msg, '\t'); if (pos_tab) { pos_tab[0] = '\0'; pos_prefix = ptr_msg; ptr_msg = pos_tab + 1; } } } if (gui_init_ok) { ptr_line = gui_line_add (buffer, (display_time) ? date : 0, (display_time) ? date_printed : 0, tags, pos_prefix, ptr_msg); if (ptr_line) { if (buffer->print_hooks_enabled) hook_print_exec (buffer, ptr_line); if (ptr_line->data->displayed) at_least_one_message_printed = 1; } } else { if (pos_prefix) string_iconv_fprintf (stdout, "%s ", pos_prefix); string_iconv_fprintf (stdout, "%s\n", ptr_msg); } if (new_msg) free (new_msg); pos = (pos_end && pos_end[1]) ? pos_end + 1 : NULL; } if (gui_init_ok && at_least_one_message_printed) gui_buffer_ask_chat_refresh (buffer, 1); }
void weechat_create_home_dir () { char *ptr_home, *config_weechat_home = WEECHAT_HOME; int dir_length; struct stat statinfo; if (!weechat_home) { if (strlen (config_weechat_home) == 0) { string_iconv_fprintf (stderr, _("Error: WEECHAT_HOME is undefined, check " "build options\n")); weechat_shutdown (EXIT_FAILURE, 0); /* make C static analyzer happy (never executed) */ return; } if (config_weechat_home[0] == '~') { /* replace leading '~' by $HOME */ ptr_home = getenv ("HOME"); if (!ptr_home) { string_iconv_fprintf (stderr, _("Error: unable to get HOME directory\n")); weechat_shutdown (EXIT_FAILURE, 0); /* make C static analyzer happy (never executed) */ return; } dir_length = strlen (ptr_home) + strlen (config_weechat_home + 1) + 1; weechat_home = malloc (dir_length); if (weechat_home) { snprintf (weechat_home, dir_length, "%s%s", ptr_home, config_weechat_home + 1); } } else { weechat_home = strdup (config_weechat_home); } if (!weechat_home) { string_iconv_fprintf (stderr, _("Error: not enough memory for home " "directory\n")); weechat_shutdown (EXIT_FAILURE, 0); /* make C static analyzer happy (never executed) */ return; } } /* if home already exists, it has to be a directory */ if (stat (weechat_home, &statinfo) == 0) { if (!S_ISDIR (statinfo.st_mode)) { string_iconv_fprintf (stderr, _("Error: home (%s) is not a directory\n"), weechat_home); weechat_shutdown (EXIT_FAILURE, 0); } } /* create home directory; error is fatal */ if (!util_mkdir (weechat_home, 0755)) { string_iconv_fprintf (stderr, _("Error: cannot create directory \"%s\"\n"), weechat_home); weechat_shutdown (EXIT_FAILURE, 0); } }