From 56a1ccedd4a58b6c87d1bbd94e22094ad5ac1a98 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 31 Aug 2016 15:16:06 -0400 Subject: [PATCH] Move remaining protorectoral files to ctf fs plugin MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- converter/babeltrace.c | 62 ++++++++++++++----- lib/plugin-system/source.c | 2 +- plugins/ctf/fs/Makefile.am | 16 ++++- .../ctf/fs/data-stream.c | 25 ++++---- .../ctf/fs/data-stream.h | 0 .../ctf-fs-file.c => plugins/ctf/fs/file.c | 8 +-- .../ctf-fs-file.h => plugins/ctf/fs/file.h | 14 +---- plugins/ctf/fs/fs.c | 54 +++++++++++++--- plugins/ctf/fs/{fs-internal.h => fs.h} | 39 +++++++++++- .../ctf/fs/metadata.c | 19 +++--- .../ctf/fs/metadata.h | 13 +--- {ctf-reader-proto => plugins/ctf/fs}/print.h | 2 - plugins/ctf/plugin.c | 8 +-- plugins/text/text.c | 2 +- 14 files changed, 182 insertions(+), 82 deletions(-) rename ctf-reader-proto/ctf-fs-data-stream.c => plugins/ctf/fs/data-stream.c (93%) rename ctf-reader-proto/ctf-fs-data-stream.h => plugins/ctf/fs/data-stream.h (100%) rename ctf-reader-proto/ctf-fs-file.c => plugins/ctf/fs/file.c (92%) rename ctf-reader-proto/ctf-fs-file.h => plugins/ctf/fs/file.h (85%) rename plugins/ctf/fs/{fs-internal.h => fs.h} (72%) rename ctf-reader-proto/ctf-fs-metadata.c => plugins/ctf/fs/metadata.c (94%) rename ctf-reader-proto/ctf-fs-metadata.h => plugins/ctf/fs/metadata.h (89%) rename {ctf-reader-proto => plugins/ctf/fs}/print.h (98%) diff --git a/converter/babeltrace.c b/converter/babeltrace.c index 035c4a25..cd7bd7c4 100644 --- a/converter/babeltrace.c +++ b/converter/babeltrace.c @@ -40,10 +40,12 @@ static char *opt_plugin_path; +static char *opt_input_path; enum { OPT_NONE = 0, OPT_PLUGIN_PATH, + OPT_INPUT_PATH, OPT_VERBOSE, OPT_DEBUG, OPT_HELP, @@ -60,6 +62,7 @@ enum { static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ { "plugin-path", 0, POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL }, + { "input-path", 0, POPT_ARG_STRING, NULL, OPT_INPUT_PATH, NULL, NULL }, { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL }, { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL }, { NULL, 0, 0, NULL, 0, NULL, NULL }, @@ -95,7 +98,7 @@ static int parse_options(int argc, char **argv) if (!opt_plugin_path) { ret = -EINVAL; goto end; - } ; + } break; case OPT_VERBOSE: babeltrace_verbose = 1; @@ -103,6 +106,13 @@ static int parse_options(int argc, char **argv) case OPT_DEBUG: babeltrace_debug = 1; break; + case OPT_INPUT_PATH: + opt_input_path = (char *) poptGetOptArg(pc); + if (!opt_input_path) { + ret = -EINVAL; + goto end; + } + break; default: ret = -EINVAL; goto end; @@ -133,7 +143,7 @@ const char *component_type_str(enum bt_component_type type) } static -void print_detected_component_classes(struct bt_component_factory *factory) +void print_found_component_classes(struct bt_component_factory *factory) { int count, i; @@ -183,18 +193,12 @@ void print_detected_component_classes(struct bt_component_factory *factory) } } -static -void test_sink_notifications(struct bt_component *sink) -{ - return; -} - int main(int argc, char **argv) { int ret; + enum bt_value_status value_status; struct bt_component_factory *component_factory = NULL; - struct bt_component_class *source_class = NULL; - struct bt_component_class *sink_class = NULL; + struct bt_component_class *source_class = NULL, *sink_class = NULL; struct bt_component *source = NULL, *sink = NULL; struct bt_value *source_params = NULL, *sink_params = NULL; @@ -206,6 +210,20 @@ int main(int argc, char **argv) exit(EXIT_SUCCESS); } + source_params = bt_value_map_create(); + if (!source_params) { + fprintf(stderr, "Failed to create source parameters map, aborting...\n"); + ret = -1; + goto end; + } + + value_status = bt_value_map_insert_string(source_params, "path", + opt_input_path); + if (value_status != BT_VALUE_STATUS_OK) { + ret = -1; + goto end; + } + printf_verbose("Verbose mode active.\n"); printf_debug("Debug mode active.\n"); @@ -229,25 +247,39 @@ int main(int argc, char **argv) goto end; } - print_detected_component_classes(component_factory); + print_found_component_classes(component_factory); + + source_class = bt_component_factory_get_component_class( + component_factory, "ctf", BT_COMPONENT_TYPE_SOURCE, + "fs"); + if (!source_class) { + fprintf(stderr, "Could not find ctf-fs output component class. Aborting...\n"); + ret = -1; + goto end; + } sink_class = bt_component_factory_get_component_class(component_factory, - NULL, BT_COMPONENT_TYPE_SINK, "text"); + "text", BT_COMPONENT_TYPE_SINK, "text"); if (!sink_class) { fprintf(stderr, "Could not find text output component class. Aborting...\n"); ret = -1; goto end; } + source = bt_component_create(source_class, "ctf-fs", source_params); + if (!source) { + fprintf(stderr, "Failed to instantiate source component. Aborting...\n"); + ret = -1; + goto end; + } + sink = bt_component_create(sink_class, "bt_text_output", sink_params); if (!sink) { - fprintf(stderr, "Failed to instanciate text output. Aborting...\n"); + fprintf(stderr, "Failed to instantiate output component. Aborting...\n"); ret = -1; goto end; } - test_sink_notifications(sink); - /* teardown and exit */ end: BT_PUT(component_factory); diff --git a/lib/plugin-system/source.c b/lib/plugin-system/source.c index e7c4c9af..333139f5 100644 --- a/lib/plugin-system/source.c +++ b/lib/plugin-system/source.c @@ -56,7 +56,7 @@ enum bt_component_status bt_component_source_validate( } source = container_of(component, struct bt_component_source, parent); - if (source->init_iterator) { + if (!source->init_iterator) { ret = BT_COMPONENT_STATUS_INVALID; goto end; } diff --git a/plugins/ctf/fs/Makefile.am b/plugins/ctf/fs/Makefile.am index 953ca337..c08c1aa9 100644 --- a/plugins/ctf/fs/Makefile.am +++ b/plugins/ctf/fs/Makefile.am @@ -1,7 +1,17 @@ AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -noinst_HEADERS = fs-internal.h +noinst_HEADERS = \ + fs.h \ + data-stream.h \ + file.h \ + metadata.h \ + print.h noinst_LTLIBRARIES = libbabeltrace-plugin-ctf-fs.la -# Plug-in system library -libbabeltrace_plugin_ctf_fs_la_SOURCES = fs.c +libbabeltrace_plugin_ctf_fs_la_LIBADD = \ + $(builddir)/../common/libbabeltrace-plugin-ctf-common.la +libbabeltrace_plugin_ctf_fs_la_SOURCES = \ + fs.c \ + data-stream.c \ + metadata.c \ + file.c diff --git a/ctf-reader-proto/ctf-fs-data-stream.c b/plugins/ctf/fs/data-stream.c similarity index 93% rename from ctf-reader-proto/ctf-fs-data-stream.c rename to plugins/ctf/fs/data-stream.c index c696927a..6fba603a 100644 --- a/ctf-reader-proto/ctf-fs-data-stream.c +++ b/plugins/ctf/fs/data-stream.c @@ -36,10 +36,9 @@ #define PRINT_PREFIX "ctf-fs-data-stream" #include "print.h" -#include "ctf-fs.h" -#include "ctf-fs-file.h" -#include "ctf-fs-metadata.h" -#include "ctf-notif-iter/ctf-notif-iter.h" +#include "file.h" +#include "metadata.h" +#include "../common/notif-iter/notif-iter.h" static void ctf_fs_stream_destroy(struct ctf_fs_stream *stream) { @@ -66,7 +65,7 @@ static size_t remaining_mmap_bytes(struct ctf_fs_stream *stream) static int stream_munmap(struct ctf_fs_stream *stream) { - struct ctf_fs *ctf_fs = stream->file->ctf_fs; + struct ctf_fs_component *ctf_fs = stream->file->ctf_fs; if (munmap(stream->mmap_addr, stream->mmap_len)) { PERR("Cannot memory-unmap address %p (size %zu) of file \"%s\" (%p): %s\n", @@ -81,7 +80,7 @@ static int stream_munmap(struct ctf_fs_stream *stream) static int mmap_next(struct ctf_fs_stream *stream) { - struct ctf_fs *ctf_fs = stream->file->ctf_fs; + struct ctf_fs_component *ctf_fs = stream->file->ctf_fs; int ret = 0; /* Unmap old region */ @@ -123,7 +122,7 @@ static enum bt_ctf_notif_iter_medium_status medop_request_bytes( enum bt_ctf_notif_iter_medium_status status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK; struct ctf_fs_stream *stream = data; - struct ctf_fs *ctf_fs = stream->file->ctf_fs; + struct ctf_fs_component *ctf_fs = stream->file->ctf_fs; if (request_sz == 0) { goto end; @@ -172,7 +171,7 @@ static struct bt_ctf_stream *medop_get_stream( struct bt_ctf_stream_class *stream_class, void *data) { struct ctf_fs_stream *fs_stream = data; - struct ctf_fs *ctf_fs = fs_stream->file->ctf_fs; + struct ctf_fs_component *ctf_fs = fs_stream->file->ctf_fs; if (!fs_stream->stream) { int64_t id = bt_ctf_stream_class_get_id(stream_class); @@ -194,8 +193,8 @@ static struct bt_ctf_notif_iter_medium_ops medops = { .get_stream = medop_get_stream, }; -static struct ctf_fs_stream *ctf_fs_stream_create(struct ctf_fs *ctf_fs, - struct ctf_fs_file *file) +static struct ctf_fs_stream *ctf_fs_stream_create( + struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file) { struct ctf_fs_stream *stream = g_new0(struct ctf_fs_stream, 1); @@ -223,7 +222,7 @@ end: return stream; } -int ctf_fs_data_stream_open_streams(struct ctf_fs *ctf_fs) +int ctf_fs_data_stream_open_streams(struct ctf_fs_component *ctf_fs) { int ret = 0; GError *error = NULL; @@ -307,7 +306,7 @@ end: return ret; } -int ctf_fs_data_stream_init(struct ctf_fs *ctf_fs, +int ctf_fs_data_stream_init(struct ctf_fs_component *ctf_fs, struct ctf_fs_data_stream *data_stream) { int ret = 0; @@ -334,7 +333,7 @@ void ctf_fs_data_stream_deinit(struct ctf_fs_data_stream *data_stream) } int ctf_fs_data_stream_get_next_notification( - struct ctf_fs *ctf_fs, + struct ctf_fs_component *ctf_fs, struct bt_ctf_notif_iter_notif **notification) { int ret = 0; diff --git a/ctf-reader-proto/ctf-fs-data-stream.h b/plugins/ctf/fs/data-stream.h similarity index 100% rename from ctf-reader-proto/ctf-fs-data-stream.h rename to plugins/ctf/fs/data-stream.h diff --git a/ctf-reader-proto/ctf-fs-file.c b/plugins/ctf/fs/file.c similarity index 92% rename from ctf-reader-proto/ctf-fs-file.c rename to plugins/ctf/fs/file.c index 45819ef7..1d31bcfc 100644 --- a/ctf-reader-proto/ctf-fs-file.c +++ b/plugins/ctf/fs/file.c @@ -30,11 +30,11 @@ #define PRINT_PREFIX "ctf-fs-file" #include "print.h" -#include "ctf-fs-file.h" +#include "file.h" void ctf_fs_file_destroy(struct ctf_fs_file *file) { - struct ctf_fs *ctf_fs = file->ctf_fs; + struct ctf_fs_component *ctf_fs = file->ctf_fs; if (!file) { return; @@ -56,7 +56,7 @@ void ctf_fs_file_destroy(struct ctf_fs_file *file) g_free(file); } -struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs *ctf_fs) +struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs_component *ctf_fs) { struct ctf_fs_file *file = g_new0(struct ctf_fs_file, 1); @@ -80,7 +80,7 @@ end: return file; } -int ctf_fs_file_open(struct ctf_fs *ctf_fs, struct ctf_fs_file *file, +int ctf_fs_file_open(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file, const char *mode) { int ret = 0; diff --git a/ctf-reader-proto/ctf-fs-file.h b/plugins/ctf/fs/file.h similarity index 85% rename from ctf-reader-proto/ctf-fs-file.h rename to plugins/ctf/fs/file.h index 5da082eb..59f3d0ec 100644 --- a/ctf-reader-proto/ctf-fs-file.h +++ b/plugins/ctf/fs/file.h @@ -26,24 +26,16 @@ #include #include #include - -#include "ctf-fs.h" - -struct ctf_fs_file { - struct ctf_fs *ctf_fs; - GString *path; - FILE *fp; - off_t size; -}; +#include "fs.h" BT_HIDDEN void ctf_fs_file_destroy(struct ctf_fs_file *file); BT_HIDDEN -struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs *ctf_fs); +struct ctf_fs_file *ctf_fs_file_create(struct ctf_fs_component *ctf_fs); BT_HIDDEN -int ctf_fs_file_open(struct ctf_fs *ctf_fs, struct ctf_fs_file *file, +int ctf_fs_file_open(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file, const char *mode); #endif /* CTF_FS_FILE_H */ diff --git a/plugins/ctf/fs/fs.c b/plugins/ctf/fs/fs.c index cd58753a..9019543e 100644 --- a/plugins/ctf/fs/fs.c +++ b/plugins/ctf/fs/fs.c @@ -30,7 +30,8 @@ #include #include #include -#include "fs-internal.h" +#include +#include "fs.h" static bool ctf_fs_debug; @@ -104,15 +105,15 @@ error: return ret; } -static -struct ctf_fs_component *ctf_fs_create(struct bt_value *params) -{ - return g_new0(struct ctf_fs_component, 1); -} - static void ctf_fs_destroy_data(struct ctf_fs_component *component) { + if (component->trace_path) { + g_string_free(component->trace_path, TRUE); + } + +// ctf_fs_metadata_fini(&component->metadata); +// ctf_fs_data_stream_fini(&component->data_stream); g_free(component); } @@ -124,6 +125,45 @@ void ctf_fs_destroy(struct bt_component *component) ctf_fs_destroy_data(data); } +static +struct ctf_fs_component *ctf_fs_create(struct bt_value *params) +{ + struct ctf_fs_component *ctf_fs; + struct bt_value *value; + const char *path; + enum bt_value_status ret; + + ctf_fs = g_new0(struct ctf_fs_component, 1); + if (!ctf_fs) { + goto end; + } + + /* FIXME: should probably look for a source URI */ + value = bt_value_map_get(params, "path"); + if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) { + goto error; + } + + ret = bt_value_string_get(value, &path); + if (ret != BT_VALUE_STATUS_OK) { + goto error; + } + + ctf_fs->trace_path = g_string_new(path); + if (!ctf_fs->trace_path) { + goto error; + } + + ctf_fs->error_fp = stderr; + ctf_fs->page_size = (size_t) getpagesize(); + +end: + return ctf_fs; +error: + ctf_fs_destroy_data(ctf_fs); + return ctf_fs; +} + BT_HIDDEN enum bt_component_status ctf_fs_init(struct bt_component *source, struct bt_value *params) diff --git a/plugins/ctf/fs/fs-internal.h b/plugins/ctf/fs/fs.h similarity index 72% rename from plugins/ctf/fs/fs-internal.h rename to plugins/ctf/fs/fs.h index d0a9f760..ff97b7a2 100644 --- a/plugins/ctf/fs/fs-internal.h +++ b/plugins/ctf/fs/fs.h @@ -5,6 +5,7 @@ * BabelTrace - CTF on File System Component * * Copyright 2016 Jérémie Galarneau + * Copyright 2016 Philippe Proulx * * Author: Jérémie Galarneau * @@ -30,10 +31,41 @@ #include #include -#define CTF_FS_COMPONENT_NAME "ctf" +#define CTF_FS_COMPONENT_NAME "fs" #define CTF_FS_COMPONENT_DESCRIPTION \ "Component used to read a CTF trace located on a file system." +static bool ctf_fs_debug; + +struct ctf_fs_file { + struct ctf_fs_component *ctf_fs; + GString *path; + FILE *fp; + off_t size; +}; + +struct ctf_fs_metadata { + struct bt_ctf_trace *trace; + uint8_t uuid[16]; + bool is_uuid_set; + int bo; + char *text; +}; + +struct ctf_fs_stream { + struct ctf_fs_file *file; + struct bt_ctf_stream *stream; + struct bt_ctf_notif_iter *notif_iter; + void *mmap_addr; + size_t mmap_len; + off_t mmap_offset; + off_t request_offset; +}; + +struct ctf_fs_data_stream { + GPtrArray *streams; +}; + struct ctf_fs_iterator { int dummy; }; @@ -43,6 +75,11 @@ struct ctf_fs_component_options { }; struct ctf_fs_component { + GString *trace_path; + FILE *error_fp; + size_t page_size; + struct ctf_fs_metadata metadata; + struct ctf_fs_data_stream data_stream; struct ctf_fs_component_options options; }; diff --git a/ctf-reader-proto/ctf-fs-metadata.c b/plugins/ctf/fs/metadata.c similarity index 94% rename from ctf-reader-proto/ctf-fs-metadata.c rename to plugins/ctf/fs/metadata.c index bfe24728..967452f9 100644 --- a/ctf-reader-proto/ctf-fs-metadata.c +++ b/plugins/ctf/fs/metadata.c @@ -35,10 +35,11 @@ #define PRINT_PREFIX "ctf-fs-metadata" #include "print.h" -#include "ctf-fs.h" -#include "ctf-fs-file.h" -#include "metadata-parsing/ctf-ast.h" -#include "metadata-parsing/ctf-scanner.h" +#include "fs.h" +#include "file.h" +#include "metadata.h" +#include "../common/metadata/ast.h" +#include "../common/metadata/scanner.h" #define TSDL_MAGIC 0x75d11d57 @@ -55,7 +56,7 @@ struct packet_header { uint8_t minor; } __attribute__((__packed__)); -static struct ctf_fs_file *get_file(struct ctf_fs *ctf_fs, +static struct ctf_fs_file *get_file(struct ctf_fs_component *ctf_fs, const char *trace_path) { struct ctf_fs_file *file = ctf_fs_file_create(ctf_fs); @@ -84,7 +85,7 @@ end: } static -bool is_packetized(struct ctf_fs *ctf_fs, struct ctf_fs_file *file) +bool is_packetized(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file) { uint32_t magic; size_t len; @@ -117,7 +118,7 @@ bool is_version_valid(unsigned int major, unsigned int minor) } static -int decode_packet(struct ctf_fs *ctf_fs, FILE *in_fp, FILE *out_fp) +int decode_packet(struct ctf_fs_component *ctf_fs, FILE *in_fp, FILE *out_fp) { struct packet_header header; size_t readlen, writelen, toread; @@ -218,7 +219,7 @@ end: } static -int packetized_file_to_buf(struct ctf_fs *ctf_fs, struct ctf_fs_file *file, +int packetized_file_to_buf(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file, uint8_t **buf) { FILE *out_fp; @@ -278,7 +279,7 @@ end: return ret; } -void ctf_fs_metadata_set_trace(struct ctf_fs *ctf_fs) +void ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs) { int ret = 0; struct ctf_fs_file *file = get_file(ctf_fs, ctf_fs->trace_path->str); diff --git a/ctf-reader-proto/ctf-fs-metadata.h b/plugins/ctf/fs/metadata.h similarity index 89% rename from ctf-reader-proto/ctf-fs-metadata.h rename to plugins/ctf/fs/metadata.h index ed9b7853..eeccf848 100644 --- a/ctf-reader-proto/ctf-fs-metadata.h +++ b/plugins/ctf/fs/metadata.h @@ -27,19 +27,10 @@ #include #include #include +#include "fs.h" #define CTF_FS_METADATA_FILENAME "metadata" -struct ctf_fs; - -struct ctf_fs_metadata { - struct bt_ctf_trace *trace; - uint8_t uuid[16]; - bool is_uuid_set; - int bo; - char *text; -}; - BT_HIDDEN int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata); @@ -47,6 +38,6 @@ BT_HIDDEN void ctf_fs_metadata_deinit(struct ctf_fs_metadata *metadata); BT_HIDDEN -void ctf_fs_metadata_set_trace(struct ctf_fs *ctf_fs); +void ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs); #endif /* CTF_FS_METADATA_H */ diff --git a/ctf-reader-proto/print.h b/plugins/ctf/fs/print.h similarity index 98% rename from ctf-reader-proto/print.h rename to plugins/ctf/fs/print.h index 4c47f620..9daf7ea4 100644 --- a/ctf-reader-proto/print.h +++ b/plugins/ctf/fs/print.h @@ -27,8 +27,6 @@ #include -#include "ctf-fs.h" - #define PERR(fmt, ...) \ do { \ if (PRINT_ERR_STREAM) { \ diff --git a/plugins/ctf/plugin.c b/plugins/ctf/plugin.c index ef6ed2fd..f84f9ce0 100644 --- a/plugins/ctf/plugin.c +++ b/plugins/ctf/plugin.c @@ -27,19 +27,19 @@ */ #include -#include "fs/fs-internal.h" +#include "fs/fs.h" #include "lttng-live/lttng-live-internal.h" -/* Initialize plug-in entry points. */ +/* Initialize plug-in description. */ BT_PLUGIN_NAME("ctf"); -BT_PLUGIN_DESCRIPTION("Babeltrace CTF plug-in."); +BT_PLUGIN_DESCRIPTION("Built-in Babeltrace plug-in providing CTF read support."); BT_PLUGIN_AUTHOR("Jérémie Galarneau"); BT_PLUGIN_LICENSE("MIT"); +/* Declare component classes implemented by this plug-in. */ BT_PLUGIN_COMPONENT_CLASSES_BEGIN BT_PLUGIN_SOURCE_COMPONENT_CLASS_ENTRY(CTF_FS_COMPONENT_NAME, CTF_FS_COMPONENT_DESCRIPTION, ctf_fs_init); BT_PLUGIN_SOURCE_COMPONENT_CLASS_ENTRY(LTTNG_LIVE_COMPONENT_NAME, LTTNG_LIVE_COMPONENT_DESCRIPTION, lttng_live_init); BT_PLUGIN_COMPONENT_CLASSES_END - diff --git a/plugins/text/text.c b/plugins/text/text.c index a269fe16..9a31041e 100644 --- a/plugins/text/text.c +++ b/plugins/text/text.c @@ -155,7 +155,7 @@ error: } /* Initialize plug-in entry points. */ -BT_PLUGIN_NAME("ctf-text"); +BT_PLUGIN_NAME("text"); BT_PLUGIN_DESCRIPTION("Babeltrace text output plug-in."); BT_PLUGIN_AUTHOR("Jérémie Galarneau"); BT_PLUGIN_LICENSE("MIT"); -- 2.34.1