2019-07-16 20:19:11 -06:00
|
|
|
include(Plugins.cmake)
|
2011-07-25 03:09:29 -06:00
|
|
|
|
2019-07-16 20:19:11 -06:00
|
|
|
option(BUILD_STONESENSE "Build stonesense (needs a checkout first)." OFF)
|
2011-07-21 03:29:26 -06:00
|
|
|
if(BUILD_STONESENSE)
|
2019-07-16 20:19:11 -06:00
|
|
|
add_subdirectory(stonesense)
|
2011-07-21 03:29:26 -06:00
|
|
|
endif()
|
|
|
|
|
2019-07-16 20:19:11 -06:00
|
|
|
option(BUILD_ISOWORLD "Build isoworld (needs a checkout first)." OFF)
|
2013-03-30 03:57:37 -06:00
|
|
|
if(BUILD_ISOWORLD)
|
2019-07-16 20:19:11 -06:00
|
|
|
add_subdirectory(isoworld)
|
|
|
|
if(UNIX)
|
|
|
|
if(APPLE)
|
|
|
|
# TODO: add an OSX runner script
|
2014-07-21 12:18:29 -06:00
|
|
|
else()
|
|
|
|
# On linux, copy our version of the df launch script which sets LD_PRELOAD
|
|
|
|
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/runisoworld
|
|
|
|
DESTINATION .)
|
|
|
|
endif()
|
2019-07-16 20:19:11 -06:00
|
|
|
endif()
|
2013-03-30 03:57:37 -06:00
|
|
|
endif()
|
|
|
|
|
2019-07-16 20:19:11 -06:00
|
|
|
option(BUILD_DEV_PLUGINS "Build developer plugins." OFF)
|
2011-08-07 16:55:17 -06:00
|
|
|
if(BUILD_DEV_PLUGINS)
|
2019-07-16 20:19:11 -06:00
|
|
|
add_subdirectory(devel)
|
2011-07-14 00:52:06 -06:00
|
|
|
endif()
|
2011-07-16 10:10:08 -06:00
|
|
|
|
2019-07-16 20:19:11 -06:00
|
|
|
option(BUILD_RUBY "Build ruby binding." ON)
|
|
|
|
if(BUILD_RUBY)
|
|
|
|
add_subdirectory(ruby)
|
2012-03-21 11:49:50 -06:00
|
|
|
endif()
|
|
|
|
|
Allow plugins to export functions to lua with safe reload support.
- To ensure reload safety functions have to be wrapped. Every call
checks the loaded state and locks a mutex in Plugin. If the plugin
is unloaded, calling its functions throws a lua error. Therefore,
plugins may not create closures or export yieldable functions.
- The set of function argument and return types supported by
LuaWrapper is severely limited when compared to being compiled
inside the main library.
Currently supported types: numbers, bool, std::string, df::foo,
df::foo*, std::vector<bool>, std::vector<df::foo*>.
- To facilitate postponing initialization until after all plugins
have been loaded, the core sends a SC_CORE_INITIALIZED event.
- As an example, the burrows plugin now exports its functions.
2012-04-14 09:44:07 -06:00
|
|
|
install(DIRECTORY lua/
|
2019-07-16 20:19:11 -06:00
|
|
|
DESTINATION ${DFHACK_LUA_DESTINATION}/plugins
|
|
|
|
FILES_MATCHING PATTERN "*.lua")
|
2012-09-06 07:10:58 -06:00
|
|
|
install(DIRECTORY raw/
|
2019-07-16 20:19:11 -06:00
|
|
|
DESTINATION ${DFHACK_DATA_DESTINATION}/raw
|
|
|
|
FILES_MATCHING PATTERN "*.txt")
|
2012-09-17 11:15:51 -06:00
|
|
|
install(DIRECTORY raw/
|
2019-07-16 20:19:11 -06:00
|
|
|
DESTINATION ${DFHACK_DATA_DESTINATION}/raw
|
|
|
|
FILES_MATCHING PATTERN "*.diff")
|
Allow plugins to export functions to lua with safe reload support.
- To ensure reload safety functions have to be wrapped. Every call
checks the loaded state and locks a mutex in Plugin. If the plugin
is unloaded, calling its functions throws a lua error. Therefore,
plugins may not create closures or export yieldable functions.
- The set of function argument and return types supported by
LuaWrapper is severely limited when compared to being compiled
inside the main library.
Currently supported types: numbers, bool, std::string, df::foo,
df::foo*, std::vector<bool>, std::vector<df::foo*>.
- To facilitate postponing initialization until after all plugins
have been loaded, the core sends a SC_CORE_INITIALIZED event.
- As an example, the burrows plugin now exports its functions.
2012-04-14 09:44:07 -06:00
|
|
|
|
2012-03-15 03:01:23 -06:00
|
|
|
# Protobuf
|
2019-07-16 20:19:11 -06:00
|
|
|
file(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto)
|
2012-03-15 03:01:23 -06:00
|
|
|
|
2019-07-16 20:19:11 -06:00
|
|
|
string(REPLACE ".proto" ".pb.cc" PROJECT_PROTO_SRCS "${PROJECT_PROTOS}")
|
|
|
|
string(REPLACE ".proto" ".pb.h" PROJECT_PROTO_HDRS "${PROJECT_PROTOS}")
|
|
|
|
string(REPLACE "/proto/" "/proto/tmp/" PROJECT_PROTO_TMP_FILES "${PROJECT_PROTO_SRCS};${PROJECT_PROTO_HDRS}")
|
|
|
|
set_source_files_properties(${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS}
|
2016-10-24 20:28:51 -06:00
|
|
|
PROPERTIES GENERATED TRUE)
|
|
|
|
|
|
|
|
# Force a re-gen if any *.pb.* files are missing
|
2016-10-24 20:51:27 -06:00
|
|
|
# (only runs when cmake is run, but better than nothing)
|
2019-07-16 20:19:11 -06:00
|
|
|
foreach(file IN LISTS PROJECT_PROTO_SRCS PROJECT_PROTO_HDRS)
|
|
|
|
if(NOT EXISTS ${file})
|
|
|
|
# message("Resetting generate_proto because '${file}' is missing")
|
|
|
|
file(REMOVE ${PROJECT_PROTO_TMP_FILES})
|
|
|
|
break()
|
|
|
|
endif()
|
|
|
|
endforeach()
|
|
|
|
|
|
|
|
add_custom_command(
|
2016-10-24 20:51:27 -06:00
|
|
|
OUTPUT ${PROJECT_PROTO_TMP_FILES}
|
2012-03-15 04:06:50 -06:00
|
|
|
COMMAND protoc-bin -I=${dfhack_SOURCE_DIR}/library/proto/
|
|
|
|
-I=${CMAKE_CURRENT_SOURCE_DIR}/proto/
|
2016-10-24 20:28:51 -06:00
|
|
|
--cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/proto/tmp/
|
2012-03-15 03:01:23 -06:00
|
|
|
${PROJECT_PROTOS}
|
2022-03-29 11:28:52 -06:00
|
|
|
COMMAND ${PERL_EXECUTABLE} ${dfhack_SOURCE_DIR}/depends/copy-if-different.pl
|
2016-10-24 20:28:51 -06:00
|
|
|
${PROJECT_PROTO_TMP_FILES}
|
|
|
|
${CMAKE_CURRENT_SOURCE_DIR}/proto/
|
|
|
|
COMMENT "Generating plugin protobufs"
|
2012-03-15 03:01:23 -06:00
|
|
|
DEPENDS protoc-bin ${PROJECT_PROTOS}
|
|
|
|
)
|
2019-07-16 20:19:11 -06:00
|
|
|
add_custom_target(generate_proto DEPENDS ${PROJECT_PROTO_TMP_FILES})
|
2012-03-15 03:01:23 -06:00
|
|
|
|
2019-07-16 20:19:11 -06:00
|
|
|
set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE )
|
2012-03-24 06:22:43 -06:00
|
|
|
|
2012-03-15 03:01:23 -06:00
|
|
|
# Plugins
|
2019-07-16 20:19:11 -06:00
|
|
|
option(BUILD_SUPPORTED "Build the supported plugins (reveal, probe, etc.)." ON)
|
|
|
|
if(BUILD_SUPPORTED)
|
2022-04-13 20:53:22 -06:00
|
|
|
# If you are adding a plugin that you do not intend to commit to the DFHack repo,
|
|
|
|
# see instructions for adding "external" plugins at the end of this file.
|
|
|
|
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(3dveins 3dveins.cpp)
|
|
|
|
dfhack_plugin(add-spatter add-spatter.cpp)
|
|
|
|
# dfhack_plugin(advtools advtools.cpp)
|
|
|
|
dfhack_plugin(autochop autochop.cpp)
|
2020-01-18 20:28:43 -07:00
|
|
|
dfhack_plugin(autoclothing autoclothing.cpp)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(autodump autodump.cpp)
|
2020-01-18 20:28:43 -07:00
|
|
|
dfhack_plugin(autofarm autofarm.cpp)
|
2022-05-13 14:52:43 -06:00
|
|
|
dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(autohauler autohauler.cpp)
|
|
|
|
dfhack_plugin(autolabor autolabor.cpp)
|
improve UX between automaterial and buildingplan
solves the confusing behavior when both automaterial and buildingplan
are enabled for constructions. the two plugins now communicate with each
other over the Lua layer to negotiate consistent behavior.
if neither plugin is enabled, the standard DF UI acts as normal
if automaterial is enabled but buildingplan is not, then automaterial
behavior is unchanged.
if buildingplan is enabled and automaterial is not then behavior is
the same as other buildings with buildingplan (no material selection
screen, screen stays on building placement screen after placement).
this commit fixes a bug, though, where buildingplan would only lay
down a single tile of contruction instead of a solid block when a
block is requested.
if both plugins are enabled but buildingplan is not enabled for the
building type then automaterial is unchanged from previous behavior,
execpt for an additional header showing the separation between
automaterial hotkeys and buildingplan hotkeys.
finally, if both plugins are enabled and buildingplan is enabled for the
building type then buildingplan behavior prevails, but the box select and
hollow designations features of automaterial are still usable and
useful. the 'Auto Mat-select', 'Reselect Type', and "Open Placement"
automaterial hotkeys are hidden in the UI and ignored in the feed. This
is because buildingplan takes over material selection, so 'Auto
Mat-select' doesn't make sense. Buildingplan also already stays on the
placement screen after placement, so 'Reselect Type' is not necessary.
And all buildingplan-placed buildings have relaxed placement
restrictions (e.g. they can be built in mid-air) so 'Open Placement' is
also not necessary. The missing options are replaced with blank lines so
the vertical alignment of all other options stays constant.
we also remove a few extra lua_pop() calls that are made superfluous by
the StackUnwinder.
2020-10-29 12:00:49 -06:00
|
|
|
dfhack_plugin(automaterial automaterial.cpp LINK_LIBRARIES lua)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(automelt automelt.cpp)
|
|
|
|
dfhack_plugin(autotrade autotrade.cpp)
|
|
|
|
dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(burrows burrows.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(building-hacks building-hacks.cpp LINK_LIBRARIES lua)
|
2021-09-04 22:00:18 -06:00
|
|
|
dfhack_plugin(buildingplan buildingplan.cpp buildingplan-planner.cpp buildingplan-rooms.cpp LINK_LIBRARIES lua)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(changeitem changeitem.cpp)
|
|
|
|
dfhack_plugin(changelayer changelayer.cpp)
|
|
|
|
dfhack_plugin(changevein changevein.cpp)
|
|
|
|
dfhack_plugin(cleanconst cleanconst.cpp)
|
|
|
|
dfhack_plugin(cleaners cleaners.cpp)
|
|
|
|
dfhack_plugin(cleanowned cleanowned.cpp)
|
|
|
|
dfhack_plugin(command-prompt command-prompt.cpp)
|
|
|
|
dfhack_plugin(confirm confirm.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(createitem createitem.cpp)
|
2022-07-05 15:13:25 -06:00
|
|
|
dfhack_plugin(cromulate cromulate.cpp)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(cursecheck cursecheck.cpp)
|
|
|
|
dfhack_plugin(cxxrandom cxxrandom.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(deramp deramp.cpp)
|
2022-05-13 14:52:43 -06:00
|
|
|
dfhack_plugin(debug debug.cpp LINK_LIBRARIES jsoncpp_static)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(dig dig.cpp)
|
2021-06-02 23:18:42 -06:00
|
|
|
dfhack_plugin(dig-now dig-now.cpp LINK_LIBRARIES lua)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(digFlood digFlood.cpp)
|
2017-08-06 19:01:36 -06:00
|
|
|
add_subdirectory(diggingInvaders)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(dwarfvet dwarfvet.cpp)
|
|
|
|
dfhack_plugin(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua)
|
2017-09-01 06:13:34 -06:00
|
|
|
add_subdirectory(embark-assistant)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(embark-tools embark-tools.cpp)
|
|
|
|
dfhack_plugin(eventful eventful.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(fastdwarf fastdwarf.cpp)
|
|
|
|
dfhack_plugin(filltraffic filltraffic.cpp)
|
|
|
|
dfhack_plugin(fix-armory fix-armory.cpp)
|
|
|
|
dfhack_plugin(fix-unit-occupancy fix-unit-occupancy.cpp)
|
|
|
|
dfhack_plugin(fixveins fixveins.cpp)
|
|
|
|
dfhack_plugin(flows flows.cpp)
|
|
|
|
dfhack_plugin(follow follow.cpp)
|
|
|
|
dfhack_plugin(forceequip forceequip.cpp)
|
|
|
|
dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp)
|
|
|
|
dfhack_plugin(getplants getplants.cpp)
|
|
|
|
dfhack_plugin(hotkeys hotkeys.cpp)
|
|
|
|
dfhack_plugin(infiniteSky infiniteSky.cpp)
|
|
|
|
dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote)
|
|
|
|
dfhack_plugin(jobutils jobutils.cpp)
|
2017-07-28 01:43:32 -06:00
|
|
|
add_subdirectory(labormanager)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(lair lair.cpp)
|
|
|
|
dfhack_plugin(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread)
|
|
|
|
dfhack_plugin(manipulator manipulator.cpp)
|
2019-08-23 21:58:00 -06:00
|
|
|
dfhack_plugin(map-render map-render.cpp LINK_LIBRARIES lua)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(misery misery.cpp)
|
|
|
|
dfhack_plugin(mode mode.cpp)
|
|
|
|
dfhack_plugin(mousequery mousequery.cpp)
|
|
|
|
dfhack_plugin(nestboxes nestboxes.cpp)
|
2022-05-13 14:52:43 -06:00
|
|
|
dfhack_plugin(orders orders.cpp LINK_LIBRARIES jsoncpp_static)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(pathable pathable.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(petcapRemover petcapRemover.cpp)
|
|
|
|
dfhack_plugin(plants plants.cpp)
|
|
|
|
dfhack_plugin(probe probe.cpp)
|
2022-07-06 07:57:13 -06:00
|
|
|
dfhack_plugin(prospector prospector.cpp LINK_LIBRARIES lua)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(power-meter power-meter.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(regrass regrass.cpp)
|
2016-11-08 02:41:27 -07:00
|
|
|
add_subdirectory(remotefortressreader)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename)
|
2014-11-07 14:43:50 -07:00
|
|
|
add_subdirectory(rendermax)
|
2020-11-13 13:43:46 -07:00
|
|
|
dfhack_plugin(resume resume.cpp LINK_LIBRARIES lua)
|
2021-06-02 15:49:19 -06:00
|
|
|
dfhack_plugin(reveal reveal.cpp LINK_LIBRARIES lua)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(search search.cpp)
|
|
|
|
dfhack_plugin(seedwatch seedwatch.cpp)
|
|
|
|
dfhack_plugin(showmood showmood.cpp)
|
|
|
|
dfhack_plugin(siege-engine siege-engine.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(sort sort.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(steam-engine steam-engine.cpp)
|
2022-03-14 20:33:41 -06:00
|
|
|
dfhack_plugin(spectate spectate.cpp)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua)
|
2014-12-02 04:06:01 -07:00
|
|
|
add_subdirectory(stockpiles)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(stocks stocks.cpp)
|
|
|
|
dfhack_plugin(strangemood strangemood.cpp)
|
2020-01-18 20:28:43 -07:00
|
|
|
dfhack_plugin(tailor tailor.cpp)
|
2021-06-07 06:16:00 -06:00
|
|
|
dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(title-folder title-folder.cpp)
|
|
|
|
dfhack_plugin(title-version title-version.cpp)
|
|
|
|
dfhack_plugin(trackstop trackstop.cpp)
|
|
|
|
dfhack_plugin(tubefill tubefill.cpp)
|
2014-09-26 16:40:19 -06:00
|
|
|
add_subdirectory(tweak)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua)
|
|
|
|
dfhack_plugin(workNow workNow.cpp)
|
2020-09-18 13:04:06 -06:00
|
|
|
dfhack_plugin(xlsxreader xlsxreader.cpp LINK_LIBRARIES lua xlsxio_read_STATIC zip expat)
|
2019-07-16 20:19:11 -06:00
|
|
|
dfhack_plugin(zone zone.cpp LINK_LIBRARIES lua)
|
2022-04-13 20:53:22 -06:00
|
|
|
|
|
|
|
# If you are adding a plugin that you do not intend to commit to the DFHack repo,
|
|
|
|
# see instructions for adding "external" plugins at the end of this file.
|
2014-03-04 10:00:12 -07:00
|
|
|
endif()
|
2012-02-21 10:19:17 -07:00
|
|
|
|
2011-10-06 19:53:58 -06:00
|
|
|
# this is the skeleton plugin. If you want to make your own, make a copy and then change it
|
2019-07-16 20:19:11 -06:00
|
|
|
option(BUILD_SKELETON "Build the skeleton plugin." OFF)
|
2011-10-06 19:53:58 -06:00
|
|
|
if(BUILD_SKELETON)
|
|
|
|
add_subdirectory(skeleton)
|
|
|
|
endif()
|
2015-11-17 15:38:53 -07:00
|
|
|
|
2022-04-27 20:53:05 -06:00
|
|
|
macro(subdirlist result subdir)
|
|
|
|
file(GLOB children ABSOLUTE ${subdir}/ ${subdir}/*/)
|
|
|
|
set(dirlist "")
|
|
|
|
foreach(child ${children})
|
|
|
|
if(IS_DIRECTORY ${child})
|
|
|
|
file(RELATIVE_PATH child ${CMAKE_CURRENT_SOURCE_DIR}/${subdir} ${child})
|
|
|
|
list(APPEND dirlist ${child})
|
|
|
|
endif()
|
|
|
|
endforeach()
|
|
|
|
set(${result} ${dirlist})
|
|
|
|
endmacro()
|
2018-07-18 13:00:40 -06:00
|
|
|
|
2022-04-13 20:53:22 -06:00
|
|
|
# To add "external" plugins without committing them to the DFHack repo:
|
|
|
|
#
|
|
|
|
# 1. run CMake as you normally do (this is only necessary once if
|
|
|
|
# `external/CMakeLists.txt` does not exist yet)
|
|
|
|
# 2. add the plugin to the `external` folder (relative to this file).
|
|
|
|
# - for a multi-file plugin, either clone the repository inside of the
|
|
|
|
# `external` folder, or add the folder there manually.
|
|
|
|
# - for a single-file plugin, simply add the file there.
|
|
|
|
# 3. add an entry to `external/CMakeLists.txt`:
|
|
|
|
# - add_subdirectory() for multi-file plugins in a subdirectory
|
|
|
|
# - dfhack_plugin() for single-file plugins
|
|
|
|
# 4. build DFHack as normal. The plugins you added will be built as well.
|
|
|
|
|
|
|
|
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/external/CMakeLists.txt")
|
2022-04-27 20:53:05 -06:00
|
|
|
set(content_str
|
2022-04-13 20:53:22 -06:00
|
|
|
"# Add external plugins here - this file is ignored by git
|
|
|
|
|
|
|
|
# Recommended: use add_subdirectory() for folders that you have created within
|
|
|
|
# this folder, or dfhack_plugin() for single files that you have added here.
|
|
|
|
|
|
|
|
# See the end of /plugins/CMakeLists.txt for more details.
|
2018-07-18 13:00:40 -06:00
|
|
|
")
|
2022-04-27 20:53:05 -06:00
|
|
|
subdirlist(SUBDIRS external)
|
|
|
|
foreach(subdir ${SUBDIRS})
|
|
|
|
set(content_str "${content_str}add_subdirectory(${subdir})\n")
|
|
|
|
endforeach()
|
|
|
|
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/external/CMakeLists.txt" ${content_str})
|
2018-07-18 13:00:40 -06:00
|
|
|
endif()
|
|
|
|
|
2022-04-27 20:53:05 -06:00
|
|
|
add_subdirectory(external)
|
2022-04-13 20:53:22 -06:00
|
|
|
|
|
|
|
# for backwards compatibility
|
|
|
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.custom.txt")
|
|
|
|
include("${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.custom.txt")
|
|
|
|
endif()
|