diff options
author | Guy Harris <guy@alum.mit.edu> | 2017-04-23 16:48:17 -0700 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2017-04-24 03:38:21 +0000 |
commit | e52c95c6c8cdac34eccdba9b49d68a6982685f1a (patch) | |
tree | fc479aac517dbee8b5a6a82ea33ec40a482cc248 /epan | |
parent | 751e078d2bc6adf1179de164291eb743abd8732b (diff) | |
download | wireshark-e52c95c6c8cdac34eccdba9b49d68a6982685f1a.tar.gz |
Move UI-only stuff out of libwireshark.
Packet ranges are used only in the UI; move the packet range stuff into
libui.
Don't pass a print_args_t structure to libwireshark packet-printing
routines, just pass the few parameters they need. Move the declaration
of print_args_t into file.h.
Change-Id: Icff5991eea7d7d56f33b4716105895263d275bcf
Reviewed-on: https://code.wireshark.org/review/21308
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Guy Harris <guy@alum.mit.edu>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/Makefile.am | 2 | ||||
-rw-r--r-- | epan/packet_range.c | 379 | ||||
-rw-r--r-- | epan/packet_range.h | 118 | ||||
-rw-r--r-- | epan/print.c | 28 | ||||
-rw-r--r-- | epan/print.h | 42 |
6 files changed, 31 insertions, 539 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 4ebc03f60e..1d3c7ac150 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -132,7 +132,6 @@ set(LIBWIRESHARK_FILES oids.c osi-utils.c oui.c - packet_range.c packet.c print.c print_stream.c diff --git a/epan/Makefile.am b/epan/Makefile.am index 1b9878fd8b..46d8bd0829 100644 --- a/epan/Makefile.am +++ b/epan/Makefile.am @@ -95,7 +95,6 @@ LIBWIRESHARK_SRC = \ oids.c \ osi-utils.c \ oui.c \ - packet_range.c \ packet.c \ prefs.c \ print.c \ @@ -247,7 +246,6 @@ LIBWIRESHARK_INCLUDES = \ oids.h \ osi-utils.h \ oui.h \ - packet_range.h \ packet.h \ packet_info.h \ params.h \ diff --git a/epan/packet_range.c b/epan/packet_range.c deleted file mode 100644 index a6797e3110..0000000000 --- a/epan/packet_range.c +++ /dev/null @@ -1,379 +0,0 @@ -/* packet_range.c - * Packet range routines (save, print, ...) - * - * Dick Gooris <gooris@lucent.com> - * Ulf Lamping <ulf.lamping@web.de> - * - * Wireshark - Network traffic analyzer - * By Gerald Combs <gerald@wireshark.org> - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include <string.h> - -#include <glib.h> - -#include <epan/frame_data.h> - -#include "packet_range.h" - -/* (re-)calculate the packet counts (except the user specified range) */ -static void packet_range_calc(packet_range_t *range) { - guint32 framenum; - guint32 mark_low; - guint32 mark_high; - guint32 displayed_mark_low; - guint32 displayed_mark_high; - frame_data *packet; - - - range->selected_packet = 0; - - mark_low = 0; - mark_high = 0; - range->mark_range_cnt = 0; - range->ignored_cnt = 0; - range->ignored_marked_cnt = 0; - range->ignored_mark_range_cnt = 0; - range->ignored_user_range_cnt = 0; - - displayed_mark_low = 0; - displayed_mark_high = 0; - - range->displayed_cnt = 0; - range->displayed_marked_cnt = 0; - range->displayed_mark_range_cnt = 0; - range->displayed_plus_dependents_cnt = 0; - range->displayed_ignored_cnt = 0; - range->displayed_ignored_marked_cnt = 0; - range->displayed_ignored_mark_range_cnt = 0; - range->displayed_ignored_user_range_cnt = 0; - - g_assert(range->cf != NULL); - - /* XXX - this doesn't work unless you have a full set of frame_data - * structures for all packets in the capture, which is not, - * for example, the case when TShark is doing a one-pass - * read of a file or a live capture. - * - * It's also horribly slow on large captures, causing it to - * take a long time for the Save As dialog to pop up, for - * example. We should really keep these statistics in - * the capture_file structure, updating them whenever we - * filter the display, etc.. - */ - if (range->cf->frames != NULL) { - /* The next for-loop is used to obtain the amount of packets - * to be processed and is used to present the information in - * the Save/Print As widget. - * We have different types of ranges: All the packets, the number - * of packets of a marked range, a single packet, and a user specified - * packet range. The last one is not calculated here since this - * data must be entered in the widget by the user. - */ - - for(framenum = 1; framenum <= range->cf->count; framenum++) { - packet = frame_data_sequence_find(range->cf->frames, framenum); - - if (range->cf->current_frame == packet) { - range->selected_packet = framenum; - } - if (packet->flags.passed_dfilter) { - range->displayed_cnt++; - } - if (packet->flags.passed_dfilter || - packet->flags.dependent_of_displayed) { - range->displayed_plus_dependents_cnt++; - } - if (packet->flags.marked) { - if (packet->flags.ignored) { - range->ignored_marked_cnt++; - } - if (packet->flags.passed_dfilter) { - range->displayed_marked_cnt++; - if (packet->flags.ignored) { - range->displayed_ignored_marked_cnt++; - } - if (displayed_mark_low == 0) { - displayed_mark_low = framenum; - } - if (framenum > displayed_mark_high) { - displayed_mark_high = framenum; - } - } - - if (mark_low == 0) { - mark_low = framenum; - } - if (framenum > mark_high) { - mark_high = framenum; - } - } - if (packet->flags.ignored) { - range->ignored_cnt++; - if (packet->flags.passed_dfilter) { - range->displayed_ignored_cnt++; - } - } - } - - for(framenum = 1; framenum <= range->cf->count; framenum++) { - packet = frame_data_sequence_find(range->cf->frames, framenum); - - if (framenum >= mark_low && - framenum <= mark_high) - { - range->mark_range_cnt++; - if (packet->flags.ignored) { - range->ignored_mark_range_cnt++; - } - } - - if (framenum >= displayed_mark_low && - framenum <= displayed_mark_high) - { - if (packet->flags.passed_dfilter) { - range->displayed_mark_range_cnt++; - if (packet->flags.ignored) { - range->displayed_ignored_mark_range_cnt++; - } - } - } - } - -#if 0 - /* in case we marked just one packet, we add 1. */ - if (range->cf->marked_count != 0) { - range->mark_range = mark_high - mark_low + 1; - } - - /* in case we marked just one packet, we add 1. */ - if (range->displayed_marked_cnt != 0) { - range->displayed_mark_range = displayed_mark_high - displayed_mark_low + 1; - } -#endif - } -} - - -/* (re-)calculate the user specified packet range counts */ -static void packet_range_calc_user(packet_range_t *range) { - guint32 framenum; - frame_data *packet; - - range->user_range_cnt = 0; - range->ignored_user_range_cnt = 0; - range->displayed_user_range_cnt = 0; - range->displayed_ignored_user_range_cnt = 0; - - g_assert(range->cf != NULL); - - /* XXX - this doesn't work unless you have a full set of frame_data - * structures for all packets in the capture, which is not, - * for example, the case when TShark is doing a one-pass - * read of a file or a live capture. - * - * It's also horribly slow on large captures, causing it to - * take a long time for the Save As dialog to pop up, for - * example. This obviously can't be kept in the capture_file - * structure and recalculated whenever we filter the display - * or mark frames as ignored, as the results of this depend - * on what the user specifies. In some cases, limiting the - * frame_data structures at which we look to the ones specified - * by the user might help, but if most of the frames are in - * the range, that won't help. In that case, if we could - * examine the *complement* of the range, and *subtract* them - * from the statistics for the capture as a whole, that might - * help, but if the user specified about *half* the packets in - * the range, that won't help, either. - */ - if (range->cf->frames != NULL) { - for(framenum = 1; framenum <= range->cf->count; framenum++) { - packet = frame_data_sequence_find(range->cf->frames, framenum); - - if (value_is_in_range(range->user_range, framenum)) { - range->user_range_cnt++; - if (packet->flags.ignored) { - range->ignored_user_range_cnt++; - } - if (packet->flags.passed_dfilter) { - range->displayed_user_range_cnt++; - if (packet->flags.ignored) { - range->displayed_ignored_user_range_cnt++; - } - } - } - } - } -} - - -/* init the range struct */ -void packet_range_init(packet_range_t *range, capture_file *cf) { - - memset(range, 0, sizeof(packet_range_t)); - range->process = range_process_all; - range->user_range = NULL; - range->cf = cf; - - /* calculate all packet range counters */ - packet_range_calc(range); - packet_range_calc_user(range); -} - -/* check whether the packet range is OK */ -convert_ret_t packet_range_check(packet_range_t *range) { - if (range->process == range_process_user_range && range->user_range == NULL) { - /* Not valid - return the error. */ - return range->user_range_status; - } - return CVT_NO_ERROR; -} - -/* init the processing run */ -void packet_range_process_init(packet_range_t *range) { - /* Check that, if an explicit range was selected, it's valid. */ - /* "enumeration" values */ - range->marked_range_active = FALSE; - range->selected_done = FALSE; - - if (range->process_filtered == FALSE) { - range->marked_range_left = range->mark_range_cnt; - } else { - range->marked_range_left = range->displayed_mark_range_cnt; - } -} - -/* do we have to process all packets? */ -gboolean packet_range_process_all(packet_range_t *range) { - return range->process == range_process_all && !range->process_filtered && !range->remove_ignored; -} - -/* do we have to process this packet? */ -range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata) { - - if (range->remove_ignored && fdata->flags.ignored) { - return range_process_next; - } - - g_assert(range->cf != NULL); - - switch(range->process) { - case(range_process_all): - break; - case(range_process_selected): - if (range->selected_done) { - return range_processing_finished; - } - if (fdata->num != range->cf->current_frame->num) { - return range_process_next; - } - range->selected_done = TRUE; - break; - case(range_process_marked): - if (fdata->flags.marked == FALSE) { - return range_process_next; - } - break; - case(range_process_marked_range): - if (range->marked_range_left == 0) { - return range_processing_finished; - } - if (fdata->flags.marked == TRUE) { - range->marked_range_active = TRUE; - } - if (range->marked_range_active == FALSE ) { - return range_process_next; - } - if (!range->process_filtered || - (range->process_filtered && fdata->flags.passed_dfilter == TRUE)) - { - range->marked_range_left--; - } - break; - case(range_process_user_range): - if (value_is_in_range(range->user_range, fdata->num) == FALSE) { - return range_process_next; - } - break; - default: - g_assert_not_reached(); - } - - /* This packet has to pass the display filter but didn't? - * Try next, but only if we're not including dependent packets and this - * packet happens to be a dependency on something that is displayed. - */ - if ((range->process_filtered && fdata->flags.passed_dfilter == FALSE) && - !(range->include_dependents && fdata->flags.dependent_of_displayed)) { - return range_process_next; - } - - /* We fell through the conditions above, so we accept this packet */ - return range_process_this; -} - - -/******************** Range Entry Parser *********************************/ - -/* Converts a range string to a user range. - * The parameter 'es' points to the string to be converted, and is defined in - * the Save/Print-As widget. - */ - -void packet_range_convert_str(packet_range_t *range, const gchar *es) -{ - range_t *new_range; - convert_ret_t ret; - - if (range->user_range != NULL) - wmem_free(NULL, range->user_range); - - g_assert(range->cf != NULL); - - ret = range_convert_str(NULL, &new_range, es, range->cf->count); - if (ret != CVT_NO_ERROR) { - /* range isn't valid */ - range->user_range = NULL; - range->user_range_status = ret; - range->user_range_cnt = 0; - range->ignored_user_range_cnt = 0; - range->displayed_user_range_cnt = 0; - range->displayed_ignored_user_range_cnt = 0; - return; - } - range->user_range = new_range; - - /* calculate new user specified packet range counts */ - packet_range_calc_user(range); -} /* packet_range_convert_str */ - - -/* - * Editor modelines - http://www.wireshark.org/tools/modelines.html - * - * Local variables: - * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - * - * vi: set shiftwidth=4 tabstop=8 expandtab: - * :indentSize=4:tabSize=8:noTabs=true: - */ diff --git a/epan/packet_range.h b/epan/packet_range.h deleted file mode 100644 index 500cdc951f..0000000000 --- a/epan/packet_range.h +++ /dev/null @@ -1,118 +0,0 @@ -/* packet_range.h - * Packet range routines (save, print, ...) - * - * Dick Gooris <gooris@lucent.com> - * Ulf Lamping <ulf.lamping@web.de> - * - * Wireshark - Network traffic analyzer - * By Gerald Combs <gerald@wireshark.org> - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef __PACKET_RANGE_H__ -#define __PACKET_RANGE_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include <glib.h> - -#include <epan/range.h> - -#include "cfile.h" - - -extern guint32 curr_selected_frame; - -typedef enum { - range_process_all, - range_process_selected, - range_process_marked, - range_process_marked_range, - range_process_user_range -} packet_range_e; - -typedef struct packet_range_tag { - /* values coming from the UI */ - packet_range_e process; /* which range to process */ - gboolean process_filtered; /* captured or filtered packets */ - gboolean remove_ignored; /* remove ignored packets */ - gboolean include_dependents; /* True if packets which are dependents of others should be processed */ - - /* user specified range(s) and, if null, error status */ - range_t *user_range; - convert_ret_t user_range_status; - - /* calculated values */ - guint32 selected_packet; /* the currently selected packet */ - - /* current packet counts (captured) */ - capture_file *cf; /* Associated capture file. */ - guint32 mark_range_cnt; /* packets in marked range */ - guint32 user_range_cnt; /* packets in user specified range */ - guint32 ignored_cnt; /* packets ignored */ - guint32 ignored_marked_cnt; /* packets ignored and marked */ - guint32 ignored_mark_range_cnt; /* packets ignored in marked range */ - guint32 ignored_user_range_cnt; /* packets ignored in user specified range */ - - /* current packet counts (displayed) */ - guint32 displayed_cnt; - guint32 displayed_plus_dependents_cnt; - guint32 displayed_marked_cnt; - guint32 displayed_mark_range_cnt; - guint32 displayed_user_range_cnt; - guint32 displayed_ignored_cnt; - guint32 displayed_ignored_marked_cnt; - guint32 displayed_ignored_mark_range_cnt; - guint32 displayed_ignored_user_range_cnt; - - /* "enumeration" values */ - gboolean marked_range_active; /* marked range is currently processed */ - guint32 marked_range_left; /* marked range packets left to do */ - gboolean selected_done; /* selected packet already processed */ -} packet_range_t; - -typedef enum { - range_process_this, /* process this packet */ - range_process_next, /* skip this packet, process next */ - range_processing_finished /* stop processing, required packets done */ -} range_process_e; - -/* init the range structure */ -WS_DLL_PUBLIC void packet_range_init(packet_range_t *range, capture_file *cf); - -/* check whether the packet range is OK */ -WS_DLL_PUBLIC convert_ret_t packet_range_check(packet_range_t *range); - -/* init the processing run */ -WS_DLL_PUBLIC void packet_range_process_init(packet_range_t *range); - -/* do we have to process all packets? */ -WS_DLL_PUBLIC gboolean packet_range_process_all(packet_range_t *range); - -/* do we have to process this packet? */ -WS_DLL_PUBLIC range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata); - -/* convert user given string to the internal user specified range representation */ -WS_DLL_PUBLIC void packet_range_convert_str(packet_range_t *range, const gchar *es); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __PACKET_RANGE_H__ */ diff --git a/epan/print.c b/epan/print.c index 5ce5e2b18a..90710f5afb 100644 --- a/epan/print.c +++ b/epan/print.c @@ -32,7 +32,7 @@ #include <epan/epan_dissect.h> #include <epan/to_str.h> #include <epan/expert.h> -#include <epan/packet_range.h> +#include <epan/column-info.h> #include <epan/prefs.h> #include <epan/print.h> #include <epan/charsets.h> @@ -135,8 +135,9 @@ void print_cache_field_handles(void) } gboolean -proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, - GHashTable *output_only_tables, print_stream_t *stream) +proto_tree_print(print_dissections_e print_dissections, gboolean print_hex_data, + epan_dissect_t *edt, GHashTable *output_only_tables, + print_stream_t *stream) { print_data data; @@ -146,10 +147,10 @@ proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, data.success = TRUE; data.src_list = edt->pi.data_src; data.encoding = (packet_char_enc)edt->pi.fd->flags.encoding; - data.print_dissections = print_args->print_dissections; + data.print_dissections = print_dissections; /* If we're printing the entire packet in hex, don't print uninterpreted data fields in hex as well. */ - data.print_hex_for_data = !print_args->print_hex; + data.print_hex_for_data = !print_hex_data; data.output_only_tables = output_only_tables; proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data); @@ -337,7 +338,11 @@ write_pdml_proto_tree(output_fields_t* fields, gchar **protocolfilter, pf_flags } void -write_json_proto_tree(output_fields_t* fields, print_args_t *print_args, gchar **protocolfilter, pf_flags protocolfilter_flags, epan_dissect_t *edt, FILE *fh) +write_json_proto_tree(output_fields_t* fields, + print_dissections_e print_dissections, + gboolean print_hex_data, gchar **protocolfilter, + pf_flags protocolfilter_flags, epan_dissect_t *edt, + FILE *fh) { write_json_data data; char ts[30]; @@ -373,9 +378,9 @@ write_json_proto_tree(output_fields_t* fields, print_args_t *print_args, gchar * data.src_list = edt->pi.data_src; data.filter = protocolfilter; data.filter_flags = protocolfilter_flags; - data.print_hex = print_args->print_hex; + data.print_hex = print_hex_data; data.print_text = TRUE; - if (print_args->print_dissections == print_dissections_none) { + if (print_dissections == print_dissections_none) { data.print_text = FALSE; } @@ -393,7 +398,10 @@ write_json_proto_tree(output_fields_t* fields, print_args_t *print_args, gchar * } void -write_ek_proto_tree(output_fields_t* fields, print_args_t *print_args, gchar **protocolfilter, pf_flags protocolfilter_flags, epan_dissect_t *edt, FILE *fh) +write_ek_proto_tree(output_fields_t* fields, + gboolean print_hex_data, gchar **protocolfilter, + pf_flags protocolfilter_flags, epan_dissect_t *edt, + FILE *fh) { write_json_data data; char ts[30]; @@ -421,7 +429,7 @@ write_ek_proto_tree(output_fields_t* fields, print_args_t *print_args, gchar **p data.src_list = edt->pi.data_src; data.filter = protocolfilter; data.filter_flags = protocolfilter_flags; - data.print_hex = print_args->print_hex; + data.print_hex = print_hex_data; proto_tree_children_foreach(edt->tree, proto_tree_write_node_ek, &data); diff --git a/epan/print.h b/epan/print.h index ef7330bd2b..6dedc30878 100644 --- a/epan/print.h +++ b/epan/print.h @@ -32,8 +32,6 @@ #include <epan/print_stream.h> -#include <epan/packet_range.h> - #include "ws_symbol_export.h" #ifdef __cplusplus @@ -46,14 +44,6 @@ typedef enum { PR_FMT_PS /* postscript */ } print_format_e; -/* print_range, enum which frames should be printed */ -typedef enum { - print_range_selected_only, /* selected frame(s) only (currently only one) */ - print_range_marked_only, /* marked frames only */ - print_range_all_displayed, /* all frames currently displayed */ - print_range_all_captured /* all frames in capture */ -} print_range_e; - /* print_dissections, enum how the dissections should be printed */ typedef enum { print_dissections_none, /* no dissections at all */ @@ -62,22 +52,6 @@ typedef enum { print_dissections_expanded /* all dissection details */ } print_dissections_e; -typedef struct { - print_stream_t *stream; /* the stream to which we're printing */ - print_format_e format; /* plain text or PostScript */ - gboolean to_file; /* TRUE if we're printing to a file */ - char *file; /* file output pathname */ - char *cmd; /* print command string (not win32) */ - packet_range_t range; - - gboolean print_summary; /* TRUE if we should print summary line. */ - gboolean print_col_headings; /* TRUE if we should print column headings */ - print_dissections_e print_dissections; - gboolean print_hex; /* TRUE if we should print hex data; - * FALSE if we should print only if not dissected. */ - gboolean print_formfeed; /* TRUE if a formfeed should be printed before - * each new packet */ -} print_args_t; typedef enum { FORMAT_CSV, /* CSV */ @@ -110,7 +84,8 @@ WS_DLL_PUBLIC gboolean output_fields_has_cols(output_fields_t* info); * Higher-level packet-printing code. */ -WS_DLL_PUBLIC gboolean proto_tree_print(print_args_t *print_args, +WS_DLL_PUBLIC gboolean proto_tree_print(print_dissections_e print_dissections, + gboolean print_hex_data, epan_dissect_t *edt, GHashTable *output_only_tables, print_stream_t *stream); @@ -121,10 +96,19 @@ WS_DLL_PUBLIC void write_pdml_proto_tree(output_fields_t* fields, gchar **protoc WS_DLL_PUBLIC void write_pdml_finale(FILE *fh); WS_DLL_PUBLIC void write_json_preamble(FILE *fh); -WS_DLL_PUBLIC void write_json_proto_tree(output_fields_t* fields, print_args_t *print_args, gchar **protocolfilter, pf_flags protocolfilter_flags, epan_dissect_t *edt, FILE *fh); +WS_DLL_PUBLIC void write_json_proto_tree(output_fields_t* fields, + print_dissections_e print_dissections, + gboolean print_hex_data, + gchar **protocolfilter, + pf_flags protocolfilter_flags, + epan_dissect_t *edt, FILE *fh); WS_DLL_PUBLIC void write_json_finale(FILE *fh); -WS_DLL_PUBLIC void write_ek_proto_tree(output_fields_t* fields, print_args_t *print_args, gchar **protocolfilter, pf_flags protocolfilter_flags, epan_dissect_t *edt, FILE *fh); +WS_DLL_PUBLIC void write_ek_proto_tree(output_fields_t* fields, + gboolean print_hex_data, + gchar **protocolfilter, + pf_flags protocolfilter_flags, + epan_dissect_t *edt, FILE *fh); WS_DLL_PUBLIC void write_psml_preamble(column_info *cinfo, FILE *fh); WS_DLL_PUBLIC void write_psml_columns(epan_dissect_t *edt, FILE *fh); |