From a1b275f94c2644b2d96ee8d6f665b9265ec9c2b4 Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Sat, 1 Oct 2022 19:14:29 +0200
Subject: [PATCH] MISC: Remove unused/bugged luka executable

---
 CMakeLists.txt  |  34 +---
 README.md       |   1 +
 src/main/luka.c | 472 ------------------------------------------------
 3 files changed, 3 insertions(+), 504 deletions(-)
 delete mode 100644 src/main/luka.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5a61fd26..61cc7038 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -228,15 +228,6 @@ set(lkt_SOURCES
     src/base/cmd.c
 )
 
-set(luka_SOURCES
-    src/main/luka.c
-    ${lektor_net_SOURCES}
-    ${lektor_base_SOURCES}
-    ${lektor_module_SOURCES}
-    ${lektor_db_SOURCES}
-    ${lektor_mkv_SOURCES}
-)
-
 set(common_DEFINITIONS
     LKT_ARCH="${CMAKE_SYSTEM_PROCESSOR}"
     LKT_MAN_BINARY="${MAN}"
@@ -284,12 +275,11 @@ else()
     )
 endif()
 add_executable(lkt  ${lkt_SOURCES})
-add_executable(luka ${luka_SOURCES} ${SQL_GENERATED_FILE})
 
 set(MANPAGES_COMMANDS)
 if(GENERATE_MANPAGES)
     message(STATUS "Generating manpages")
-    set(MANPAGE_COMMANDS lkt lektord lektor luka)
+    set(MANPAGE_COMMANDS lkt lektord lektor)
     foreach(CMD IN LISTS MANPAGE_COMMANDS)
         add_custom_target(manpage_cmd_${CMD} ALL
             COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/utils/scripts/manpage.bash
@@ -313,27 +303,11 @@ target_link_libraries(lektord PRIVATE
     ${SDL2_IMAGE_LIBRARIES}
     Qt${QT_VERSION_MAJOR}::Widgets
 )
-target_link_libraries(luka PRIVATE
-    ${OpenMP_C_LIBRARIES}
-    ${MPV_LIBRARY}
-    ${CMAKE_DL_LIBS}
-    ${SQLITE3_LIBRARY}
-    ${SDL2_LIBRARIES}
-    ${CURL_LIBRARIES}
-    ${SDL2_IMAGE_LIBRARIES}
-    Qt${QT_VERSION_MAJOR}::Widgets
-)
 target_link_libraries(lkt PRIVATE
     ${OpenMP_C_LIBRARIES}
 )
 
 target_include_directories(lkt  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/inc)
-target_include_directories(luka PRIVATE
-    ${CMAKE_CURRENT_SOURCE_DIR}/inc
-    ${SDL2_INCLUDE_DIRS}
-    ${SDL2_IMAGE_INCLUDE_DIRS}
-    ${CURL_INCLUDE_DIRS}
-)
 target_include_directories(lektord PRIVATE
     ${CMAKE_CURRENT_SOURCE_DIR}/inc
     ${SDL2_INCLUDE_DIRS}
@@ -343,7 +317,6 @@ target_include_directories(lektord PRIVATE
 
 target_compile_definitions(lektord PRIVATE ${common_DEFINITIONS})
 target_compile_definitions(lkt     PRIVATE ${common_DEFINITIONS})
-target_compile_definitions(luka    PRIVATE ${common_DEFINITIONS})
 
 target_compile_options(lektord PRIVATE ${COMMON_C_FLAGS} ${${CMAKE_C_COMPILER_ID}_C_FLAGS} ${${CMAKE_CXX_COMPILER_ID}_CXX_FLAGS})
 target_compile_definitions(lektord PRIVATE
@@ -354,10 +327,8 @@ target_compile_definitions(lektord PRIVATE
 )
 
 target_compile_options(lkt  PRIVATE ${COMMON_C_FLAGS} ${${CMAKE_C_COMPILER_ID}_C_FLAGS} ${${CMAKE_CXX_COMPILER_ID}_CXX_FLAGS})
-target_compile_options(luka PRIVATE ${COMMON_C_FLAGS} ${${CMAKE_C_COMPILER_ID}_C_FLAGS} ${${CMAKE_CXX_COMPILER_ID}_CXX_FLAGS})
 
 set_property(TARGET lektord PROPERTY CXX_STANDARD 20)
-set_property(TARGET luka    PROPERTY CXX_STANDARD 20)
 
 set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/Rust)
 
@@ -401,10 +372,9 @@ target_link_libraries(lektord
 # THE INSTALL DIRECTIVES #
 ###                    ###
 
-install(TARGETS lektord lkt luka
+install(TARGETS lektord lkt
     RUNTIME # For lektord
     RUNTIME # For lkt
-    RUNTIME # For luka
 )
 
 install(FILES
diff --git a/README.md b/README.md
index 9dc67192..aa182786 100644
--- a/README.md
+++ b/README.md
@@ -75,6 +75,7 @@ The manual way of installing and setting up lektor:
 ```sh
 cmake -Bbuild \
     -DCMAKE_C_COMPILER=clang           \ # Choose the compiler
+    -DCMAKE_CXX_COMPILER=clang++       \ # Choose the compiler
     -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ # For clangd/ccls
     -DCMAKE_BUILD_TYPE=Debug             # The debug stuff
 ```
diff --git a/src/main/luka.c b/src/main/luka.c
deleted file mode 100644
index 5a0eb574..00000000
--- a/src/main/luka.c
+++ /dev/null
@@ -1,472 +0,0 @@
-#include <lektor/common.h>
-#include <lektor/cmd.h>
-#include <lektor/config.h>
-#include <lektor/segv.h>
-#include <lektor/commands.h>
-#include <lektor/database.h>
-#include <lektor/uri.h>
-#include <lektor/internal/dbmacro.h>
-#include <signal.h>
-
-/* Static global variables */
-
-static struct queue __queue;
-static struct lkt_module __mod_repo = MOD_NULL;
-static sqlite3 *__db                = NULL;
-
-/* The register */
-REG_DECLARE(repo_reg)
-REG_BEGIN(luka_reg)
-REG_REGISTER("repo", repo_reg)
-REG_END()
-
-/* Utility functions */
-
-DESTRUCTOR_FUNCTION
-___cleanup_db(void)
-{
-    if (__db == NULL)
-        return;
-
-    static const char *SQL = "UPDATE " LKT_PROTECTED_DATABASE ".misc SET opened = 0;";
-    SQLITE_EXEC(__db, SQL, error);
-    LOG_INFO("DB", "Dec open count on db '" LKT_PROTECTED_DATABASE "'");
-    sqlite3_close(__db);
-    LOG_INFO("DB", "Database was closed successfully");
-    __db = NULL;
-    return;
-
-error:
-    LOG_ERROR("DB", "Failed to close database");
-    sqlite3_close(__db);
-    __db = NULL;
-}
-
-DESTRUCTOR_FUNCTION
-___cleanup_repo(void)
-{
-    if (__mod_repo.handle != NULL && __mod_repo.data != NULL && __mod_repo.reg != NULL &&
-        MOD_PROC(__mod_repo, "free")) {
-        LOG_FATAL("Failed to free module repo");
-    }
-    LOG_INFO("REPO", "Module 'repo' was freed successfully");
-}
-
-CONSTRUCTOR_FUNCTION
-___setup(void)
-{
-    char path[PATH_MAX];
-    memset(path, 0, sizeof(path));
-    lkt_queue_new(&__queue);
-    reg_export(luka_reg);
-
-    FAIL_UNLESS(database_new((lkt_db **)&__db), "Can't init sqlite database");
-    FAIL_IF(config_open(__db, path, PATH_MAX), "Failed to read the config");
-
-    database_config_get_text(__db, "database", "db_path", path, PATH_MAX);
-    FAIL_UNLESS(database_open(__db, path, true), "Can't open database %s", path);
-    FAIL_IF(atexit(___cleanup_db), "Failed to register cleanup function");
-    LOG_INFO("SETUP", "Setup of database is OK");
-
-    database_config_get_text(__db, "repo", "module", path, PATH_MAX);
-    LOG_INFO("SETUP", "Try to import repo module from '%s'", path);
-    reg_import(path, &__mod_repo.reg, &__mod_repo.handle);
-    FAIL_IF(MOD_CALL(__mod_repo, "new", &__queue, &__db), "Failed to init repo module %s", path);
-    LOG_INFO("SETUP", "Setup of repo module is OK");
-
-    LOG_INFO("SETUP", "Setup phase was successfull");
-}
-
-/* Private callbacks and internal functions */
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-___handle_queue_and_exit(void)
-{
-#define __CASE(type, func)                                                                   \
-    case LKT_EVENT_##type:                                                                   \
-        if (evt.attr != NULL) {                                                              \
-            LOG_DEBUG("EVENT", "Got event " #type " (%d) with attr (int: %d, ptr %0*p)",     \
-                      LKT_EVENT_##type, evt.attr, sizeof(size_t) * CHAR_BIT / 4, evt.attr);  \
-        } else                                                                               \
-            LOG_DEBUG("EVENT", "Got event " #type " (%d) with NULL attr", LKT_EVENT_##type); \
-        func;                                                                                \
-        break;
-
-    lkt_event evt;
-    size_t update_total   = 0;
-    size_t update_current = 0;
-    bool is_updating      = true;
-
-redo:
-    if (!is_updating) {
-        LKT_OUTPUT("GENERAL", "Luka is not updating the database, exiting");
-        LKT_OUTPUT("GENERAL", "Total update count is %ld out of %ld", update_current, update_total);
-        exit(EXIT_SUCCESS);
-    }
-    evt = lkt_queue_handle(&__queue);
-    switch (evt.type) {
-        // clang-format off
-        __CASE(DB_UPDATE_TOTAL, { update_total += (size_t)evt.attr; })
-        __CASE(DB_UPDATING,     { is_updating   = (((uint8_t)(size_t)evt.attr) > 0); })
-        __CASE(DB_UPDATE_TICK,  {
-            if (update_current != ((size_t)-1))
-                update_current++;
-            if (update_current >= update_total)
-                (LOG_WARN("EVENT", "Force updating state because tikcs exceded the update count"),
-                 is_updating = false, update_total = 0, update_current = 0);
-        })
-
-        __CASE(SKIP_CURRENT, {})
-        __CASE(PLAY_FILE,    {})
-        __CASE(PLAY_POS,     {})
-        __CASE(PLAY_NEXT,    {})
-        __CASE(PLAY_PREV,    {})
-        __CASE(PLAY_TOGGLE,  {})
-        __CASE(PROP_VOL,     {})
-        __CASE(PROP_DUR,     {})
-        __CASE(PROP_TIME,    {})
-        __CASE(NULL,         {})
-
-    /* Something went REALLY wrong */
-    default:
-        LOG_FATAL("Got unknown type event: %ld", evt.type);
-        // clang-format on
-    }
-    goto redo;
-
-#undef __ATTR_IS_STATE
-#undef __CASE
-}
-
-PRIVATE_FUNCTION bool
-___callback_plt_list(struct lkt_state UNUSED *srv, size_t UNUSED c, const char *plt_name)
-{
-    LKT_OUTPUT("PLT_LIST", "name -> %s", plt_name);
-    return true;
-}
-
-PRIVATE_FUNCTION bool
-___callback_list_row(struct lkt_state UNUSED *srv, size_t UNUSED c, int id, int id_len,
-                     const char *sql_row)
-{
-    LKT_OUTPUT("SEARCH", "%*d %s", id_len, id, sql_row);
-    return true;
-}
-
-/* Init database search function */
-typedef bool (*___init_search_function)(lkt_db *, struct lkt_search *);
-
-PRIVATE_FUNCTION void
-___iter_search(___init_search_function init_function, struct lkt_search *search)
-{
-    size_t continuation           = 0, count;
-    struct lkt_search *new_search = database_search_new_from(search);
-
-redo_search_for_continuation:
-    FAIL_UNLESS(init_function((lkt_db *)__db, search), "Failed to init search for database");
-
-    for (count = 0; database_search_iter(search); ++count)
-        continue;
-
-    if (count) {
-        continuation += count;
-        database_search_set_continuation(new_search, continuation);
-        search = database_search_new_from(new_search);
-        goto redo_search_for_continuation;
-    }
-
-    else
-        LOG_WARN("COMMAND", "Nothing found");
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-___search(struct cmd_args *args, ___init_search_function init_function)
-{
-    long count;
-    struct lkt_uri *search_uri = lkt_uri_new();
-    struct lkt_search *search =
-        database_search_new(NULL, 0, 0, FUNCTION_POINTER(___callback_list_row));
-    database_search_set_uri(search, search_uri);
-    database_search_set_name(search, args->argv[0]);
-
-    FAIL_UNLESS(NULL == args->argv[0], "Invalid argument");
-
-    FAIL_IF(args->argv[0] && !args->argv[1] && (count = strtol(args->argv[0], NULL, 0)),
-            "Just an id, use the 'search get' command for that");
-
-    if (!lkt_uri_from(search_uri, (char **)args->argv)) {
-        /* Try from idx 1, in case of playlust searches */
-        LOG_DEBUG(
-            "COMMAND",
-            "URI may not starts at idx 0, may be because of playlist search. At idx 0, value was '%s'",
-            args->argv[0]);
-        FAIL_UNLESS(lkt_uri_from(search_uri, (char **)&(args->argv[1])),
-                    "Failed to create the uri");
-    }
-
-    database_search_set_uri(search, search_uri);
-
-    ___iter_search(init_function, search);
-    lkt_uri_free(search_uri);
-    exit(EXIT_SUCCESS);
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__sigpipe(int sig)
-{
-    LOG_ERROR("GENERAL", "Exit because of signal sigpipe (%d)", sig);
-    exit(EXIT_FAILURE);
-}
-
-/* Command line functions */
-
-PRIVATE_FUNCTION EXIT_FUNCTION __version(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __unref(struct cmd_args *args);
-
-PRIVATE_FUNCTION EXIT_FUNCTION __admin(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __admin_rescan(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __admin_populate(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __admin_update(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __admin_import(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __admin_config(struct cmd_args *args);
-
-PRIVATE_FUNCTION EXIT_FUNCTION __search(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __search_database(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __search_plt(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __search_count(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __search_get(struct cmd_args *args);
-
-PRIVATE_FUNCTION EXIT_FUNCTION __plt(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __plt_delete(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __plt_add(struct cmd_args *args);
-PRIVATE_FUNCTION EXIT_FUNCTION __plt_list(struct cmd_args *args);
-
-// clang-format off
-static struct cmd_opt __options_plt[] = {
-    { "delete",  __plt_delete   },
-    { "add",     __plt_add      },
-    { "list",    __plt_list     },
-    CMD_OPT_NULL,
-};
-
-static struct cmd_opt __options_search[] = {
-    { "plt",      __search_plt      },
-    { "count",    __search_count    },
-    { "get",      __search_get      },
-    { "database", __search_database },
-    CMD_OPT_DEFAULT(__search_database),
-};
-
-static struct cmd_opt __options_admin[] = {
-    { "rescan",   __admin_rescan   },
-    { "populate", __admin_populate },
-    { "update",   __admin_update   },
-    { "import",   __admin_import   },
-    { "config",   __admin_config   },
-    CMD_OPT_NULL,
-};
-
-static struct cmd_opt __options[] = {
-    { "version", __version },
-    { "unref",   __unref   },
-    { "search",  __search  },
-    { "search",  __plt     },
-    { "admin",   __admin   },
-    CMD_OPT_NULL,
-};
-// clang-format on
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__version(struct cmd_args UNUSED *args)
-{
-    puts("Lektor version " LKT_VERSION);
-    exit(EXIT_SUCCESS);
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__unref(struct cmd_args UNUSED *args)
-{
-    /* Should be enaugh to clear the inc in the db */
-    exit(EXIT_SUCCESS);
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__search_database(struct cmd_args *args)
-{
-    ___search(args, database_search_database_init);
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__search_plt(struct cmd_args *args)
-{
-    ___search(args, database_search_playlist_init);
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__search_count(struct cmd_args UNUSED *args)
-{
-    NOT_IMPLEMENTED;
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__search_get(struct cmd_args *args)
-{
-    FAIL_UNLESS(args->argc > 1, "Invalid argument");
-    struct kara_metadata kara;
-    char filepath[PATH_MAX];
-    long id         = strtol(args->argv[0], NULL, 0);
-    double duration = 0.0;
-    memset(&kara, 0, sizeof(struct kara_metadata));
-    memset(filepath, 0, sizeof(filepath));
-    FAIL_UNLESS(database_kara_by_id(__db, (int)id, &kara, filepath), "Failed to find kara %ld", id);
-
-    LKT_OUTPUT("SEARCH", "%s - %s / %s - %s%d - %s [%s]", kara.category, kara.language,
-               kara.source_name, kara.song_type, kara.song_number, kara.song_name,
-               kara.author_name);
-
-    /* Print with the duration */
-    if (!kara_read_length(&duration, filepath)) {
-        int s = (int)(duration * 10e-10);
-        int h = s / 3600;
-        s     = s % 3600;
-        int m = s / 60;
-        s     = s % 60;
-        LKT_OUTPUT("SEARCH", "Duration: %d:%02d:%02d", h, m, s);
-    }
-
-    exit(EXIT_SUCCESS);
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__plt_delete(struct cmd_args *args)
-{
-    FAIL_UNLESS(args->argc < 1, "Invalid number of arguments");
-    char *endptr = NULL, err;
-    long pos;
-
-    if (args->argv[1] == NULL)
-        exit(!database_plt_remove(__db, args->argv[0]));
-
-    STRTOL(pos, args->argv[1], endptr, err);
-    FAIL_IF(err, "STRTOL failed");
-    exit(!database_plt_remove_pos(__db, args->argv[0], (int)pos));
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__plt_add(struct cmd_args *args)
-{
-    struct lkt_uri *uri = lkt_uri_new();
-    int ret_code        = EXIT_FAILURE;
-
-    if (args->argc == 1)
-        exit(!database_plt_create(__db, args->argv[0]));
-
-    if (!lkt_uri_from(uri, (char *)args->argv[1])) {
-        LOG_ERROR("COMMAND", "Failed to get uri");
-        goto end_plt_add_uri;
-    }
-
-    else if (!database_plt_add_uri(__db, args->argv[0], uri)) {
-        LOG_ERROR("COMMAND", "Failed to add uri '%s' to playlist", args->argv[1]);
-        goto end_plt_add_uri;
-    }
-
-    ret_code = EXIT_SUCCESS;
-end_plt_add_uri:
-    lkt_uri_free(uri);
-    exit(ret_code);
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__plt_list(struct cmd_args *args)
-{
-    function_ptr callback     = args->argc ? FUNCTION_POINTER(___callback_list_row)
-                                           : FUNCTION_POINTER(___callback_plt_list);
-    struct lkt_uri *null_uri  = lkt_uri_new();
-    struct lkt_search *search = database_search_new(NULL, 0, 0, callback);
-    database_search_set_name(search, args->argc ? args->argv[0] : NULL);
-    database_search_set_uri(search, null_uri);
-
-    ___iter_search(database_search_listplaylist_init, search);
-    lkt_uri_free(null_uri);
-    exit(EXIT_SUCCESS);
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__admin_rescan(struct cmd_args UNUSED *args)
-{
-    FAIL_IF(MOD_PROC(__mod_repo, "rescan"),
-            "Failed to call the 'rescan' function from the repo module");
-    ___handle_queue_and_exit();
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__admin_populate(struct cmd_args UNUSED *args)
-{
-    __admin_rescan(args);
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__admin_update(struct cmd_args UNUSED *args)
-{
-    /* Will need to be copied by the repo module before calling the thread thing */
-    struct lkt_uri *null_uri = lkt_uri_new();
-
-    FAIL_IF(MOD_CALL(__mod_repo, "update", null_uri),
-            "Failed to call the 'update' function from the repo module");
-    lkt_uri_free(null_uri);
-    ___handle_queue_and_exit();
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__admin_import(struct cmd_args UNUSED *args)
-{
-    FAIL_IF(MOD_PROC(__mod_repo, "import"),
-            "Failed to call the 'import' function from the repo module");
-    ___handle_queue_and_exit();
-}
-
-PRIVATE_FUNCTION EXIT_FUNCTION
-__admin_config(struct cmd_args UNUSED *args)
-{
-    fwrite(lkt_default_config_file, sizeof(char), strlen(lkt_default_config_file), stdout);
-    exit(EXIT_SUCCESS);
-}
-
-/* Sub commands functions */
-
-#define __SUB_COMMAND(name) /* Create sub-commands here */                             \
-    PRIVATE_FUNCTION EXIT_FUNCTION __##name(struct cmd_args *args)                     \
-    {                                                                                  \
-        FAIL_IF(args->argc == 0, "Invalid command, specify a sub command for " #name); \
-        cmd_parse(__options_##name, args->argc, args->argv);                           \
-    }
-__SUB_COMMAND(plt)
-__SUB_COMMAND(search)
-__SUB_COMMAND(admin)
-#undef __SUB_COMMAND
-
-/* The main function */
-
-int
-main(const int argc, const char **argv)
-{
-    cmd_set_executable_name("luka");
-    lkt_set_log_level(LOG_LEVEL_ERROR);
-    lkt_segv_quiet();
-    lkt_install_segv_handler();
-
-    /* Enforce some locals */
-    RETURN_UNLESS(setlocale(LC_ALL, ""), "Failed to set LC_ALL to UTF-8", 1);
-    RETURN_UNLESS(setlocale(LC_CTYPE, ""), "Failed to set LC_CTYPE", 1);
-    RETURN_UNLESS(setlocale(LC_NUMERIC, ""), "Failed to set LC_NUMERIC for mpv", 1);
-    RETURN_UNLESS(STR_MATCH(nl_langinfo(CODESET), "UTF-8"),
-                  "Your locale is not set to an UTF-8 one. "
-                  "Consider using en_US.UTF-8 or fr_FR.UTF-8!",
-                  1);
-
-    if (signal(SIGPIPE, __sigpipe))
-        LOG_ERROR("SYS", "Failed to install handler for SIGPIPE signal (you may be using php...)");
-
-    cmd_parse(__options, argc - 1, argv + 1);
-}
-- 
GitLab