Prefixing variables to prevent shadowing. Fixes: #3370 (#3585)

This commit is contained in:
M Starch 2025-05-09 17:02:37 -07:00 committed by GitHub
parent d1f7f1155e
commit 6e812a9e8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 36 additions and 250 deletions

View File

@ -1,27 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "C/C++: g++ build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build-fprime-automatic-native-ut/bin/Linux/Svc_DpCatalog_ut_exe",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": ""
},
]
}

View File

@ -7,7 +7,7 @@ include(utilities)
include(autocoder/helpers)
include(autocoder/ai-shared)
set(PACKETS_AUTOCODER_SCRIPT "${FPRIME_FRAMEWORK_PATH}/Autocoders/Python/bin/tlm_packet_gen.py")
set(FPRIME__INTERNAL_PACKETS_AUTOCODER_SCRIPT "${FPRIME_FRAMEWORK_PATH}/Autocoders/Python/bin/tlm_packet_gen.py")
autocoder_setup_for_individual_sources()
####
@ -58,7 +58,7 @@ function(packets_setup_autocode MODULE_NAME AC_INPUT_FILE)
COMMAND
PYTHONPATH=${PYTHON_AUTOCODER_DIR}/src:${PYTHON_AUTOCODER_DIR}/utils
BUILD_ROOT=${FPRIME_BUILD_LOCATIONS_SEP}:${CMAKE_BINARY_DIR_RESOLVED}:${CMAKE_BINARY_DIR_RESOLVED}/F-Prime
"${PYTHON}" "${PACKETS_AUTOCODER_SCRIPT}" "${AC_INPUT_FILE}"
"${PYTHON}" "${FPRIME__INTERNAL_PACKETS_AUTOCODER_SCRIPT}" "${AC_INPUT_FILE}"
DEPENDS "${AC_INPUT_FILE}" "${FULL_TOPOLOGY_FILE}"
)
set(AUTOCODER_GENERATED "${GENERATED_FILES}" PARENT_SCOPE)

View File

@ -1,66 +0,0 @@
####
# Module 'CMakeLists.txt':
#
# fprime modules setup source files, non-standard module dependencies, unit test source files, unit test module
# dependencies, and call one of the following functions from the F prime API:
#
# First define needed variables:
#
# - `SOURCE_FILES:` combined list of source and autocoding files. Used by `register_fprime_module` and
# `register_fprime_executable` to provide source files.
# - `MOD_DEPS:` (optional) module dependencies that cannot be auto-detected. Used by `register_fprime_module` and
# `register_fprime_executable`.
# - `EXECUTABLE_NAME`: (optional) override default executable name. Used by `register_fprime_executable`
# - `UT_SOURCE_FILES`: (optional) specify sources for unit tests used with `register_fprime_ut`
# - `UT_MOD_DEPS`: (optional) specify modules for unit tests used with `register_fprime_ut`
#
# Once set, register fprime modules using:
# - `register_fprime_module`: register a typical module/library
# - `register_fprime_executable`: register an executable/deployment binary
# - `register_fprime_ut`: register a unit test
#
#
# See: [API](./API.md)
#
# **Example:**
# ```
# # Setup source files
# set(SOURCE_FILES
# "${CMAKE_CURRENT_LIST_DIR}/CommandDispatcherComponentAi.xml"
# "${CMAKE_CURRENT_LIST_DIR}/CommandDispatcherImpl.cpp"
# )
#
# # Register the fprime module using above sources
# register_fprime_module()
#
# # Setup unit test source files
# set(UT_SOURCE_FILES
# "${FPRIME_FRAMEWORK_PATH}/Svc/CmdDispatcher/CommandDispatcherComponentAi.xml"
# "${CMAKE_CURRENT_LIST_DIR}/test/ut/CommandDispatcherTester.cpp"
# "${CMAKE_CURRENT_LIST_DIR}/test/ut/CommandDispatcherImplTester.cpp"
# )
# # Register a unit test with above sources
# register_fprime_ut()
# ```
####
# Step 1: fill in source files. Autocoding XML files go here.
set(SOURCE_FILES
...
)
# Step 2: (optional) fill in non-standard module dependencies here.
set(MOD_DEPS
...
)
# Step 3: call `register_fprime_module` or `register_fprime_executable`
register_fprime_module()
# Step 4: (optional) set UT files
set(UT_SOURCE_FILES
...
)
# Step 5: (optional) set UT dependencies
set(UT_MOD_DEPS
...
)
# Step 6: (optional) register fprime UT
register_fprime_ut()

View File

@ -1,2 +0,0 @@
project(profiler C)
add_executable(profiler "${CMAKE_CURRENT_LIST_DIR}/profile.c")

View File

@ -1,20 +0,0 @@
#include <sys/time.h>
#include <stdio.h>
int main(int argc, char** argv) {
struct timeval val;
gettimeofday(&val, 0);
FILE* pointer = stdout;
if (argc > 1)
{
pointer = fopen(argv[1], "a");
}
fprintf(pointer, "%ld.%06d", val.tv_sec, val.tv_usec);
for (int i = 2; i < argc; i++)
{
fprintf(pointer, " %s", argv[i]);
}
fprintf(pointer, "\n");
}

View File

@ -1,46 +0,0 @@
option(FPRIME_PROFILE_CMAKE "Enable profiling of the CMake system." ${CMAKE_DEBUG_OUTPUT})
set(PROFILER_OUTPUT "${CMAKE_BINARY_DIR}/fp_profiling")
set(PROFILER_SETUP_DIR "${CMAKE_BINARY_DIR}/profiler-tooling")
function(setup_profiling)
make_directory(${PROFILER_SETUP_DIR})
file(REMOVE "${PROFILER_OUTPUT}")
find_program(PROFILER profiler PATHS ${PROFILER_SETUP_DIR})
if (NOT FPRIME_PROFILE_CMAKE OR PROFILER)
return()
endif()
message(STATUS "[profiler] Building the profiler C application")
execute_process(
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" ${CMAKE_CURRENT_LIST_DIR}
RESULT_VARIABLE result
WORKING_DIRECTORY ${PROFILER_SETUP_DIR}
OUTPUT_QUIET
ERROR_VARIABLE ERROR_OUT
)
if(result)
message(FATAL_ERROR "[profiler] configure step failed: ${result}\n${ERROR_OUT}")
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${PROFILER_SETUP_DIR}
OUTPUT_QUIET
ERROR_VARIABLE ERROR_OUT
)
if(result)
message(FATAL_ERROR "[profiler] build step failed: ${result}\n${ERROR_OUT}")
endif()
find_program(PROFILER profiler PATHS ${PROFILER_SETUP_DIR})
endfunction(setup_profiling)
setup_profiling() # Set-up profiling at the beginning
function(fp_profile STAGE TOKEN ANNOTATION)
if (NOT FPRIME_PROFILE_CMAKE)
return()
endif()
find_program(PROFILER profiler PATHS ${PROFILER_SETUP_DIR})
execute_process(COMMAND ${PROFILER} "${PROFILER_OUTPUT}" "${STAGE}" "${TOKEN}" "${ANNOTATION}")
endfunction(fp_profile)

View File

@ -1,53 +0,0 @@
import random
MEMBER_SIZES = 3
with open("fp_profiling", "r") as fh:
lines = [line.strip().split() for line in fh.readlines()]
totals = {}
lasts = {}
for stamp, stage, token, module in lines:
stamp = float(stamp)
if token not in totals:
totals[token] = (0, 0, 9999999999, 0, [])
if stage == "START":
lasts[token] = stamp
elif stage == "STOP":
accum, count, min_delta, max_delta, hits = totals[token]
delta = stamp - lasts[token]
totals[token] = (
accum + delta,
count + 1,
min(delta, min_delta),
max(delta, max_delta),
hits + [(delta, module)],
)
for token, pair in totals.items():
accum, count, min_delta, max_delta, hits = totals[token]
if count == 0:
continue
print(
"{} {:.6f} ({:.6f}, {:.6f}, {:.6f}) {}".format(
token, accum, min_delta, accum / count, max_delta, hits[int(count / 2)][0]
)
)
hist = {index: (0, []) for index in range(0, 1000)}
for item, module in hits:
index = int(int(item * 1000) / 10) * 10
if index not in hist:
hist[index] = (0, [])
hist[index] = (hist[index][0] + 1, hist[index][1] + [module])
for index, pair in hist.items():
count, members = pair
random.shuffle(members)
if count != 0:
print(
" {:3} ms: {:4} -- {}".format(
index,
count,
" ".join(members[:MEMBER_SIZES])
+ ("" if len(members) <= MEMBER_SIZES else " ..."),
)
)

View File

@ -13,20 +13,20 @@ find_program(FPUTIL NAMES fprime-util)
locate_fpp_tools()
set(FRAGMENT "pip install -r \"${FPRIME_FRAMEWORK_PATH}/requirements.txt\"")
set(TO_INSTALL_MESSAGE "Install with:\n '${FRAGMENT}'")
set(TO_REINSTALL "Reinstall with:\n '${FRAGMENT} -U --force-reinstall'")
set(FPRIME__INTERNAL_FRAGMENT "pip install -r \"${FPRIME_FRAMEWORK_PATH}/requirements.txt\"")
set(FPRIME__INTERNAL_TO_INSTALL_MESSAGE "Install with:\n '${FRAGMENT}'")
set(FPRIME__INTERNAL_TO_REINSTALL "Reinstall with:\n '${FRAGMENT} -U --force-reinstall'")
# Check python was found
if (NOT FPUTIL)
message(FATAL_ERROR " fprime-util was not found. ${TO_INSTALL_MESSAGE}")
message(FATAL_ERROR " fprime-util was not found. ${FPRIME__INTERNAL_TO_INSTALL_MESSAGE}")
elseif (NOT PYTHON)
message(FATAL_ERROR " python3 was not found. Please see: https://www.python.org/downloads/")
elseif (DEFINED FPP_ERROR_MESSAGE)
message(FATAL_ERROR " ${FPP_ERROR_MESSAGE}")
elseif (DEFINED FPP_REINSTALL_ERROR_MESSAGE)
message(FATAL_ERROR " ${FPP_REINSTALL_ERROR_MESSAGE}. ${TO_REINSTALL}")
message(FATAL_ERROR " ${FPP_REINSTALL_ERROR_MESSAGE}. ${FPRIME__INTERNAL_TO_REINSTALL}")
elseif(NOT FPP_FOUND)
message(FATAL_ERROR " fpp tools not found. ${TO_INSTALL_MESSAGE}")
message(FATAL_ERROR " fpp tools not found. ${FPRIME__INTERNAL_TO_INSTALL_MESSAGE}")
endif()

View File

@ -8,7 +8,7 @@
include_guard()
# Necessary global variables
set(SETTINGS_CMAKE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}")
set(FPRIME__INTERNAL_SETTINGS_CMAKE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}")
find_program(PYTHON NAMES python3 python) #This happens before required
####
@ -40,7 +40,7 @@ function(ini_to_cache)
endif()
# Execute the process
execute_process(COMMAND ${PYTHON}
"${SETTINGS_CMAKE_DIRECTORY}/ini-to-stdio.py"
"${FPRIME__INTERNAL_SETTINGS_CMAKE_DIRECTORY}/ini-to-stdio.py"
"${CALCULATED_INI}"
${CMAKE_TOOLCHAIN_FILE}
OUTPUT_VARIABLE INI_OUTPUT

View File

@ -7,13 +7,13 @@
include_guard()
# List of types of variables that are excluded from the list passed to sub-builds.
set(TYPES_DISALLOWED_LIST
set(FPRIME_SUB_BUILD_TYPES_DISALLOWED_LIST
INTERNAL
STATIC
)
# List of cache variables that shall be excluded from the list passed to sub-builds.
set(SUB_BUILD_EXCLUDED_CACHE_VARIABLES
set(FPRIME_SUB_BUILD_EXCLUDED_CACHE_VARIABLES
CMAKE_EDIT_COMMAND
CMAKE_HOME_DIRECTORY
CMAKE_INSTALL_NAME_TOOL

View File

@ -88,13 +88,13 @@ function(_get_call_properties)
foreach (PROPERTY IN LISTS CACHE_VARS)
get_property(CACHE_TYPE CACHE "${PROPERTY}" PROPERTY TYPE)
# Exclude listed properties and empty properties
if ("${PROPERTY}" IN_LIST SUB_BUILD_EXCLUDED_CACHE_VARIABLES)
if ("${PROPERTY}" IN_LIST FPRIME_SUB_BUILD_EXCLUDED_CACHE_VARIABLES)
continue()
# Exclude empty values
elseif("${${PROPERTY}}" STREQUAL "")
continue()
# Exclude internal cache values
elseif("${CACHE_TYPE}" IN_LIST TYPES_DISALLOWED_LIST)
elseif("${CACHE_TYPE}" IN_LIST FPRIME_SUB_BUILD_TYPES_DISALLOWED_LIST)
continue()
endif()
# Add escaping for list type variables (for pass to function call and then again to another function call)

View File

@ -5,7 +5,7 @@
# sub-build that generates cached-information about the build itself.
####
include_guard()
set(FPP_LOCATE_DEFS_HELPER "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/tools/redirector.py")
set(FPP__INTERNAL_LOCATE_DEFS_HELPER "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/tools/redirector.py")
####
# Function `fpp_depend_add_global_target`:
#
@ -61,7 +61,7 @@ function(fpp_depend_add_module_target MODULE TARGET SOURCES_UNUSED DEPENDENCIES)
)
add_custom_command(
OUTPUT ${OUTPUT_FILES}
COMMAND ${FPP_LOCATE_DEFS_HELPER}
COMMAND ${FPP__INTERNAL_LOCATE_DEFS_HELPER}
"${LOCAL_CACHE}/stdout.txt"
"${FPP_DEPEND}"
"${FPRIME_BINARY_DIR}/locs.fpp"

View File

@ -9,7 +9,7 @@
# fpp_locs_add_module_target: used to identify all source files to pass to location global target
####
include_guard()
set(FPP_LOCATE_DEFS_HELPER "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/tools/redirector.py")
set(FPP__INTERNAL_LOCATE_DEFS_HELPER "${PYTHON}" "${CMAKE_CURRENT_LIST_DIR}/tools/redirector.py")
####
# Function `fpp_locs_add_global_target`:
@ -23,7 +23,7 @@ function(fpp_locs_add_global_target TARGET)
add_custom_command(
OUTPUT "${CMAKE_BINARY_DIR}/locs.fpp"
COMMAND
"${FPP_LOCATE_DEFS_HELPER}"
"${FPP__INTERNAL_LOCATE_DEFS_HELPER}"
"${CMAKE_BINARY_DIR}/locs.fpp"
"${FPP_LOCATE_DEFS}"
-d "${FPRIME_BINARY_DIR}"

View File

@ -4,7 +4,7 @@
# A target used to add SBOM generation to the build. Will be invoked when running the "all" target
# and installed into the build_artifacts directory underneath the platform folder.
####
set(REDIRECTOR "${CMAKE_CURRENT_LIST_DIR}/tools/redirector.py")
set(FPRIME__INTERNAL_SBOM_REDIRECTOR "${CMAKE_CURRENT_LIST_DIR}/tools/redirector.py")
####
# sbom_add_global_target:
@ -19,7 +19,7 @@ function(sbom_add_global_target TARGET)
add_custom_target("${TARGET}" ALL
COMMAND
# Redirect to cleanly capture standard out
${PYTHON} ${REDIRECTOR} "${CMAKE_BINARY_DIR}/${PROJECT_NAME}_sbom.json"
${PYTHON} ${FPRIME__INTERNAL_SBOM_REDIRECTOR} "${CMAKE_BINARY_DIR}/${PROJECT_NAME}_sbom.json"
# syft arguments
"${SYFT}" "dir:${FPRIME_PROJECT_ROOT}" -o spdx-json
# Excludes .github paths not in the root of the project as those should not be activated by the project

View File

@ -5,7 +5,7 @@
####
include(target/build) # Borrows some implementation
set(FPRIME__INTERNAL_UT_TARGET "ut_exe") # For historical reasons
set(UT_CLEAN_SCRIPT "${CMAKE_BINARY_DIR}/clean.cmake")
set(FPRIME__INTERNAL_UT_CLEAN_SCRIPT "${CMAKE_BINARY_DIR}/clean.cmake")
####
@ -16,14 +16,14 @@ set(UT_CLEAN_SCRIPT "${CMAKE_BINARY_DIR}/clean.cmake")
####
function(_ut_setup_clean_file)
set(REMOVAL_GLOB "*.gcda")
file(WRITE "${UT_CLEAN_SCRIPT}" "
file(WRITE "${FPRIME__INTERNAL_UT_CLEAN_SCRIPT}" "
file(GLOB_RECURSE GCDA_FILES \"${CMAKE_BINARY_DIR}/**/${REMOVAL_GLOB}\")
if (GCDA_FILES)
file(REMOVE \${GCDA_FILES})
endif()
")
set_property(DIRECTORY APPEND PROPERTY
TEST_INCLUDE_FILES "${UT_CLEAN_SCRIPT}"
TEST_INCLUDE_FILES "${FPRIME__INTERNAL_UT_CLEAN_SCRIPT}"
)
endfunction(_ut_setup_clean_file)
@ -55,7 +55,7 @@ function(ut_add_deployment_target MODULE TARGET SOURCES DEPENDENCIES FULL_DEPEND
return()
endif()
set_property(DIRECTORY APPEND PROPERTY
TEST_INCLUDE_FILES "${UT_CLEAN_SCRIPT}"
TEST_INCLUDE_FILES "${FPRIME__INTERNAL_UT_CLEAN_SCRIPT}"
)
add_custom_target("${MODULE}_${FPRIME__INTERNAL_UT_TARGET}")
foreach(DEPENDENCY IN LISTS FULL_DEPENDENCIES)
@ -112,7 +112,7 @@ function(ut_add_module_target MODULE_NAME TARGET_NAME SOURCE_FILES DEPENDENCIES)
set(UT_MODULE_TARGET "${FPRIME_CURRENT_MODULE}_${FPRIME__INTERNAL_UT_TARGET}")
message(STATUS "Adding Unit Test: ${UT_EXECUTABLE_TARGET}")
set_property(DIRECTORY APPEND PROPERTY
TEST_INCLUDE_FILES "${UT_CLEAN_SCRIPT}"
TEST_INCLUDE_FILES "${FPRIME__INTERNAL_UT_CLEAN_SCRIPT}"
)
run_ac_set("${UT_EXECUTABLE_TARGET}" autocoder/fpp autocoder/fpp_ut)

View File

@ -3,7 +3,7 @@
#
# A basic versioning target which will produce the version files.
####
set(FPRIME_VERSION_INFO_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/version/generate_version_info.py")
set(FPRIME__INTERNAL_VERSION_INFO_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/version/generate_version_info.py")
function(version_add_global_target TARGET)
set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/versions")
@ -23,7 +23,7 @@ function(version_add_global_target TARGET)
"FPRIME_PROJECT_ROOT=${FPRIME_PROJECT_ROOT}"
"FPRIME_FRAMEWORK_PATH=${FPRIME_FRAMEWORK_PATH}"
"FPRIME_LIBRARY_LOCATIONS=${FPRIME_LIBRARY_LOCATIONS_CSV}"
"${FPRIME_VERSION_INFO_SCRIPT}" "${OUTPUT_DIR}" "${OPTIONAL_CHECK_ARG}"
"${FPRIME__INTERNAL_VERSION_INFO_SCRIPT}" "${OUTPUT_DIR}" "${OPTIONAL_CHECK_ARG}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${OUTPUT_HPP}.tmp" "${OUTPUT_HPP}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${OUTPUT_CPP}.tmp" "${OUTPUT_CPP}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${OUTPUT_JSON}.tmp" "${OUTPUT_JSON}"

View File

@ -12,16 +12,16 @@ set(FPRIME_PLATFORM Linux)
set(CMAKE_SYSTEM_VERSION 0.2)
# Check ARM tools path
set(FIND_INPUTS PATHS ENV ARM_TOOLS_PATH PATH_SUFFIXES bin REQUIRED)
set(PREFIX_1 "${CMAKE_SYSTEM_PROCESSOR}-linux-gnu${ARM_TOOL_SUFFIX}")
set(PREFIX_2 "${CMAKE_SYSTEM_PROCESSOR}-none-linux-gnu${ARM_TOOL_SUFFIX}")
set(FPRIME__INTERNAL_FIND_INPUTS PATHS ENV ARM_TOOLS_PATH PATH_SUFFIXES bin REQUIRED)
set(FPRIME__INTERNAL_PREFIX_1 "${CMAKE_SYSTEM_PROCESSOR}-linux-gnu${ARM_TOOL_SUFFIX}")
set(FPRIME__INTERNAL_PREFIX_2 "${CMAKE_SYSTEM_PROCESSOR}-none-linux-gnu${ARM_TOOL_SUFFIX}")
# Set the GNU ARM toolchain
find_program(CMAKE_ASM_COMPILER NAMES ${PREFIX_1}-as ${PREFIX_2}-as ${FIND_INPUTS})
find_program(CMAKE_C_COMPILER NAMES ${PREFIX_1}-gcc ${PREFIX_2}-gcc ${FIND_INPUTS})
find_program(CMAKE_CXX_COMPILER NAMES ${PREFIX_1}-g++ ${PREFIX_2}-g++ ${FIND_INPUTS})
find_program(CMAKE_AR NAMES ${PREFIX_1}-ar ${PREFIX_2}-ar ${FIND_INPUTS})
find_program(CMAKE_OBJCOPY NAMES ${PREFIX_1}-objcopy ${PREFIX_2}-objcopy ${FIND_INPUTS})
find_program(CMAKE_OBJDUMP NAMES ${PREFIX_1}-objdump ${PREFIX_2}-objdump ${FIND_INPUTS})
find_program(CMAKE_ASM_COMPILER NAMES ${FPRIME__INTERNAL_PREFIX_1}-as ${FPRIME__INTERNAL_PREFIX_2}-as ${FPRIME__INTERNAL_FIND_INPUTS})
find_program(CMAKE_C_COMPILER NAMES ${FPRIME__INTERNAL_PREFIX_1}-gcc ${FPRIME__INTERNAL_PREFIX_2}-gcc ${FPRIME__INTERNAL_FIND_INPUTS})
find_program(CMAKE_CXX_COMPILER NAMES ${FPRIME__INTERNAL_PREFIX_1}-g++ ${FPRIME__INTERNAL_PREFIX_2}-g++ ${FPRIME__INTERNAL_FIND_INPUTS})
find_program(CMAKE_AR NAMES ${FPRIME__INTERNAL_PREFIX_1}-ar ${FPRIME__INTERNAL_PREFIX_2}-ar ${FPRIME__INTERNAL_FIND_INPUTS})
find_program(CMAKE_OBJCOPY NAMES ${FPRIME__INTERNAL_PREFIX_1}-objcopy ${FPRIME__INTERNAL_PREFIX_2}-objcopy ${FPRIME__INTERNAL_FIND_INPUTS})
find_program(CMAKE_OBJDUMP NAMES ${FPRIME__INTERNAL_PREFIX_1}-objdump ${FPRIME__INTERNAL_PREFIX_2}-objdump ${FPRIME__INTERNAL_FIND_INPUTS})
# List programs as found
if (CMAKE_DEBUG_OUTPUT)