Hi Adrian,

Sorry, I didn't notice but in the wip.patch the ide_codium.py file is missing.
In attachment is wip2.patch that includes all the differences.

> 
> Yes, that's because cmake and also meson have the compile_commands.json
> generator built in. With meson it's enabled by default, with cmake we
> enable this feature
> here: https://git.yoctoproject.org/poky/tree/meta/classes-
> recipe/cmake.bbclass#n185.
> 
> 

So if cmake compile_commands.json is generated automatically with this 
OECMAKE_ARGS variable, then can I remove

> 
> "cmake.configureSettings": {
> "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
> }
> 

from the cmake_kit_new variable in ide_codium.py (because it is redundant)?

> 
> For the kernel and the u-boot recipes that seams to be possible:
> *
> https://github.com/torvalds/linux/blob/master/scripts/clang-tools/gen_compile_commands.py
> 
> *
> https://github.com/u-boot/u-boot/blob/master/scripts/gen_compile_commands.py
> 
> That looks like we can use these scripts which are available as make
> targets out of the box.
> 

I know of them, but I didn't use them.
I think you need to first have all the build files present in the project and 
then the scripts parses those build files.
Probably this additional step can be automated in ide_codium.py.
But the build (I think .cmd) files aren't located in the workspace/sources/ 
directory but in build/tmp/work/...
In compile_commands.json all paths are absolute so this could be a problem.
I can play with the scripts and see if I can make them work.

> 
> But handling recipes with the ide-sdk fallback mode is not ideal.
> Handling the recipes in a build-tool specific way leads to a much
> better user experience. To add support for recipes using the kbuild
> framework (u-boot, kernel) we could:
> * Add another elif case for them to this
> if: https://git.yoctoproject.org/poky/tree/scripts/lib/devtool/ide_s
> dk.py#n377.
> elif bb.data.inherits_class('cml1', recipe_d):
> Then these recipes are no longer handled by the fallback mode of
> ide-sdk
> * Then we can recommend a Makefile vscode plugin
> like 
> https://marketplace.visualstudio.com/items?itemName=ms-vscode.makefile-tools
> 
> or something more open source if you like.
> Having a plugin like that allows to configure the plugin for cross-
> compilation with Yocto's tool-chain.
> Alternative we could generate some task which call make with the
> right configuration. But this is usually a bit clunky as well.
> 

I don't fully understand the code to add kbuild and make build tool specific 
handles in ide_sdk.py.
That is why I used the bear tool.
It can index all cases at the devtool ide-sdk stage.
User doesn't need to do anything additionally.
It would be better if kbuild and make were supported in ide_sdk.py.
kbuild (linux and u-boot) will be indexed by scripts, but how would make 
projects be indexed (generation of compiler_commands.json) if bear tool isn't 
used?

Probably the usage of the bear tool isn't ideal, but it gives the functionality 
that can later be optimized (replaced) with kbuild and make handles in 
ide_sdk.py
I just don't get why in my implementation the do_package task breaks.

Best regards,
Karlo
diff --git a/oe-init-build-env b/oe-init-build-env
index 82382f2..79075d2 100755
--- a/oe-init-build-env
+++ b/oe-init-build-env
@@ -48,8 +48,8 @@ export OEROOT
     return 1
 }
 
-# Generate an initial configuration for VSCode and the yocto-bitbake plugin.
-if command -v code > /dev/null && [ ! -d "$OEROOT/.vscode" ]; then
+# Generate an initial configuration for VSCode or VSCodium and the yocto-bitbake plugin.
+if command -v code > /dev/null || command -v codium > /dev/null && [ ! -d "$OEROOT/.vscode" ]; then
     oe-setup-vscode "$OEROOT" "$BUILDDIR"
 fi
 
diff --git a/scripts/lib/devtool/ide_plugins/ide_code.py b/scripts/lib/devtool/ide_plugins/ide_code.py
index a62b932..69d1754 100644
--- a/scripts/lib/devtool/ide_plugins/ide_code.py
+++ b/scripts/lib/devtool/ide_plugins/ide_code.py
@@ -3,7 +3,7 @@
 #
 # SPDX-License-Identifier: GPL-2.0-only
 #
-"""Devtool ide-sdk IDE plugin for VSCode and VSCodium"""
+"""Devtool ide-sdk IDE plugin for VSCode"""
 
 import json
 import logging
diff --git a/scripts/lib/devtool/ide_plugins/ide_codium.py b/scripts/lib/devtool/ide_plugins/ide_codium.py
new file mode 100644
index 0000000..349abca
--- /dev/null
+++ b/scripts/lib/devtool/ide_plugins/ide_codium.py
@@ -0,0 +1,464 @@
+#
+# Copyright (C) 2024 Karlo Strize
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+"""Devtool ide-sdk IDE plugin for VSCodium"""
+
+import json
+import logging
+import os
+import shutil
+from devtool.ide_plugins import BuildTool, IdeBase, GdbCrossConfig, get_devtool_deploy_opts
+
+logger = logging.getLogger('devtool')
+
+
+class GdbCrossConfigVSCodium(GdbCrossConfig):
+    def __init__(self, image_recipe, modified_recipe, binary):
+        super().__init__(image_recipe, modified_recipe, binary, False)
+
+    def initialize(self):
+        self._gen_gdbserver_start_script()
+
+
+class IdeVSCodium(IdeBase):
+    """Manage IDE configurations for VSCodium
+
+    Modified recipe mode:
+    - cmake: use the cmake-preset generated by devtool ide-sdk
+    - meson: meson is called via a wrapper script generated by devtool ide-sdk
+
+    Shared sysroot mode:
+    In shared sysroot mode, the cross tool-chain is exported to the user's global configuration.
+    A workspace cannot be created because there is no recipe that defines how a workspace could
+    be set up.
+    - cmake: adds a cmake-kit to .local/share/CMakeTools/cmake-tools-kits.json
+             The cmake-kit uses the environment script and the tool-chain file
+             generated by meta-ide-support.
+    - meson: Meson needs manual workspace configuration.
+    """
+
+    @classmethod
+    def ide_plugin_priority(cls):
+        """If --ide is not passed this is the default plugin"""
+        if shutil.which('codium'):
+            return 100
+        return 0
+
+    def setup_shared_sysroots(self, shared_env):
+        """Expose the toolchain of the shared sysroots SDK"""
+        datadir = shared_env.ide_support.datadir
+        deploy_dir_image = shared_env.ide_support.deploy_dir_image
+        real_multimach_target_sys = shared_env.ide_support.real_multimach_target_sys
+        standalone_sysroot_native = shared_env.build_sysroots.standalone_sysroot_native
+        vscodium_ws_path = os.path.join(
+            os.environ['HOME'], '.local', 'share', 'CMakeTools')
+        cmake_kits_path = os.path.join(vscodium_ws_path, 'cmake-tools-kits.json')
+        oecmake_generator = "Ninja" # "Unix Makefiles"
+        env_script = os.path.join(
+            deploy_dir_image, 'environment-setup-' + real_multimach_target_sys)
+
+        if not os.path.isdir(vscodium_ws_path):
+            os.makedirs(vscodium_ws_path)
+        cmake_kits_old = []
+        if os.path.exists(cmake_kits_path):
+            with open(cmake_kits_path, 'r', encoding='utf-8') as cmake_kits_file:
+                cmake_kits_old = json.load(cmake_kits_file)
+        cmake_kits = cmake_kits_old.copy()
+
+        cmake_kit_new = {
+            "name": "OE " + real_multimach_target_sys,
+            "environmentSetupScript": env_script,
+            "toolchainFile": standalone_sysroot_native + datadir + "/cmake/OEToolchainConfig.cmake",
+            "preferredGenerator": {
+                "name": oecmake_generator
+            },
+            "cmake.configureSettings": {
+                "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
+            }
+        }
+
+        def merge_kit(cmake_kits, cmake_kit_new):
+            i = 0
+            while i < len(cmake_kits):
+                if 'environmentSetupScript' in cmake_kits[i] and \
+                        cmake_kits[i]['environmentSetupScript'] == cmake_kit_new['environmentSetupScript']:
+                    cmake_kits[i] = cmake_kit_new
+                    return
+                i += 1
+            cmake_kits.append(cmake_kit_new)
+        merge_kit(cmake_kits, cmake_kit_new)
+
+        if cmake_kits != cmake_kits_old:
+            logger.info("Updating: %s" % cmake_kits_path)
+            with open(cmake_kits_path, 'w', encoding='utf-8') as cmake_kits_file:
+                json.dump(cmake_kits, cmake_kits_file, indent=4)
+        else:
+            logger.info("Already up to date: %s" % cmake_kits_path)
+
+        cmake_native = os.path.join(
+            shared_env.build_sysroots.standalone_sysroot_native, 'usr', 'bin', 'cmake')
+        if os.path.isfile(cmake_native):
+            logger.info('cmake-kits call cmake by default. If the cmake provided by this SDK should be used, please add the following line to ".vscode/settings.json" file: "cmake.cmakePath": "%s"' % cmake_native)
+        else:
+            logger.error("Cannot find cmake native at: %s" % cmake_native)
+
+    def dot_code_dir(self, modified_recipe):
+        return os.path.join(modified_recipe.srctree, '.vscode')
+
+    def __vscodium_settings_meson(self, settings_dict, modified_recipe):
+        if modified_recipe.build_tool is not BuildTool.MESON:
+            return
+        settings_dict["mesonbuild.mesonPath"] = modified_recipe.meson_wrapper
+
+        confopts = modified_recipe.mesonopts.split()
+        confopts += modified_recipe.meson_cross_file.split()
+        confopts += modified_recipe.extra_oemeson.split()
+        settings_dict["mesonbuild.configureOptions"] = confopts
+        settings_dict["mesonbuild.buildFolder"] = modified_recipe.b
+
+    def __vscodium_settings_cmake(self, settings_dict, modified_recipe):
+        """Add cmake specific settings to settings.json.
+
+        Note: most settings are passed to the cmake preset.
+        """
+        if modified_recipe.build_tool is not BuildTool.CMAKE:
+            return
+        settings_dict["cmake.configureOnOpen"] = True
+        settings_dict["cmake.sourceDirectory"] = modified_recipe.real_srctree
+
+    def vscodium_settings(self, modified_recipe, image_recipe):
+        files_excludes = {
+            "**/.cache/**": True,
+            "**/.git/**": True,
+            "**/oe-logs/**": True,
+            "**/oe-workdir/**": True,
+            "**/source-date-epoch/**": True
+        }
+        python_exclude = [
+            "**/.cache/**",
+            "**/.git/**",
+            "**/oe-logs/**",
+            "**/oe-workdir/**",
+            "**/source-date-epoch/**"
+        ]
+        files_readonly = {
+            modified_recipe.recipe_sysroot + '/**': True,
+            modified_recipe.recipe_sysroot_native + '/**': True,
+        }
+        if image_recipe.rootfs_dbg is not None:
+            files_readonly[image_recipe.rootfs_dbg + '/**'] = True
+        settings_dict = {
+            "files.watcherExclude": files_excludes,
+            "files.exclude": files_excludes,
+            "files.readonlyInclude": files_readonly,
+            "python.analysis.exclude": python_exclude
+        }
+        self.__vscodium_settings_cmake(settings_dict, modified_recipe)
+        self.__vscodium_settings_meson(settings_dict, modified_recipe)
+
+        settings_file = 'settings.json'
+        IdeBase.update_json_file(
+            self.dot_code_dir(modified_recipe), settings_file, settings_dict)
+
+    def __vscodium_extensions_cmake(self, modified_recipe, recommendations):
+        if modified_recipe.build_tool is not BuildTool.CMAKE:
+            return
+        recommendations += [
+            "twxs.cmake",
+            "ms-vscode.cmake-tools",
+            "llvm-vs-code-extensions.vscode-clangd",
+            "webfreak.debug"
+        ]
+
+    def __vscodium_extensions_meson(self, modified_recipe, recommendations):
+        if modified_recipe.build_tool is not BuildTool.MESON:
+            return
+        recommendations += [
+            'mesonbuild.mesonbuild',
+            "llvm-vs-code-extensions.vscode-clangd",
+            "webfreak.debug"
+        ]
+
+    def vscodium_extensions(self, modified_recipe):
+        recommendations = []
+        self.__vscodium_extensions_cmake(modified_recipe, recommendations)
+        self.__vscodium_extensions_meson(modified_recipe, recommendations)
+        extensions_file = 'extensions.json'
+        IdeBase.update_json_file(
+            self.dot_code_dir(modified_recipe), extensions_file, {"recommendations": recommendations})
+
+    def vscodium_c_cpp_properties(self, modified_recipe):
+        properties_dict = {
+            "name": modified_recipe.recipe_id_pretty,
+        }
+        if modified_recipe.build_tool is BuildTool.CMAKE:
+            properties_dict["configurationProvider"] = "ms-vscode.cmake-tools"
+        elif modified_recipe.build_tool is BuildTool.MESON:
+            properties_dict["configurationProvider"] = "mesonbuild.mesonbuild"
+            properties_dict["compilerPath"] = os.path.join(modified_recipe.staging_bindir_toolchain, modified_recipe.cxx.split()[0])
+        else:  # no C/C++ build
+            return
+
+        properties_dicts = {
+            "configurations": [
+                properties_dict
+            ],
+            "version": 4
+        }
+        prop_file = 'c_cpp_properties.json'
+        IdeBase.update_json_file(
+            self.dot_code_dir(modified_recipe), prop_file, properties_dicts)
+
+    def vscodium_launch_bin_dbg(self, gdb_cross_config):
+        modified_recipe = gdb_cross_config.modified_recipe
+
+        launch_config = {
+            "name": gdb_cross_config.id_pretty,
+            "type": "gdb",
+            "request": "attach", # launch -> no executable parameter
+            "executable": os.path.join(modified_recipe.d, gdb_cross_config.binary.lstrip('/')),
+            "stopAtEntry": True,
+            "cwd": "${workspaceFolder}",
+            "preLaunchTask": gdb_cross_config.id_pretty,
+            "gdbpath": modified_recipe.gdb_cross.gdb,
+            "target": "%s:%d" % (modified_recipe.gdb_cross.host, gdb_cross_config.gdbserver_port)
+        }
+
+        # Search for header files in recipe-sysroot.
+        src_file_map = {
+            "/usr/include": os.path.join(modified_recipe.recipe_sysroot, "usr", "include")
+        }
+        # First of all search for not stripped binaries in the image folder.
+        # These binaries are copied (and optionally stripped) by deploy-target
+        setup_commands = [
+            {
+                "description": "sysroot",
+                "text": "set sysroot " + modified_recipe.d
+            }
+        ]
+
+        if gdb_cross_config.image_recipe.rootfs_dbg:
+            launch_config['additionalSOLibSearchPath'] = modified_recipe.solib_search_path_str(
+                gdb_cross_config.image_recipe)
+            # First: Search for sources of this recipe in the workspace folder
+            if modified_recipe.pn in modified_recipe.target_dbgsrc_dir:
+                src_file_map[modified_recipe.target_dbgsrc_dir] = "${workspaceFolder}"
+            else:
+                logger.error(
+                    "TARGET_DBGSRC_DIR must contain the recipe name PN.")
+            # Second: Search for sources of other recipes in the rootfs-dbg
+            if modified_recipe.target_dbgsrc_dir.startswith("/usr/src/debug"):
+                src_file_map["/usr/src/debug"] = os.path.join(
+                    gdb_cross_config.image_recipe.rootfs_dbg, "usr", "src", "debug")
+            else:
+                logger.error(
+                    "TARGET_DBGSRC_DIR must start with /usr/src/debug.")
+        else:
+            logger.warning(
+                "Cannot setup debug symbols configuration for GDB. IMAGE_GEN_DEBUGFS is not enabled.")
+
+        launch_config['sourceFileMap'] = src_file_map
+        launch_config['setupCommands'] = setup_commands
+        return launch_config
+
+    def vscodium_launch(self, modified_recipe):
+        """GDB Launch configuration for binaries (elf files)"""
+
+        configurations = []
+        for gdb_cross_config in self.gdb_cross_configs:
+            if gdb_cross_config.modified_recipe is modified_recipe:
+                configurations.append(self.vscodium_launch_bin_dbg(gdb_cross_config))
+        launch_dict = {
+            "version": "0.2.0",
+            "configurations": configurations
+        }
+        launch_file = 'launch.json'
+        IdeBase.update_json_file(
+            self.dot_code_dir(modified_recipe), launch_file, launch_dict)
+
+    def vscodium_tasks_cpp(self, args, modified_recipe):
+        run_install_deploy = modified_recipe.gen_install_deploy_script(args)
+        install_task_name = "install && deploy-target %s" % modified_recipe.recipe_id_pretty
+        tasks_dict = {
+            "version": "2.0.0",
+            "tasks": [
+                {
+                    "label": install_task_name,
+                    "type": "shell",
+                    "command": run_install_deploy,
+                    "problemMatcher": []
+                }
+            ]
+        }
+        for gdb_cross_config in self.gdb_cross_configs:
+            if gdb_cross_config.modified_recipe is not modified_recipe:
+                continue
+            tasks_dict['tasks'].append(
+                {
+                    "label": gdb_cross_config.id_pretty,
+                    "type": "shell",
+                    "isBackground": True,
+                    "dependsOn": [
+                        install_task_name
+                    ],
+                    "command": gdb_cross_config.gdbserver_script,
+                    "problemMatcher": [
+                        {
+                            "pattern": [
+                                {
+                                    "regexp": ".",
+                                    "file": 1,
+                                    "location": 2,
+                                    "message": 3
+                                }
+                            ],
+                            "background": {
+                                "activeOnStart": True,
+                                "beginsPattern": ".",
+                                "endsPattern": ".",
+                            }
+                        }
+                    ]
+                })
+        tasks_file = 'tasks.json'
+        IdeBase.update_json_file(
+            self.dot_code_dir(modified_recipe), tasks_file, tasks_dict)
+
+    def vscodium_tasks_fallback(self, args, modified_recipe):
+        oe_init_dir = modified_recipe.oe_init_dir
+        oe_init = ". %s %s > /dev/null && " % (modified_recipe.oe_init_build_env, modified_recipe.topdir)
+        #clangd_index = "cd %s &&  " % (modified_recipe.srctree)
+        dt_build = "cd %s && bear devtool build " % (modified_recipe.srctree)
+        dt_build_label = dt_build + modified_recipe.recipe_id_pretty
+        dt_build_cmd = dt_build + modified_recipe.bpn
+        clean_opt = " --clean"
+        dt_build_clean_label = dt_build + modified_recipe.recipe_id_pretty + clean_opt
+        dt_build_clean_cmd = dt_build + modified_recipe.bpn + clean_opt
+        dt_deploy = "devtool deploy-target "
+        dt_deploy_label = dt_deploy + modified_recipe.recipe_id_pretty
+        dt_deploy_cmd = dt_deploy + modified_recipe.bpn
+        dt_build_deploy_label = "bear devtool build & deploy-target %s" % modified_recipe.recipe_id_pretty
+        deploy_opts = ' '.join(get_devtool_deploy_opts(args))
+        tasks_dict = {
+            "version": "2.0.0",
+            "tasks": [
+                {
+                    "label": dt_build_label,
+                    "type": "shell",
+                    "command": "bash",
+                    "linux": {
+                        "options": {
+                            "cwd": oe_init_dir
+                        }
+                    },
+                    "args": [
+                        "--login",
+                        "-c",
+                        "%s%s" % (oe_init, dt_build_cmd)
+                    ],
+                    "problemMatcher": []
+                },
+                {
+                    "label": dt_deploy_label,
+                    "type": "shell",
+                    "command": "bash",
+                    "linux": {
+                        "options": {
+                            "cwd": oe_init_dir
+                        }
+                    },
+                    "args": [
+                        "--login",
+                        "-c",
+                        "%s%s %s" % (
+                            oe_init, dt_deploy_cmd, deploy_opts)
+                    ],
+                    "problemMatcher": []
+                },
+                {
+                    "label": dt_build_deploy_label,
+                    "dependsOrder": "sequence",
+                    "dependsOn": [
+                        dt_build_label,
+                        dt_deploy_label
+                    ],
+                    "problemMatcher": [],
+                    "group": {
+                        "kind": "build",
+                        "isDefault": True
+                    }
+                },
+                {
+                    "label": dt_build_clean_label,
+                    "type": "shell",
+                    "command": "bash",
+                    "linux": {
+                        "options": {
+                            "cwd": oe_init_dir
+                        }
+                    },
+                    "args": [
+                        "--login",
+                        "-c",
+                        "%s%s" % (oe_init, dt_build_clean_cmd)
+                    ],
+                    "problemMatcher": []
+                }
+            ]
+        }
+        if modified_recipe.gdb_cross:
+            for gdb_cross_config in self.gdb_cross_configs:
+                if gdb_cross_config.modified_recipe is not modified_recipe:
+                    continue
+                tasks_dict['tasks'].append(
+                    {
+                        "label": gdb_cross_config.id_pretty,
+                        "type": "shell",
+                        "isBackground": True,
+                        "dependsOn": [
+                            dt_build_deploy_label
+                        ],
+                        "command": gdb_cross_config.gdbserver_script,
+                        "problemMatcher": [
+                            {
+                                "pattern": [
+                                    {
+                                        "regexp": ".",
+                                        "file": 1,
+                                        "location": 2,
+                                        "message": 3
+                                    }
+                                ],
+                                "background": {
+                                    "activeOnStart": True,
+                                    "beginsPattern": ".",
+                                    "endsPattern": ".",
+                                }
+                            }
+                        ]
+                    })
+        tasks_file = 'tasks.json'
+        IdeBase.update_json_file(
+            self.dot_code_dir(modified_recipe), tasks_file, tasks_dict)
+
+    def vscodium_tasks(self, args, modified_recipe):
+        if modified_recipe.build_tool.is_c_ccp:
+            self.vscodium_tasks_cpp(args, modified_recipe)
+        else:
+            self.vscodium_tasks_fallback(args, modified_recipe)
+
+    def setup_modified_recipe(self, args, image_recipe, modified_recipe):
+        self.vscodium_settings(modified_recipe, image_recipe)
+        self.vscodium_extensions(modified_recipe)
+        self.vscodium_c_cpp_properties(modified_recipe)
+        if args.target:
+            self.initialize_gdb_cross_configs(
+                image_recipe, modified_recipe, gdb_cross_config_class=GdbCrossConfigVSCodium)
+            self.vscodium_launch(modified_recipe)
+            self.vscodium_tasks(args, modified_recipe)
+
+
+def register_ide_plugin(ide_plugins):
+    ide_plugins['codium'] = IdeVSCodium
diff --git a/scripts/lib/devtool/ide_sdk.py b/scripts/lib/devtool/ide_sdk.py
index 2f6edde..08da286 100755
--- a/scripts/lib/devtool/ide_sdk.py
+++ b/scripts/lib/devtool/ide_sdk.py
@@ -918,17 +918,30 @@ def ide_setup(args, config, basepath, workspace):
         tinfoil.shutdown()
 
     if not args.skip_bitbake:
-        bb_cmd = 'bitbake '
+        bb_cmd = ""
+        codium_error = False
+        if args.ide == "codium":
+            if len(recipes_modified_names) == 1:
+                bb_cmd += "cd %s && bear " % (recipes_modified[0].srctree)
+            else:
+                logger.error("Multiple recipes detected! VSCodium setup currently only supports one recipe at a time.")
+                codium_error = True
+        bb_cmd += "bitbake "
         if args.bitbake_k:
             bb_cmd += "-k "
         bb_cmd_early = bb_cmd + ' '.join(bootstrap_tasks)
+        if (args.ide == "codium") and (codium_error == False):
+            bb_cmd_early += " && cd -"
         exec_build_env_command(
             config.init_path, basepath, bb_cmd_early, watch=True)
         if bootstrap_tasks_late:
             bb_cmd_late = bb_cmd + ' '.join(bootstrap_tasks_late)
+            if (args.ide == "codium") and (codium_error == False):
+                bb_cmd_early += " && cd -"
             exec_build_env_command(
                 config.init_path, basepath, bb_cmd_late, watch=True)
 
+
     for recipe_image in recipes_images:
         if (recipe_image.gdbserver_missing):
             logger.warning(
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#64205): https://lists.yoctoproject.org/g/yocto/message/64205
Mute This Topic: https://lists.yoctoproject.org/mt/109085158/21656
Mute #github:https://lists.yoctoproject.org/g/yocto/mutehashtag/github
Group Owner: yocto+ow...@lists.yoctoproject.org
Unsubscribe: https://lists.yoctoproject.org/g/yocto/unsub 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to