From 5de93a90f20b9ce35d4799d521029f2fde5c6441 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Fri, 10 Apr 2020 00:23:49 +0200
Subject: Created extra flags for binary symbols.

---
 plugins/pychrysalide/format/constants.c |  14 +++
 plugins/pychrysalide/format/symbol.c    | 198 ++++++++++++++++++++++++++++++++
 src/format/symbol-int.h                 |   1 +
 src/format/symbol.c                     | 133 ++++++++++++++++++++-
 src/format/symbol.h                     |  23 +++-
 tests/format/symbol.py                  |  43 ++++++-
 6 files changed, 402 insertions(+), 10 deletions(-)

diff --git a/plugins/pychrysalide/format/constants.c b/plugins/pychrysalide/format/constants.c
index 4ffdc5f..dfa4615 100644
--- a/plugins/pychrysalide/format/constants.c
+++ b/plugins/pychrysalide/format/constants.c
@@ -85,6 +85,20 @@ bool define_binary_symbol_constants(PyTypeObject *type)
     result = attach_constants_group_to_type(type, false, "SymbolStatus", values,
                                             "Status of a symbol visibility.");
 
+    values = PyDict_New();
+
+    result = add_const_to_group(values, "NONE", SFL_NONE);
+    if (result) result = add_const_to_group(values, "PREFIXED_NAME", SFL_PREFIXED_NAME);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group_to_type(type, true, "SymbolFlag", values,
+                                            "Extra indications for symbols.");
+
  exit:
 
     return result;
diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c
index c67d6e7..75eb8f4 100644
--- a/plugins/pychrysalide/format/symbol.c
+++ b/plugins/pychrysalide/format/symbol.c
@@ -72,6 +72,15 @@ static int py_binary_symbol_init(PyObject *, PyObject *, PyObject *);
 /* Effectue une comparaison avec un objet Python 'BinSymbol'. */
 static PyObject *py_binary_symbol_richcompare(PyObject *, PyObject *, int);
 
+/* Ajoute une information complémentaire à un symbole. */
+static PyObject *py_binary_symbol_set_flag(PyObject *, PyObject *);
+
+/* Retire une information complémentaire à un symbole. */
+static PyObject *py_binary_symbol_unset_flag(PyObject *, PyObject *);
+
+/* Détermine si un symbole possède un fanion particulier. */
+static PyObject *py_binary_symbol_has_flag(PyObject *, PyObject *);
+
 /* Fournit l'emplacement où se situe un symbole. */
 static PyObject *py_binary_symbol_get_range(PyObject *, void *);
 
@@ -93,6 +102,9 @@ static PyObject *py_binary_symbol_get_status(PyObject *, void *);
 /* Définit la visibilité du symbole. */
 static int py_binary_symbol_set_status(PyObject *, PyObject *, void *);
 
+/* Fournit les particularités du symbole. */
+static PyObject *py_binary_symbol_get_flags(PyObject *, void *);
+
 /* Définit un autre nom pour le symbole. */
 static int py_binary_symbol_set_label(PyObject *, PyObject *, void *);
 
@@ -343,6 +355,152 @@ static PyObject *py_binary_symbol_richcompare(PyObject *a, PyObject *b, int op)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = serveur à manipuler.                                  *
+*                args = arguments d'appel non utilisés ici.                   *
+*                                                                             *
+*  Description : Ajoute une information complémentaire à un symbole.          *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_symbol_set_flag(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    unsigned int flag;                      /* Propriété à traiter         */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBinSymbol *symbol;                     /* Elément à manipuler         */
+    bool status;                            /* Bilan de l'opération        */
+
+#define BINARY_SYMBOL_SET_FLAG_METHOD PYTHON_METHOD_DEF             \
+(                                                                   \
+    set_flag, "$self, flag, /",                                     \
+    METH_VARARGS, py_binary_symbol,                                 \
+    "Add a property from a binary symbol.\n"                        \
+    "\n"                                                            \
+    "This property is one of the values listed in the"              \
+    " of pychrysalide.format.BinSymbol.SymbolFlag enumeration.\n"   \
+    "\n"                                                            \
+    "If the flag was not set before the operation, True is"         \
+    " returned, else the result is False."                          \
+)
+
+    ret = PyArg_ParseTuple(args, "I", &flag);
+    if (!ret) return NULL;
+
+    symbol = G_BIN_SYMBOL(pygobject_get(self));
+
+    status = g_binary_symbol_set_flag(symbol, flag);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = serveur à manipuler.                                  *
+*                args = arguments d'appel non utilisés ici.                   *
+*                                                                             *
+*  Description : Retire une information complémentaire à un symbole.          *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_symbol_unset_flag(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    unsigned int flag;                      /* Propriété à traiter         */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBinSymbol *symbol;                     /* Elément à manipuler         */
+    bool status;                            /* Bilan de l'opération        */
+
+#define BINARY_SYMBOL_UNSET_FLAG_METHOD PYTHON_METHOD_DEF           \
+(                                                                   \
+    unset_flag, "$self, flag, /",                                   \
+    METH_VARARGS, py_binary_symbol,                                 \
+    "Remove a property from a binary symbol.\n"                     \
+    "\n"                                                            \
+    "This property is one of the values listed in the"              \
+    " of pychrysalide.format.BinSymbol.SymbolFlag enumeration.\n"   \
+    "\n"                                                            \
+    "If the flag was not set before the operation, False is"        \
+    " returned, else the result is True."                           \
+)
+
+    ret = PyArg_ParseTuple(args, "I", &flag);
+    if (!ret) return NULL;
+
+    symbol = G_BIN_SYMBOL(pygobject_get(self));
+
+    status = g_binary_symbol_unset_flag(symbol, flag);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = serveur à manipuler.                                  *
+*                args = arguments d'appel non utilisés ici.                   *
+*                                                                             *
+*  Description : Détermine si un symbole possède un fanion particulier.       *
+*                                                                             *
+*  Retour      : Bilan de la détection.                                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_symbol_has_flag(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    unsigned int flag;                      /* Propriété à traiter         */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBinSymbol *symbol;                     /* Elément à manipuler         */
+    bool status;                            /* Bilan de l'opération        */
+
+#define BINARY_SYMBOL_HAS_FLAG_METHOD PYTHON_METHOD_DEF             \
+(                                                                   \
+    has_flag, "$self, flag, /",                                     \
+    METH_VARARGS, py_binary_symbol,                                 \
+    "Test if a binary symbol has a given property.\n"               \
+    "\n"                                                            \
+    "This property is one of the values listed in the"              \
+    " of pychrysalide.format.BinSymbol.SymbolFlag enumeration.\n"   \
+    "\n"                                                            \
+    "The result is a boolean value."                                \
+)
+
+    ret = PyArg_ParseTuple(args, "I", &flag);
+    if (!ret) return NULL;
+
+    symbol = G_BIN_SYMBOL(pygobject_get(self));
+
+    status = g_binary_symbol_has_flag(symbol, flag);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
@@ -553,6 +711,42 @@ static int py_binary_symbol_set_status(PyObject *self, PyObject *value, void *cl
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
+*  Description : Fournit les particularités du symbole.                       *
+*                                                                             *
+*  Retour      : Somme de tous les fanions associés au symbole.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_symbol_get_flags(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Valeur à retourner          */
+    GBinSymbol *symbol;                     /* Elément à consulter         */
+    SymbolFlag flags;                       /* Indications complémentaires */
+
+#define BINARY_SYMBOL_FLAGS_ATTRIB PYTHON_GET_DEF_FULL          \
+(                                                               \
+    flags, py_binary_symbol,                                    \
+    "Provide all the flags set for a symbol. The return value"  \
+    " is of type pychrysalide.format.BinSymbol.SymbolFlag."     \
+)
+
+    symbol = G_BIN_SYMBOL(pygobject_get(self));
+    flags = g_binary_symbol_get_flags(symbol);
+
+    result = cast_with_constants_group_from_type(get_python_binary_symbol_type(), "SymbolFlag", flags);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
 *  Description : Fournit un étiquette pour viser un symbole.                  *
 *                                                                             *
 *  Retour      : Chaîne de caractères renvoyant au symbole.                   *
@@ -647,6 +841,9 @@ static int py_binary_symbol_set_label(PyObject *self, PyObject *value, void *clo
 PyTypeObject *get_python_binary_symbol_type(void)
 {
     static PyMethodDef binary_symbol_methods[] = {
+        BINARY_SYMBOL_SET_FLAG_METHOD,
+        BINARY_SYMBOL_UNSET_FLAG_METHOD,
+        BINARY_SYMBOL_HAS_FLAG_METHOD,
         { NULL }
     };
 
@@ -654,6 +851,7 @@ PyTypeObject *get_python_binary_symbol_type(void)
         BINARY_SYMBOL_RANGE_ATTRIB,
         BINARY_SYMBOL_STYPE_ATTRIB,
         BINARY_SYMBOL_STATUS_ATTRIB,
+        BINARY_SYMBOL_FLAGS_ATTRIB,
         BINARY_SYMBOL_LABEL_ATTRIB,
         { NULL }
     };
diff --git a/src/format/symbol-int.h b/src/format/symbol-int.h
index e2c3292..77ffd39 100644
--- a/src/format/symbol-int.h
+++ b/src/format/symbol-int.h
@@ -41,6 +41,7 @@ typedef union _sym_obj_extra
     {
         SymbolType stype;                   /* Type du symbole             */
         SymbolStatus status;                /* Visibilité du symbole       */
+        SymbolFlag flags;                   /* Informations complémentaires*/
 
     };
 
diff --git a/src/format/symbol.c b/src/format/symbol.c
index c10c46d..7d272ce 100644
--- a/src/format/symbol.c
+++ b/src/format/symbol.c
@@ -68,7 +68,7 @@ static void g_binary_symbol_compute_cursor(const GBinSymbol *, gint, size_t, siz
 static int g_binary_symbol_contains_cursor(const GBinSymbol *, size_t, size_t, const GLineCursor *);
 
 /* Renseigne sur les propriétés liées à un générateur. */
-static BufferLineFlags g_binary_symbol_get_flags(const GBinSymbol *, size_t, size_t);
+static BufferLineFlags g_binary_symbol_get_line_flags(const GBinSymbol *, size_t, size_t);
 
 /* Imprime dans une ligne de rendu le contenu représenté. */
 static void g_binary_symbol_print(GBinSymbol *, GBufferLine *, size_t, size_t, const GBinContent *);
@@ -149,7 +149,7 @@ static void g_binary_symbol_interface_init(GLineGeneratorInterface *iface)
     iface->count = (linegen_count_lines_fc)g_binary_symbol_count_lines;
     iface->compute = (linegen_compute_fc)g_binary_symbol_compute_cursor;
     iface->contains = (linegen_contains_fc)g_binary_symbol_contains_cursor;
-    iface->get_flags = (linegen_get_flags_fc)g_binary_symbol_get_flags;
+    iface->get_flags = (linegen_get_flags_fc)g_binary_symbol_get_line_flags;
     iface->print = (linegen_print_fc)g_binary_symbol_print;
 
 }
@@ -433,6 +433,133 @@ SymbolStatus g_binary_symbol_get_status(const GBinSymbol *symbol)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : symbol = symbole à venir modifier.                           *
+*                flag   = drapeau d'information complémentaire à planter.     *
+*                                                                             *
+*  Description : Ajoute une information complémentaire à un symbole.          *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_binary_symbol_set_flag(GBinSymbol *symbol, SymbolFlag flag)
+{
+    bool result;                            /* Bilan à retourner           */
+    sym_obj_extra *extra;                   /* Données insérées à modifier */
+
+    extra = GET_BIN_SYMBOL_EXTRA(symbol);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    result = !(extra->flags & flag);
+
+    extra->flags |= flag;
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : symbol = symbole à venir modifier.                           *
+*                flag   = drapeau d'information complémentaire à planter.     *
+*                                                                             *
+*  Description : Retire une information complémentaire à un symbole.          *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_binary_symbol_unset_flag(GBinSymbol *symbol, SymbolFlag flag)
+{
+    bool result;                            /* Bilan à retourner           */
+    sym_obj_extra *extra;                   /* Données insérées à modifier */
+
+    extra = GET_BIN_SYMBOL_EXTRA(symbol);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    result = (extra->flags & flag);
+
+    extra->flags &= ~flag;
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : symbol = symbole à venir consulter.                          *
+*                flag   = drapeau d'information à rechercher.                 *
+*                                                                             *
+*  Description : Détermine si un symbole possède un fanion particulier.       *
+*                                                                             *
+*  Retour      : Bilan de la détection.                                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_binary_symbol_has_flag(const GBinSymbol *symbol, SymbolFlag flag)
+{
+    bool result;                            /* Bilan à retourner           */
+    sym_obj_extra *extra;                   /* Données insérées à modifier */
+
+    extra = GET_BIN_SYMBOL_EXTRA(symbol);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    result = (extra->flags & flag);
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : symbol = symbole à venir consulter.                          *
+*                                                                             *
+*  Description : Fournit les particularités du symbole.                       *
+*                                                                             *
+*  Retour      : Somme de tous les fanions associés au symbole.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+SymbolFlag g_binary_symbol_get_flags(const GBinSymbol *symbol)
+{
+    SymbolFlag result;                      /* Fanions à retourner         */
+    sym_obj_extra *extra;                   /* Données insérées à modifier */
+
+    extra = GET_BIN_SYMBOL_EXTRA(symbol);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    result = extra->flags;
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : symbol = symbole à venir consulter.                          *
 *                                                                             *
 *  Description : Fournit une étiquette pour viser un symbole.                 *
@@ -626,7 +753,7 @@ static int g_binary_symbol_contains_cursor(const GBinSymbol *symbol, size_t inde
 *                                                                             *
 ******************************************************************************/
 
-static BufferLineFlags g_binary_symbol_get_flags(const GBinSymbol *symbol, size_t index, size_t repeat)
+static BufferLineFlags g_binary_symbol_get_line_flags(const GBinSymbol *symbol, size_t index, size_t repeat)
 {
     return BLF_IS_LABEL;
 
diff --git a/src/format/symbol.h b/src/format/symbol.h
index 48f740e..e304d69 100644
--- a/src/format/symbol.h
+++ b/src/format/symbol.h
@@ -50,7 +50,6 @@ typedef enum _SymbolType
 
 } SymbolType;
 
-
 /* Visibilité du symbole */
 typedef enum _SymbolStatus
 {
@@ -63,6 +62,16 @@ typedef enum _SymbolStatus
 
 } SymbolStatus;
 
+/* Indications supplémentaires liées aux symboles */
+typedef enum _SymbolFlag
+{
+    SFL_NONE          = (0 << 0),           /* Aucune propriété            */
+    SFL_PREFIXED_NAME = (1 << 0),           /* Indication en amont du nom  */
+
+    SFL_COUNT
+
+} SymbolFlag;
+
 
 #define G_TYPE_BIN_SYMBOL            g_binary_symbol_get_type()
 #define G_BIN_SYMBOL(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BIN_SYMBOL, GBinSymbol))
@@ -109,6 +118,18 @@ void g_binary_symbol_set_status(GBinSymbol *, SymbolStatus);
 /* Fournit la visibilité du symbole. */
 SymbolStatus g_binary_symbol_get_status(const GBinSymbol *);
 
+/* Ajoute une information complémentaire à un symbole. */
+bool g_binary_symbol_set_flag(GBinSymbol *, SymbolFlag);
+
+/* Retire une information complémentaire à un symbole. */
+bool g_binary_symbol_unset_flag(GBinSymbol *, SymbolFlag);
+
+/* Détermine si un symbole possède un fanion particulier. */
+bool g_binary_symbol_has_flag(const GBinSymbol *, SymbolFlag);
+
+/* Fournit les particularités du symbole. */
+SymbolFlag g_binary_symbol_get_flags(const GBinSymbol *);
+
 /* Fournit une étiquette pour viser un symbole. */
 char *g_binary_symbol_get_label(const GBinSymbol *);
 
diff --git a/tests/format/symbol.py b/tests/format/symbol.py
index 6c4f573..fed4133 100644
--- a/tests/format/symbol.py
+++ b/tests/format/symbol.py
@@ -17,7 +17,7 @@ class TestBinarySymbols(ChrysalideTestCase):
     def testSymbolProperties(self):
         """Validate the basic properties of symbols."""
 
-        saddr = vmpa(0x10, vmpa.VMPA_NO_VIRTUAL)
+        saddr = vmpa(0x10, vmpa.VmpaSpecialValue.NO_VIRTUAL)
         srange = mrange(saddr, 0x3)
         symbol = BinSymbol(srange, BinSymbol.SymbolType.ENTRY_POINT)
 
@@ -53,7 +53,7 @@ class TestBinarySymbols(ChrysalideTestCase):
     def testSymbolDefaultStatus(self):
         """Validate the default status for symbols."""
 
-        saddr = vmpa(0x10, vmpa.VMPA_NO_VIRTUAL)
+        saddr = vmpa(0x10, vmpa.VmpaSpecialValue.NO_VIRTUAL)
         srange = mrange(saddr, 0x3)
         symbol = BinSymbol(srange, BinSymbol.SymbolType.ENTRY_POINT)
 
@@ -62,18 +62,49 @@ class TestBinarySymbols(ChrysalideTestCase):
         self.assertEqual(str(symbol.status), 'SymbolStatus.INTERNAL')
 
 
+    def testSymbolFlags(self):
+        """Play with symbol flags."""
+
+        saddr = vmpa(0x10, vmpa.VmpaSpecialValue.NO_VIRTUAL)
+        srange = mrange(saddr, 0x3)
+        symbol = BinSymbol(srange, BinSymbol.SymbolType.ENTRY_POINT)
+
+        self.assertEqual(symbol.flags, BinSymbol.SymbolFlag.NONE)
+
+        ret = symbol.set_flag(BinSymbol.SymbolFlag.NONE)
+        self.assertTrue(ret)
+
+        ret = symbol.has_flag(BinSymbol.SymbolFlag.NONE)
+        self.assertFalse(ret)
+
+        ret = symbol.unset_flag(BinSymbol.SymbolFlag.NONE)
+        self.assertFalse(ret)
+
+        ret = symbol.set_flag(BinSymbol.SymbolFlag.PREFIXED_NAME)
+        self.assertTrue(ret)
+
+        ret = symbol.has_flag(BinSymbol.SymbolFlag.PREFIXED_NAME)
+        self.assertTrue(ret)
+
+        ret = symbol.unset_flag(BinSymbol.SymbolFlag.PREFIXED_NAME)
+        self.assertTrue(ret)
+
+        ret = symbol.has_flag(BinSymbol.SymbolFlag.PREFIXED_NAME)
+        self.assertFalse(ret)
+
+
     def testSymbolComparison(self):
         """Compare symbols and check the result."""
 
-        saddr = vmpa(0x100, vmpa.VMPA_NO_VIRTUAL)
+        saddr = vmpa(0x100, vmpa.VmpaSpecialValue.NO_VIRTUAL)
         srange = mrange(saddr, 0x3)
         symbol0 = BinSymbol(srange, BinSymbol.SymbolType.ENTRY_POINT)
 
-        saddr = vmpa(0x10, vmpa.VMPA_NO_VIRTUAL)
+        saddr = vmpa(0x10, vmpa.VmpaSpecialValue.NO_VIRTUAL)
         srange = mrange(saddr, 0x3)
         symbol1 = BinSymbol(srange, BinSymbol.SymbolType.ENTRY_POINT)
 
-        saddr = vmpa(0x100, vmpa.VMPA_NO_VIRTUAL)
+        saddr = vmpa(0x100, vmpa.VmpaSpecialValue.NO_VIRTUAL)
         srange = mrange(saddr, 0x30)
         symbol2 = BinSymbol(srange, BinSymbol.SymbolType.ENTRY_POINT)
 
@@ -93,7 +124,7 @@ class TestBinarySymbols(ChrysalideTestCase):
             def _get_label(self):
                 return 'AAA'
 
-        saddr = vmpa(0x100, vmpa.VMPA_NO_VIRTUAL)
+        saddr = vmpa(0x100, vmpa.VmpaSpecialValue.NO_VIRTUAL)
         srange = mrange(saddr, 0x3)
         symbol = MySymbol(srange, BinSymbol.SymbolType.ENTRY_POINT)
 
-- 
cgit v0.11.2-87-g4458