2014-01-02 17:04:10 +00:00
|
|
|
/* about_dialog.cpp
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2014-01-07 21:09:03 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2014-01-02 17:04:10 +00:00
|
|
|
#include "about_dialog.h"
|
2015-06-25 16:17:03 +00:00
|
|
|
#include <ui_about_dialog.h>
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
#include "wireshark_application.h"
|
|
|
|
#include <wsutil/filesystem.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBSMI
|
|
|
|
#include <epan/oids.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
#include <epan/geoip_db.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_LUA
|
|
|
|
#include <epan/wslua/init_wslua.h>
|
|
|
|
#endif
|
|
|
|
|
2016-02-18 12:06:13 +00:00
|
|
|
#include "../../log.h"
|
|
|
|
#include "../../register.h"
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
#include "ui/alert_box.h"
|
2015-07-31 17:34:43 +00:00
|
|
|
#include "ui/last_open_dir.h"
|
2014-01-02 17:04:10 +00:00
|
|
|
#include "ui/help_url.h"
|
2015-07-31 17:34:43 +00:00
|
|
|
#include "ui/text_import_scanner.h"
|
2015-10-04 17:10:29 +00:00
|
|
|
#include <wsutil/utf8_entities.h>
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
#include "file.h"
|
|
|
|
#include "wsutil/file_util.h"
|
|
|
|
#include "wsutil/tempfile.h"
|
|
|
|
#include "wsutil/plugins.h"
|
2014-06-21 17:32:12 +00:00
|
|
|
#include "wsutil/copyright_info.h"
|
2016-04-19 07:03:08 +00:00
|
|
|
#include "ws_version_info.h"
|
2014-01-02 17:04:10 +00:00
|
|
|
|
2016-01-12 12:45:20 +00:00
|
|
|
#ifdef HAVE_EXTCAP
|
|
|
|
#include "extcap.h"
|
|
|
|
#endif
|
|
|
|
|
2014-04-10 22:30:00 +00:00
|
|
|
#include "qt_ui_utils.h"
|
|
|
|
|
|
|
|
#include <QFontMetrics>
|
2015-09-23 21:54:25 +00:00
|
|
|
#include <QKeySequence>
|
2014-01-02 17:04:10 +00:00
|
|
|
#include <QTextStream>
|
2014-04-10 22:30:00 +00:00
|
|
|
#include <QUrl>
|
2014-01-02 17:04:10 +00:00
|
|
|
|
2014-02-13 01:30:41 +00:00
|
|
|
|
2014-01-02 17:04:10 +00:00
|
|
|
// To do:
|
2014-04-10 22:30:00 +00:00
|
|
|
// - Tweak and enhance ui...
|
2014-01-02 17:04:10 +00:00
|
|
|
|
2014-04-10 22:30:00 +00:00
|
|
|
const QString AboutDialog::about_folders_row(const char *name, const QString dir, const char *typ_file)
|
2014-01-02 17:04:10 +00:00
|
|
|
{
|
2014-04-10 22:30:00 +00:00
|
|
|
int one_em = fontMetrics().height();
|
|
|
|
|
|
|
|
QString short_dir = fontMetrics().elidedText(dir, Qt::ElideMiddle, one_em * 18); // Arbitrary
|
|
|
|
|
|
|
|
// It would be really nice to be able to add a tooltip with the
|
|
|
|
// full path here but Qt's rich text doesn't appear to support
|
|
|
|
// "a title=".
|
|
|
|
return QString("<tr><td>%1</td><td><a href=\"%2\">%3</a></td><td>%4</td></tr>\n")
|
|
|
|
.arg(name)
|
|
|
|
.arg(QUrl::fromLocalFile(dir).toString())
|
|
|
|
.arg(short_dir)
|
|
|
|
.arg(typ_file);
|
2014-01-02 17:04:10 +00:00
|
|
|
}
|
|
|
|
|
2014-01-14 01:31:49 +00:00
|
|
|
static void plugins_add_description(const char *name, const char *version,
|
|
|
|
const char *types, const char *filename,
|
2016-01-23 12:18:30 +00:00
|
|
|
void *user_data)
|
2014-01-02 17:04:10 +00:00
|
|
|
{
|
2014-04-10 22:30:00 +00:00
|
|
|
QList<QStringList> *plugin_data = (QList<QStringList> *)user_data;
|
|
|
|
QStringList plugin_row = QStringList() << name << version << types << filename;
|
|
|
|
*plugin_data << plugin_row;
|
2014-01-02 17:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-10 22:30:00 +00:00
|
|
|
const QString AboutDialog::plugins_scan()
|
2014-01-02 17:04:10 +00:00
|
|
|
{
|
2014-04-10 22:30:00 +00:00
|
|
|
QList<QStringList> plugin_data;
|
|
|
|
QString plugin_table;
|
|
|
|
|
2014-01-02 17:04:10 +00:00
|
|
|
#ifdef HAVE_PLUGINS
|
2014-04-10 22:30:00 +00:00
|
|
|
plugins_get_descriptions(plugins_add_description, &plugin_data);
|
2014-01-02 17:04:10 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_LUA
|
2014-04-10 22:30:00 +00:00
|
|
|
wslua_plugins_get_descriptions(plugins_add_description, &plugin_data);
|
2014-01-02 17:04:10 +00:00
|
|
|
#endif
|
2014-04-10 22:30:00 +00:00
|
|
|
|
|
|
|
int one_em = fontMetrics().height();
|
|
|
|
QString short_file;
|
|
|
|
|
|
|
|
foreach (QStringList plugin_row, plugin_data) {
|
2014-04-14 16:06:03 +00:00
|
|
|
short_file = fontMetrics().elidedText(plugin_row[3], Qt::ElideMiddle, one_em * 22); // Arbitrary
|
2014-04-10 22:30:00 +00:00
|
|
|
plugin_table += QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td></tr>\n")
|
|
|
|
.arg(plugin_row[0]) // Name
|
|
|
|
.arg(plugin_row[1]) // Version
|
|
|
|
.arg(plugin_row[2]) // Type
|
|
|
|
.arg(short_file);
|
|
|
|
}
|
2016-01-12 12:45:20 +00:00
|
|
|
|
2016-03-18 17:31:09 +00:00
|
|
|
#ifdef HAVE_EXTCAP
|
2016-01-12 12:45:20 +00:00
|
|
|
GHashTable * tools = extcap_tools_list();
|
2016-01-23 12:18:30 +00:00
|
|
|
if (tools && g_hash_table_size(tools) > 0) {
|
2016-01-12 12:45:20 +00:00
|
|
|
QString short_file;
|
|
|
|
GList * walker = g_list_first(g_hash_table_get_keys(tools));
|
2016-01-23 12:18:30 +00:00
|
|
|
while (walker) {
|
2016-01-12 12:45:20 +00:00
|
|
|
extcap_info * tool = (extcap_info *)g_hash_table_lookup(tools, walker->data);
|
2016-01-23 12:18:30 +00:00
|
|
|
if (tool) {
|
2016-01-12 12:45:20 +00:00
|
|
|
short_file = fontMetrics().elidedText(tool->full_path, Qt::ElideMiddle, one_em*22);
|
|
|
|
plugin_table += QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td></tr>\n")
|
|
|
|
.arg(tool->basename) // Name
|
|
|
|
.arg(tool->version) // Version
|
|
|
|
.arg("extcap") // Type
|
|
|
|
.arg(short_file);
|
|
|
|
}
|
|
|
|
walker = g_list_next(walker);
|
|
|
|
}
|
|
|
|
}
|
2016-03-18 17:31:09 +00:00
|
|
|
#endif
|
2016-01-12 12:45:20 +00:00
|
|
|
|
2014-04-10 22:30:00 +00:00
|
|
|
return plugin_table;
|
2014-01-02 17:04:10 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 21:54:25 +00:00
|
|
|
AboutDialog::AboutDialog(QWidget *parent) :
|
2015-02-11 21:34:08 +00:00
|
|
|
QDialog(NULL),
|
2014-01-02 17:04:10 +00:00
|
|
|
ui(new Ui::AboutDialog)
|
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
2016-01-20 14:13:38 +00:00
|
|
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
2014-01-02 17:04:10 +00:00
|
|
|
QFile f_authors;
|
|
|
|
QFile f_license;
|
|
|
|
const char *constpath;
|
2014-04-10 22:30:00 +00:00
|
|
|
QString message;
|
2014-08-21 13:34:16 +00:00
|
|
|
#if defined(HAVE_LIBSMI) || defined(HAVE_GEOIP) || defined(HAVE_EXTCAP)
|
|
|
|
#if defined(HAVE_LIBSMI) || defined(HAVE_GEOIP)
|
2014-04-14 13:33:25 +00:00
|
|
|
char *path = NULL;
|
2014-08-21 13:34:16 +00:00
|
|
|
#endif
|
2014-01-02 17:04:10 +00:00
|
|
|
gint i;
|
|
|
|
gchar **resultArray;
|
|
|
|
#endif
|
2016-06-18 20:49:23 +00:00
|
|
|
GString *comp_info_str = get_compiled_version_info(get_wireshark_qt_compiled_info,
|
|
|
|
get_gui_compiled_info);
|
|
|
|
GString *runtime_info_str = get_runtime_version_info(get_wireshark_runtime_info);
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
/* Wireshark tab */
|
|
|
|
|
|
|
|
/* Construct the message string */
|
2014-04-10 22:30:00 +00:00
|
|
|
message = QString(
|
2014-06-22 01:02:27 +00:00
|
|
|
"Version %1\n"
|
2014-01-02 17:04:10 +00:00
|
|
|
"\n"
|
2014-04-10 22:30:00 +00:00
|
|
|
"%2"
|
2014-01-02 17:04:10 +00:00
|
|
|
"\n"
|
2014-04-10 22:30:00 +00:00
|
|
|
"%3"
|
2014-01-02 17:04:10 +00:00
|
|
|
"\n"
|
2014-04-10 22:30:00 +00:00
|
|
|
"%4"
|
2014-01-02 17:04:10 +00:00
|
|
|
"\n"
|
|
|
|
"Wireshark is Open Source Software released under the GNU General Public License.\n"
|
|
|
|
"\n"
|
2014-04-10 22:30:00 +00:00
|
|
|
"Check the man page and http://www.wireshark.org for more information.")
|
2014-06-22 01:02:27 +00:00
|
|
|
.arg(get_ws_vcs_version_info()).arg(get_copyright_info()).arg(comp_info_str->str)
|
2014-04-10 22:30:00 +00:00
|
|
|
.arg(runtime_info_str->str);
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
ui->label_wireshark->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
|
|
|
ui->label_wireshark->setText(message);
|
|
|
|
|
2014-01-02 20:21:09 +00:00
|
|
|
/* Check if it is a dev release... (VERSION_MINOR is odd in dev release) */
|
2014-01-02 19:11:06 +00:00
|
|
|
#if VERSION_MINOR & 1
|
2016-01-23 12:18:30 +00:00
|
|
|
ui->label_logo->setPixmap(QPixmap(":/about/wssplash_dev.png"));
|
2014-01-02 19:11:06 +00:00
|
|
|
#endif
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Authors */
|
2014-01-02 20:21:09 +00:00
|
|
|
|
2014-01-03 10:21:56 +00:00
|
|
|
f_authors.setFileName(get_datafile_path("AUTHORS-SHORT"));
|
2014-01-02 17:04:10 +00:00
|
|
|
f_authors.open(QFile::ReadOnly | QFile::Text);
|
|
|
|
QTextStream ReadFile_authors(&f_authors);
|
2014-02-13 01:30:41 +00:00
|
|
|
ReadFile_authors.setCodec("UTF-8");
|
2014-01-02 17:04:10 +00:00
|
|
|
|
2014-02-13 01:30:41 +00:00
|
|
|
ui->pte_Authors->setFont(wsApp->monospaceFont());
|
2014-01-02 17:04:10 +00:00
|
|
|
ui->pte_Authors->insertPlainText(ReadFile_authors.readAll());
|
|
|
|
ui->pte_Authors->moveCursor(QTextCursor::Start);
|
|
|
|
|
|
|
|
/* Folders */
|
|
|
|
|
2014-04-10 22:30:00 +00:00
|
|
|
int one_em = fontMetrics().height();
|
2014-01-02 17:04:10 +00:00
|
|
|
|
2014-04-10 22:30:00 +00:00
|
|
|
// Couldn't get CSS to work.
|
|
|
|
message = QString("<table cellpadding=\"%1\">\n").arg(one_em / 4);
|
|
|
|
message += "<tr><th align=\"left\">Name</th><th align=\"left\">Location</th><th align=\"left\">Typical Files</th></tr>\n";
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
/* "file open" */
|
2014-04-10 22:30:00 +00:00
|
|
|
message += about_folders_row("\"File\" dialogs", get_last_open_dir(), "capture files");
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
/* temp */
|
2014-04-10 22:30:00 +00:00
|
|
|
message += about_folders_row("Temp", g_get_tmp_dir(), "untitled capture files");
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
/* pers conf */
|
2014-04-10 22:30:00 +00:00
|
|
|
message += about_folders_row("Personal configuration",
|
|
|
|
gchar_free_to_qstring(get_persconffile_path("", FALSE)),
|
2015-07-31 17:34:43 +00:00
|
|
|
"<i>dfilters</i>, <i>preferences</i>, <i>ethers</i>, " UTF8_HORIZONTAL_ELLIPSIS);
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
/* global conf */
|
|
|
|
constpath = get_datafile_dir();
|
|
|
|
if (constpath != NULL) {
|
2014-04-10 22:30:00 +00:00
|
|
|
message += about_folders_row("Global configuration", constpath,
|
2015-07-31 17:34:43 +00:00
|
|
|
"<i>dfilters</i>, <i>preferences</i>, <i>manuf</i>, " UTF8_HORIZONTAL_ELLIPSIS);
|
2014-01-02 17:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* system */
|
2014-04-10 22:30:00 +00:00
|
|
|
message += about_folders_row("System", get_systemfile_dir(), "<i>ethers</i>, <i>ipxnets</i>");
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
/* program */
|
2014-04-10 22:30:00 +00:00
|
|
|
message += about_folders_row("Program", get_progfile_dir(), "program files");
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
#if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
|
|
|
|
/* pers plugins */
|
2014-04-10 22:30:00 +00:00
|
|
|
message += about_folders_row("Personal Plugins", gchar_free_to_qstring(get_plugins_pers_dir()),
|
|
|
|
"dissector plugins");
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
/* global plugins */
|
2014-04-10 22:30:00 +00:00
|
|
|
message += about_folders_row("Global Plugins", get_plugin_dir(), "dissector plugins");
|
2014-01-02 17:04:10 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
/* GeoIP */
|
|
|
|
path = geoip_db_get_paths();
|
|
|
|
|
|
|
|
resultArray = g_strsplit(path, G_SEARCHPATH_SEPARATOR_S, 10);
|
|
|
|
|
2014-04-10 22:30:00 +00:00
|
|
|
for(i = 0; resultArray[i]; i++) {
|
|
|
|
message += about_folders_row("GeoIP path", g_strstrip(resultArray[i]),
|
|
|
|
"GeoIP database search path");
|
|
|
|
}
|
2014-01-02 17:04:10 +00:00
|
|
|
g_strfreev(resultArray);
|
|
|
|
g_free(path);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBSMI
|
|
|
|
/* SMI MIBs/PIBs */
|
|
|
|
path = oid_get_default_mib_path();
|
|
|
|
|
|
|
|
resultArray = g_strsplit(path, G_SEARCHPATH_SEPARATOR_S, 10);
|
|
|
|
|
2014-04-10 22:30:00 +00:00
|
|
|
for(i = 0; resultArray[i]; i++) {
|
|
|
|
message += about_folders_row("MIB/PIB path", g_strstrip(resultArray[i]),
|
|
|
|
"SMI MIB/PIB search path");
|
|
|
|
}
|
2014-01-02 17:04:10 +00:00
|
|
|
g_strfreev(resultArray);
|
|
|
|
g_free(path);
|
|
|
|
#endif
|
|
|
|
|
2014-02-25 13:05:11 +00:00
|
|
|
#ifdef HAVE_EXTCAP
|
|
|
|
/* Extcap */
|
|
|
|
constpath = get_extcap_dir();
|
|
|
|
|
|
|
|
resultArray = g_strsplit(constpath, G_SEARCHPATH_SEPARATOR_S, 10);
|
|
|
|
|
|
|
|
for(i = 0; resultArray[i]; i++) {
|
|
|
|
message += about_folders_row("Extcap path", g_strstrip(resultArray[i]),
|
|
|
|
"Extcap Plugins search path");
|
|
|
|
}
|
|
|
|
g_strfreev(resultArray);
|
|
|
|
#endif
|
|
|
|
|
2014-04-10 22:30:00 +00:00
|
|
|
message += "</table>";
|
|
|
|
ui->label_folders->setText(message);
|
|
|
|
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
/* Plugins */
|
2014-04-10 22:30:00 +00:00
|
|
|
|
|
|
|
message = QString("<table cellpadding=\"%1\">\n").arg(one_em / 4);
|
|
|
|
message += "<tr><th align=\"left\">Name</th><th align=\"left\">Version</th><th align=\"left\">Type</th><th align=\"left\">Path</th></tr>\n";
|
|
|
|
|
|
|
|
message += plugins_scan();
|
|
|
|
|
|
|
|
message += "</table>";
|
2015-11-26 19:31:12 +00:00
|
|
|
ui->te_plugins->setHtml(message);
|
2014-01-02 17:04:10 +00:00
|
|
|
|
2015-09-23 21:54:25 +00:00
|
|
|
/* Shortcuts */
|
|
|
|
bool have_shortcuts = false;
|
|
|
|
|
|
|
|
if (parent) {
|
2015-09-25 16:11:23 +00:00
|
|
|
message = "<h3>Main Window Keyboard Shortcuts</h3>\n";
|
|
|
|
message += QString("<table cellpadding=\"%1\">\n").arg(one_em / 4);
|
2015-09-23 21:54:25 +00:00
|
|
|
message += "<tr><th align=\"left\">Shortcut</th><th align=\"left\">Name</th><th align=\"left\">Description</th></tr>\n";
|
|
|
|
|
|
|
|
QMap<QString, QPair<QString, QString> > shortcuts; // name -> (shortcut, description)
|
|
|
|
foreach (const QWidget *child, parent->findChildren<QWidget *>()) {
|
|
|
|
// Recent items look funny here.
|
|
|
|
if (child->objectName().compare("menuOpenRecentCaptureFile") == 0) continue;
|
|
|
|
foreach (const QAction *action, child->actions()) {
|
|
|
|
|
|
|
|
if (!action->shortcut().isEmpty()) {
|
|
|
|
QString name = action->text();
|
|
|
|
name.replace('&', "");
|
|
|
|
shortcuts[name] = QPair<QString, QString>(action->shortcut().toString(QKeySequence::NativeText), action->toolTip());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList names = shortcuts.keys();
|
|
|
|
names.sort();
|
|
|
|
foreach (const QString &name, names) {
|
|
|
|
message += QString("<tr><td>%1</td><td>%2</td><td>%3</td></tr>\n")
|
|
|
|
.arg(shortcuts[name].first)
|
|
|
|
.arg(name)
|
|
|
|
.arg(shortcuts[name].second);
|
|
|
|
have_shortcuts = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
message += "</table>";
|
|
|
|
ui->te_shortcuts->setHtml(message);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ui->te_shortcuts->setVisible(have_shortcuts);
|
|
|
|
|
2014-01-02 17:04:10 +00:00
|
|
|
/* License */
|
|
|
|
|
2014-01-03 10:21:56 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
f_license.setFileName(get_datafile_path("COPYING.txt"));
|
|
|
|
#else
|
|
|
|
f_license.setFileName(get_datafile_path("COPYING"));
|
|
|
|
#endif
|
2014-01-02 17:04:10 +00:00
|
|
|
|
|
|
|
f_license.open(QFile::ReadOnly | QFile::Text);
|
|
|
|
QTextStream ReadFile_license(&f_license);
|
|
|
|
|
2014-02-13 01:30:41 +00:00
|
|
|
ui->pte_License->setFont(wsApp->monospaceFont());
|
2014-01-02 17:04:10 +00:00
|
|
|
ui->pte_License->insertPlainText(ReadFile_license.readAll());
|
|
|
|
ui->pte_License->moveCursor(QTextCursor::Start);
|
|
|
|
}
|
|
|
|
|
|
|
|
AboutDialog::~AboutDialog()
|
|
|
|
{
|
|
|
|
delete ui;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Editor modelines
|
|
|
|
*
|
|
|
|
* Local Variables:
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 8
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
* ex: set shiftwidth=4 tabstop=8 expandtab:
|
|
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
|
|
*/
|