From 4c894535f9b736a7ce51866558ff088a6bbe694a Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Tue, 26 Aug 2025 20:39:24 -0600 Subject: [PATCH 01/10] git submodule add https://github.com/externpro/externpro .devcontainer --- .devcontainer | 1 + .gitmodules | 3 +++ 2 files changed, 4 insertions(+) create mode 160000 .devcontainer create mode 100644 .gitmodules diff --git a/.devcontainer b/.devcontainer new file mode 160000 index 0000000..98c1aef --- /dev/null +++ b/.devcontainer @@ -0,0 +1 @@ +Subproject commit 98c1aef96d4d4e16c7028b46d99721a6e013c078 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..18932ab --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule ".devcontainer"] + path = .devcontainer + url = https://github.com/externpro/externpro From ba845be374144a531a96b6d4352f5366eb96bb28 Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Tue, 26 Aug 2025 20:40:03 -0600 Subject: [PATCH 02/10] docker-compose links --- docker-compose.sh | 1 + docker-compose.yml | 1 + 2 files changed, 2 insertions(+) create mode 120000 docker-compose.sh create mode 120000 docker-compose.yml diff --git a/docker-compose.sh b/docker-compose.sh new file mode 120000 index 0000000..85f182f --- /dev/null +++ b/docker-compose.sh @@ -0,0 +1 @@ +.devcontainer/compose.pro.sh \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 120000 index 0000000..46c1f89 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1 @@ +.devcontainer/compose.bld.yml \ No newline at end of file From fb7d8d322ca29d79443c6015f4b7e70b0c640843 Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Tue, 26 Aug 2025 20:40:36 -0600 Subject: [PATCH 03/10] cp .devcontainer/cmake/presets/CMakePresets* . --- CMakePresets.json | 8 ++++++++ CMakePresetsBase.json | 10 ++++++++++ 2 files changed, 18 insertions(+) create mode 100644 CMakePresets.json create mode 100644 CMakePresetsBase.json diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..f82cfdd --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,8 @@ +{ + "version": 8, + "include": [ + ".devcontainer/cmake/presets/xpLinuxNinja.json", + ".devcontainer/cmake/presets/xpDarwinNinja.json", + ".devcontainer/cmake/presets/xpWindowsVs2022.json" + ] +} diff --git a/CMakePresetsBase.json b/CMakePresetsBase.json new file mode 100644 index 0000000..09653d8 --- /dev/null +++ b/CMakePresetsBase.json @@ -0,0 +1,10 @@ +{ + "version": 8, + "configurePresets": [ + { + "name": "config-base", + "hidden": true, + "binaryDir": "${sourceDir}/_bld-${presetName}" + } + ] +} From a0ece8818d8513fc6ec74009698b48851abea581 Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Tue, 26 Aug 2025 20:41:49 -0600 Subject: [PATCH 04/10] cp .devcontainer/.github/wf-templates/xp*.yml .github/workflows/ --- .github/workflows/xpbuild.yml | 30 ++++++++++++++++++++++++++++++ .github/workflows/xprelease.yml | 20 ++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 .github/workflows/xpbuild.yml create mode 100644 .github/workflows/xprelease.yml diff --git a/.github/workflows/xpbuild.yml b/.github/workflows/xpbuild.yml new file mode 100644 index 0000000..151d481 --- /dev/null +++ b/.github/workflows/xpbuild.yml @@ -0,0 +1,30 @@ +name: Build +on: + push: + branches: [ "dev" ] + pull_request: + branches: [ "dev" ] + workflow_dispatch: +jobs: + linux: + uses: externpro/externpro/.github/workflows/build-linux.yml@25.05.1 + with: + cmake-workflow-preset: Linux + runon: ubuntu-latest + secrets: inherit + linux-arm64: + uses: externpro/externpro/.github/workflows/build-linux.yml@25.05.1 + with: + cmake-workflow-preset: Linux + runon: ubuntu-24.04-arm + secrets: inherit + macos: + uses: externpro/externpro/.github/workflows/build-macos.yml@25.05.1 + with: + cmake-workflow-preset: Darwin + secrets: inherit + windows: + uses: externpro/externpro/.github/workflows/build-windows.yml@25.05.1 + with: + cmake-workflow-preset: Windows + secrets: inherit diff --git a/.github/workflows/xprelease.yml b/.github/workflows/xprelease.yml new file mode 100644 index 0000000..f868a82 --- /dev/null +++ b/.github/workflows/xprelease.yml @@ -0,0 +1,20 @@ +name: Release +on: + workflow_dispatch: + inputs: + workflow_run_url: + description: 'URL of the workflow run containing artifacts to upload (e.g., https://github.com/owner/repo/actions/runs/123456789)' + required: true + type: string +jobs: + # Upload build artifacts as release assets + release-from-build: + uses: externpro/externpro/.github/workflows/release-from-build.yml@25.05.1 + with: + workflow_run_url: ${{ github.event.inputs.workflow_run_url }} + artifact_pattern: "*.tar.xz" + permissions: + contents: write + id-token: write + attestations: write + secrets: inherit From 63835abfd41738e5ae652f099d8130a2b4960d5d Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Tue, 26 Aug 2025 20:43:41 -0600 Subject: [PATCH 05/10] .gitignore: add externpro ignores --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index da23814..67d1352 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,8 @@ *.exe bzip2 bzip2recover + +# externpro +.env +_bld*/ +docker-compose.override.yml From 188582ceeb0c78fb657f906c80dbadde04e270a1 Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Tue, 26 Aug 2025 20:46:44 -0600 Subject: [PATCH 06/10] copy CMakeLists.txt from github.com/externpro-archive/bzip2 copy of https://github.com/externpro-archive/bzip2/blob/291d5fb5cb1ce090ff3fb4083ffce6b364bdb630/CMakeLists.txt --- CMakeLists.txt | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..89082f1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,72 @@ +cmake_minimum_required(VERSION 3.20) +project(bzip2 C) +include(GNUInstallDirs) +include(flags OPTIONAL) +set(lib_name bz2) +######################################## +add_definitions(-D_FILE_OFFEST_BITS=64) +######################################## +set(${lib_name}_libsrcs + blocksort.c + huffman.c + crctable.c + randtable.c + compress.c + decompress.c + bzlib.c + bzlib.h + bzlib_private.h + ) +######################################## +add_library(${lib_name} STATIC ${${lib_name}_libsrcs}) +target_include_directories(${lib_name} PUBLIC $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ) +######################################## +add_executable(bzip2 bzip2.c) +target_link_libraries(bzip2 ${lib_name}) +set_target_properties(bzip2 PROPERTIES DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}") +######################################## +add_executable(bzip2recover bzip2recover.c) +set_target_properties(bzip2recover PROPERTIES DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}") +######################################## +set(srcDir ${CMAKE_CURRENT_SOURCE_DIR}) +set(binDir ${CMAKE_CURRENT_BINARY_DIR}) +file(READ words1 words1) +add_custom_target(check ALL COMMENT ${words1} + COMMAND $ -1 < ${srcDir}/sample1.ref > ${binDir}/sample1.rb2 + COMMAND $ -2 < ${srcDir}/sample2.ref > ${binDir}/sample2.rb2 + COMMAND $ -3 < ${srcDir}/sample3.ref > ${binDir}/sample3.rb2 + COMMAND $ -d < ${srcDir}/sample1.bz2 > ${binDir}/sample1.tst + COMMAND $ -d < ${srcDir}/sample2.bz2 > ${binDir}/sample2.tst + COMMAND $ -ds < ${srcDir}/sample3.bz2 > ${binDir}/sample3.tst + COMMAND ${CMAKE_COMMAND} -E compare_files ${srcDir}/sample1.bz2 ${binDir}/sample1.rb2 + COMMAND ${CMAKE_COMMAND} -E compare_files ${srcDir}/sample2.bz2 ${binDir}/sample2.rb2 + COMMAND ${CMAKE_COMMAND} -E compare_files ${srcDir}/sample3.bz2 ${binDir}/sample3.rb2 + COMMAND ${CMAKE_COMMAND} -E compare_files ${binDir}/sample1.tst ${srcDir}/sample1.ref + COMMAND ${CMAKE_COMMAND} -E compare_files ${binDir}/sample2.tst ${srcDir}/sample2.ref + COMMAND ${CMAKE_COMMAND} -E compare_files ${binDir}/sample3.tst ${srcDir}/sample3.ref + ) +######################################## +set(targetsFile ${PROJECT_NAME}-targets) +install(TARGETS ${lib_name} EXPORT ${targetsFile} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) +install(TARGETS bzip2 bzip2recover EXPORT ${targetsFile} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + CONFIGURATIONS Release + ) +install(PROGRAMS $ DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Release RENAME bunzip2${CMAKE_EXECUTABLE_SUFFIX}) +install(PROGRAMS $ DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Release RENAME bzcat${CMAKE_EXECUTABLE_SUFFIX}) +install(FILES bzlib.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) +if(DEFINED XP_NAMESPACE) + set(nameSpace NAMESPACE ${XP_NAMESPACE}::) +endif() +if(NOT DEFINED XP_INSTALL_CMAKEDIR) + set(XP_INSTALL_CMAKEDIR ${CMAKE_INSTALL_DATADIR}/cmake) +endif() +install(EXPORT ${targetsFile} DESTINATION ${XP_INSTALL_CMAKEDIR} ${nameSpace}) From a550bc88cba101d56c89f97176e55e8a15fd2031 Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Wed, 27 Aug 2025 11:06:55 -0600 Subject: [PATCH 07/10] externpro devel package --- CMakeLists.txt | 15 ++++++++++++--- CMakePresetsBase.json | 6 +++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89082f1..bc5b6cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,9 @@ -cmake_minimum_required(VERSION 3.20) -project(bzip2 C) +cmake_minimum_required(VERSION 3.31) +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/.devcontainer/cmake) +set(CMAKE_PROJECT_TOP_LEVEL_INCLUDES xproinc) +project(bzip2 VERSION 1.0.8 LANGUAGES C) +include(flags) include(GNUInstallDirs) -include(flags OPTIONAL) set(lib_name bz2) ######################################## add_definitions(-D_FILE_OFFEST_BITS=64) @@ -49,6 +51,13 @@ add_custom_target(check ALL COMMENT ${words1} ) ######################################## set(targetsFile ${PROJECT_NAME}-targets) +set(exe bzip2) +set(lib ${lib_name}) +if(DEFINED XP_NAMESPACE) + string(PREPEND exe "${XP_NAMESPACE}::") + string(PREPEND lib "${XP_NAMESPACE}::") +endif() +xpPackageDevel(TARGETS_FILE ${targetsFile} LIBRARIES ${lib} EXE ${exe}) install(TARGETS ${lib_name} EXPORT ${targetsFile} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/CMakePresetsBase.json b/CMakePresetsBase.json index 09653d8..5aa0fca 100644 --- a/CMakePresetsBase.json +++ b/CMakePresetsBase.json @@ -4,7 +4,11 @@ { "name": "config-base", "hidden": true, - "binaryDir": "${sourceDir}/_bld-${presetName}" + "binaryDir": "${sourceDir}/_bld-${presetName}", + "cacheVariables": { + "XP_INSTALL_CMAKEDIR": "share/cmake", + "XP_NAMESPACE": "xpro" + } } ] } From 09e655e883991778ff500344448bbe1500e57ab1 Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Wed, 27 Aug 2025 11:08:46 -0600 Subject: [PATCH 08/10] test: convert custom_target into ctest --- CMakeLists.txt | 24 ++++++++---------------- run_bzip2_test.cmake | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 run_bzip2_test.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index bc5b6cd..c4dcb47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,22 +32,14 @@ set_target_properties(bzip2 PROPERTIES DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}") add_executable(bzip2recover bzip2recover.c) set_target_properties(bzip2recover PROPERTIES DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}") ######################################## -set(srcDir ${CMAKE_CURRENT_SOURCE_DIR}) -set(binDir ${CMAKE_CURRENT_BINARY_DIR}) -file(READ words1 words1) -add_custom_target(check ALL COMMENT ${words1} - COMMAND $ -1 < ${srcDir}/sample1.ref > ${binDir}/sample1.rb2 - COMMAND $ -2 < ${srcDir}/sample2.ref > ${binDir}/sample2.rb2 - COMMAND $ -3 < ${srcDir}/sample3.ref > ${binDir}/sample3.rb2 - COMMAND $ -d < ${srcDir}/sample1.bz2 > ${binDir}/sample1.tst - COMMAND $ -d < ${srcDir}/sample2.bz2 > ${binDir}/sample2.tst - COMMAND $ -ds < ${srcDir}/sample3.bz2 > ${binDir}/sample3.tst - COMMAND ${CMAKE_COMMAND} -E compare_files ${srcDir}/sample1.bz2 ${binDir}/sample1.rb2 - COMMAND ${CMAKE_COMMAND} -E compare_files ${srcDir}/sample2.bz2 ${binDir}/sample2.rb2 - COMMAND ${CMAKE_COMMAND} -E compare_files ${srcDir}/sample3.bz2 ${binDir}/sample3.rb2 - COMMAND ${CMAKE_COMMAND} -E compare_files ${binDir}/sample1.tst ${srcDir}/sample1.ref - COMMAND ${CMAKE_COMMAND} -E compare_files ${binDir}/sample2.tst ${srcDir}/sample2.ref - COMMAND ${CMAKE_COMMAND} -E compare_files ${binDir}/sample3.tst ${srcDir}/sample3.ref +include(CTest) +add_test(NAME bzip2_check + COMMAND ${CMAKE_COMMAND} + -DCMD=$ + -DSRC_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -DBIN_DIR=${CMAKE_CURRENT_BINARY_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/run_bzip2_test.cmake + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) ######################################## set(targetsFile ${PROJECT_NAME}-targets) diff --git a/run_bzip2_test.cmake b/run_bzip2_test.cmake new file mode 100644 index 0000000..f3421ef --- /dev/null +++ b/run_bzip2_test.cmake @@ -0,0 +1,28 @@ +set(commands + # Compress sample files + "${CMD} -1 < ${SRC_DIR}/sample1.ref > ${BIN_DIR}/sample1.rb2" + "${CMD} -2 < ${SRC_DIR}/sample2.ref > ${BIN_DIR}/sample2.rb2" + "${CMD} -3 < ${SRC_DIR}/sample3.ref > ${BIN_DIR}/sample3.rb2" + # Decompress sample files + "${CMD} -d < ${SRC_DIR}/sample1.bz2 > ${BIN_DIR}/sample1.tst" + "${CMD} -d < ${SRC_DIR}/sample2.bz2 > ${BIN_DIR}/sample2.tst" + "${CMD} -ds < ${SRC_DIR}/sample3.bz2 > ${BIN_DIR}/sample3.tst" + # Verify compressed files + "${CMAKE_COMMAND} -E compare_files ${SRC_DIR}/sample1.bz2 ${BIN_DIR}/sample1.rb2" + "${CMAKE_COMMAND} -E compare_files ${SRC_DIR}/sample2.bz2 ${BIN_DIR}/sample2.rb2" + "${CMAKE_COMMAND} -E compare_files ${SRC_DIR}/sample3.bz2 ${BIN_DIR}/sample3.rb2" + # Verify decompressed files + "${CMAKE_COMMAND} -E compare_files ${BIN_DIR}/sample1.tst ${SRC_DIR}/sample1.ref" + "${CMAKE_COMMAND} -E compare_files ${BIN_DIR}/sample2.tst ${SRC_DIR}/sample2.ref" + "${CMAKE_COMMAND} -E compare_files ${BIN_DIR}/sample3.tst ${SRC_DIR}/sample3.ref" + ) +# Execute each command +foreach(cmd IN LISTS commands) + execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "Running: ${cmd}" + COMMAND bash -c "${cmd}" RESULT_VARIABLE result + ) + if(NOT result EQUAL 0) + message(FATAL_ERROR "Command failed: ${cmd}\nExit code: ${result}") + endif() +endforeach() From 49b68e09b189c9dff1b9919245966d421ea66bad Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Wed, 27 Aug 2025 11:10:02 -0600 Subject: [PATCH 09/10] compiler warning [-Wformat] * length modifier 'L' results in undefined behavior or no effect with 'u' conversion specifier [-Wformat] * format specifier %Lu for unsigned long long is not portable and is causing warnings * update the format specifier to %llu for GCC, which is the correct format for unsigned long long * this change ensures proper formatting of 64-bit unsigned integers and resolves the compiler warnings * the fix is more portable and follows standard C practices for unsigned long long types --- bzip2recover.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bzip2recover.c b/bzip2recover.c index a8131e0..136c72a 100644 --- a/bzip2recover.c +++ b/bzip2recover.c @@ -37,7 +37,7 @@ */ #ifdef __GNUC__ typedef unsigned long long int MaybeUInt64; -# define MaybeUInt64_FMT "%Lu" +# define MaybeUInt64_FMT "%llu" #else #ifdef _MSC_VER typedef unsigned __int64 MaybeUInt64; From 2a5de9be5a45565a545cd677ef506a1efe863f55 Mon Sep 17 00:00:00 2001 From: Scott M Anderson Date: Wed, 27 Aug 2025 11:42:22 -0600 Subject: [PATCH 10/10] run_bzip2_test: handle paths with spaces --- run_bzip2_test.cmake | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/run_bzip2_test.cmake b/run_bzip2_test.cmake index f3421ef..0ffb6b9 100644 --- a/run_bzip2_test.cmake +++ b/run_bzip2_test.cmake @@ -1,22 +1,21 @@ set(commands # Compress sample files - "${CMD} -1 < ${SRC_DIR}/sample1.ref > ${BIN_DIR}/sample1.rb2" - "${CMD} -2 < ${SRC_DIR}/sample2.ref > ${BIN_DIR}/sample2.rb2" - "${CMD} -3 < ${SRC_DIR}/sample3.ref > ${BIN_DIR}/sample3.rb2" + "'${CMD}' -1 < '${SRC_DIR}/sample1.ref' > '${BIN_DIR}/sample1.rb2'" + "'${CMD}' -2 < '${SRC_DIR}/sample2.ref' > '${BIN_DIR}/sample2.rb2'" + "'${CMD}' -3 < '${SRC_DIR}/sample3.ref' > '${BIN_DIR}/sample3.rb2'" # Decompress sample files - "${CMD} -d < ${SRC_DIR}/sample1.bz2 > ${BIN_DIR}/sample1.tst" - "${CMD} -d < ${SRC_DIR}/sample2.bz2 > ${BIN_DIR}/sample2.tst" - "${CMD} -ds < ${SRC_DIR}/sample3.bz2 > ${BIN_DIR}/sample3.tst" + "'${CMD}' -d < '${SRC_DIR}/sample1.bz2' > '${BIN_DIR}/sample1.tst'" + "'${CMD}' -d < '${SRC_DIR}/sample2.bz2' > '${BIN_DIR}/sample2.tst'" + "'${CMD}' -ds < '${SRC_DIR}/sample3.bz2' > '${BIN_DIR}/sample3.tst'" # Verify compressed files - "${CMAKE_COMMAND} -E compare_files ${SRC_DIR}/sample1.bz2 ${BIN_DIR}/sample1.rb2" - "${CMAKE_COMMAND} -E compare_files ${SRC_DIR}/sample2.bz2 ${BIN_DIR}/sample2.rb2" - "${CMAKE_COMMAND} -E compare_files ${SRC_DIR}/sample3.bz2 ${BIN_DIR}/sample3.rb2" + "'${CMAKE_COMMAND}' -E compare_files '${SRC_DIR}/sample1.bz2' '${BIN_DIR}/sample1.rb2'" + "'${CMAKE_COMMAND}' -E compare_files '${SRC_DIR}/sample2.bz2' '${BIN_DIR}/sample2.rb2'" + "'${CMAKE_COMMAND}' -E compare_files '${SRC_DIR}/sample3.bz2' '${BIN_DIR}/sample3.rb2'" # Verify decompressed files - "${CMAKE_COMMAND} -E compare_files ${BIN_DIR}/sample1.tst ${SRC_DIR}/sample1.ref" - "${CMAKE_COMMAND} -E compare_files ${BIN_DIR}/sample2.tst ${SRC_DIR}/sample2.ref" - "${CMAKE_COMMAND} -E compare_files ${BIN_DIR}/sample3.tst ${SRC_DIR}/sample3.ref" + "'${CMAKE_COMMAND}' -E compare_files '${BIN_DIR}/sample1.tst' '${SRC_DIR}/sample1.ref'" + "'${CMAKE_COMMAND}' -E compare_files '${BIN_DIR}/sample2.tst' '${SRC_DIR}/sample2.ref'" + "'${CMAKE_COMMAND}' -E compare_files '${BIN_DIR}/sample3.tst' '${SRC_DIR}/sample3.ref'" ) -# Execute each command foreach(cmd IN LISTS commands) execute_process( COMMAND ${CMAKE_COMMAND} -E echo "Running: ${cmd}"