2017-12-12 14:12:07 +00:00
|
|
|
src = [
|
2018-01-23 15:32:29 +00:00
|
|
|
'src/main.c',
|
2022-02-03 21:46:24 +00:00
|
|
|
'src/adb/adb.c',
|
2022-02-05 21:32:40 +00:00
|
|
|
'src/adb/adb_device.c',
|
2022-02-03 21:46:24 +00:00
|
|
|
'src/adb/adb_parser.c',
|
|
|
|
'src/adb/adb_tunnel.c',
|
2023-03-02 23:43:20 +00:00
|
|
|
'src/audio_player.c',
|
2019-12-08 20:35:19 +00:00
|
|
|
'src/cli.c',
|
2021-07-04 13:24:51 +00:00
|
|
|
'src/clock.c',
|
2021-01-17 13:11:59 +00:00
|
|
|
'src/compat.c',
|
2019-05-31 12:55:11 +00:00
|
|
|
'src/control_msg.c',
|
2018-02-08 10:26:31 +00:00
|
|
|
'src/controller.c',
|
2017-12-12 14:12:07 +00:00
|
|
|
'src/decoder.c',
|
2023-03-01 23:31:43 +00:00
|
|
|
'src/delay_buffer.c',
|
2022-02-02 19:51:07 +00:00
|
|
|
'src/demuxer.c',
|
2019-05-31 12:55:11 +00:00
|
|
|
'src/device_msg.c',
|
2023-03-31 18:20:27 +00:00
|
|
|
'src/display.c',
|
2021-10-22 16:51:20 +00:00
|
|
|
'src/icon.c',
|
2022-01-21 18:10:27 +00:00
|
|
|
'src/file_pusher.c',
|
2018-08-15 15:01:54 +00:00
|
|
|
'src/fps_counter.c',
|
2021-07-04 10:39:03 +00:00
|
|
|
'src/frame_buffer.c',
|
2018-08-15 15:01:54 +00:00
|
|
|
'src/input_manager.c',
|
2021-10-03 15:11:20 +00:00
|
|
|
'src/keyboard_inject.c',
|
2021-10-03 15:44:14 +00:00
|
|
|
'src/mouse_inject.c',
|
2020-04-11 14:08:23 +00:00
|
|
|
'src/opengl.c',
|
2021-10-27 16:43:47 +00:00
|
|
|
'src/options.c',
|
2023-02-10 21:52:40 +00:00
|
|
|
'src/packet_merger.c',
|
2019-05-29 22:25:37 +00:00
|
|
|
'src/receiver.c',
|
2018-11-09 11:21:17 +00:00
|
|
|
'src/recorder.c',
|
2018-01-23 15:32:29 +00:00
|
|
|
'src/scrcpy.c',
|
2018-02-08 10:14:13 +00:00
|
|
|
'src/screen.c',
|
2018-01-22 10:22:31 +00:00
|
|
|
'src/server.c',
|
2022-02-08 19:59:38 +00:00
|
|
|
'src/version.c',
|
2023-03-02 08:25:25 +00:00
|
|
|
'src/trait/frame_source.c',
|
2023-03-02 08:07:25 +00:00
|
|
|
'src/trait/packet_source.c',
|
2021-11-20 13:33:13 +00:00
|
|
|
'src/util/acksync.c',
|
2023-03-02 23:43:20 +00:00
|
|
|
'src/util/average.c',
|
2023-02-25 13:32:02 +00:00
|
|
|
'src/util/bytebuf.c',
|
2021-11-11 15:12:17 +00:00
|
|
|
'src/util/file.c',
|
2021-11-26 20:58:56 +00:00
|
|
|
'src/util/intmap.c',
|
2021-11-12 17:50:50 +00:00
|
|
|
'src/util/intr.c',
|
2021-06-20 10:46:41 +00:00
|
|
|
'src/util/log.c',
|
2023-02-28 20:48:18 +00:00
|
|
|
'src/util/memory.c',
|
2019-11-24 10:53:00 +00:00
|
|
|
'src/util/net.c',
|
2021-11-12 17:50:50 +00:00
|
|
|
'src/util/net_intr.c',
|
2021-01-03 13:55:15 +00:00
|
|
|
'src/util/process.c',
|
2021-11-12 17:50:50 +00:00
|
|
|
'src/util/process_intr.c',
|
2023-01-27 18:26:19 +00:00
|
|
|
'src/util/rand.c',
|
2021-11-06 18:51:47 +00:00
|
|
|
'src/util/strbuf.c',
|
2021-11-12 22:12:51 +00:00
|
|
|
'src/util/str.c',
|
2021-11-11 14:22:39 +00:00
|
|
|
'src/util/term.c',
|
2021-01-31 17:24:35 +00:00
|
|
|
'src/util/thread.c',
|
2021-07-04 14:50:19 +00:00
|
|
|
'src/util/tick.c',
|
2023-06-01 16:46:50 +00:00
|
|
|
'src/util/timeout.c',
|
2017-12-12 14:12:07 +00:00
|
|
|
]
|
|
|
|
|
2021-11-20 20:24:56 +00:00
|
|
|
conf = configuration_data()
|
|
|
|
|
2021-11-24 18:36:33 +00:00
|
|
|
conf.set('_POSIX_C_SOURCE', '200809L')
|
|
|
|
conf.set('_XOPEN_SOURCE', '700')
|
|
|
|
conf.set('_GNU_SOURCE', true)
|
|
|
|
|
2021-01-03 14:09:01 +00:00
|
|
|
if host_machine.system() == 'windows'
|
2021-12-09 21:58:31 +00:00
|
|
|
windows = import('windows')
|
2021-11-11 15:12:17 +00:00
|
|
|
src += [
|
|
|
|
'src/sys/win/file.c',
|
|
|
|
'src/sys/win/process.c',
|
2021-12-09 21:58:31 +00:00
|
|
|
windows.compile_resources('scrcpy-windows.rc'),
|
2021-11-11 15:12:17 +00:00
|
|
|
]
|
2021-11-20 20:24:56 +00:00
|
|
|
conf.set('_WIN32_WINNT', '0x0600')
|
|
|
|
conf.set('WINVER', '0x0600')
|
2021-01-03 14:09:01 +00:00
|
|
|
else
|
2021-11-11 15:12:17 +00:00
|
|
|
src += [
|
|
|
|
'src/sys/unix/file.c',
|
|
|
|
'src/sys/unix/process.c',
|
|
|
|
]
|
2021-11-20 20:24:56 +00:00
|
|
|
if host_machine.system() == 'darwin'
|
|
|
|
conf.set('_DARWIN_C_SOURCE', true)
|
|
|
|
endif
|
2021-01-03 14:09:01 +00:00
|
|
|
endif
|
|
|
|
|
2022-02-12 11:33:40 +00:00
|
|
|
v4l2_support = get_option('v4l2') and host_machine.system() == 'linux'
|
2021-04-03 22:10:44 +00:00
|
|
|
if v4l2_support
|
|
|
|
src += [ 'src/v4l2_sink.c' ]
|
|
|
|
endif
|
|
|
|
|
2022-02-07 07:52:17 +00:00
|
|
|
usb_support = get_option('usb')
|
2022-01-24 21:29:07 +00:00
|
|
|
if usb_support
|
2021-09-10 10:57:35 +00:00
|
|
|
src += [
|
2022-01-24 21:27:15 +00:00
|
|
|
'src/usb/aoa_hid.c',
|
|
|
|
'src/usb/hid_keyboard.c',
|
|
|
|
'src/usb/hid_mouse.c',
|
2022-01-22 10:09:41 +00:00
|
|
|
'src/usb/scrcpy_otg.c',
|
|
|
|
'src/usb/screen_otg.c',
|
2022-01-24 21:56:12 +00:00
|
|
|
'src/usb/usb.c',
|
2021-09-10 10:57:35 +00:00
|
|
|
]
|
|
|
|
endif
|
|
|
|
|
2021-01-08 18:13:53 +00:00
|
|
|
cc = meson.get_compiler('c')
|
|
|
|
|
2021-12-10 18:50:58 +00:00
|
|
|
crossbuild_windows = meson.is_cross_build() and host_machine.system() == 'windows'
|
|
|
|
|
|
|
|
if not crossbuild_windows
|
2018-05-13 14:03:39 +00:00
|
|
|
|
|
|
|
# native build
|
|
|
|
dependencies = [
|
2021-12-06 22:55:29 +00:00
|
|
|
dependency('libavformat', version: '>= 57.33'),
|
2021-12-06 23:02:22 +00:00
|
|
|
dependency('libavcodec', version: '>= 57.37'),
|
2018-05-13 14:03:39 +00:00
|
|
|
dependency('libavutil'),
|
2023-03-02 23:43:20 +00:00
|
|
|
dependency('libswresample'),
|
2021-12-06 22:46:01 +00:00
|
|
|
dependency('sdl2', version: '>= 2.0.5'),
|
2018-05-13 14:03:39 +00:00
|
|
|
]
|
|
|
|
|
2021-04-03 22:10:44 +00:00
|
|
|
if v4l2_support
|
|
|
|
dependencies += dependency('libavdevice')
|
|
|
|
endif
|
|
|
|
|
2022-01-24 21:29:07 +00:00
|
|
|
if usb_support
|
2021-09-10 10:57:35 +00:00
|
|
|
dependencies += dependency('libusb-1.0')
|
|
|
|
endif
|
2018-05-13 14:03:39 +00:00
|
|
|
|
2021-09-10 10:57:35 +00:00
|
|
|
else
|
2018-05-13 14:03:39 +00:00
|
|
|
# cross-compile mingw32 build (from Linux to Windows)
|
|
|
|
prebuilt_sdl2 = meson.get_cross_property('prebuilt_sdl2')
|
2022-02-09 22:10:38 +00:00
|
|
|
sdl2_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_sdl2 + '/bin'
|
|
|
|
sdl2_lib_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_sdl2 + '/lib'
|
|
|
|
sdl2_include_dir = 'prebuilt-deps/data/' + prebuilt_sdl2 + '/include'
|
2018-05-13 14:03:39 +00:00
|
|
|
|
|
|
|
sdl2 = declare_dependency(
|
|
|
|
dependencies: [
|
|
|
|
cc.find_library('SDL2', dirs: sdl2_bin_dir),
|
|
|
|
cc.find_library('SDL2main', dirs: sdl2_lib_dir),
|
|
|
|
],
|
|
|
|
include_directories: include_directories(sdl2_include_dir)
|
|
|
|
)
|
|
|
|
|
2022-01-17 18:04:18 +00:00
|
|
|
prebuilt_ffmpeg = meson.get_cross_property('prebuilt_ffmpeg')
|
2022-02-09 22:10:38 +00:00
|
|
|
ffmpeg_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_ffmpeg + '/bin'
|
|
|
|
ffmpeg_include_dir = 'prebuilt-deps/data/' + prebuilt_ffmpeg + '/include'
|
2022-01-17 18:11:23 +00:00
|
|
|
|
2018-05-13 14:03:39 +00:00
|
|
|
ffmpeg = declare_dependency(
|
|
|
|
dependencies: [
|
2023-02-28 10:56:42 +00:00
|
|
|
cc.find_library('avcodec-60', dirs: ffmpeg_bin_dir),
|
|
|
|
cc.find_library('avformat-60', dirs: ffmpeg_bin_dir),
|
|
|
|
cc.find_library('avutil-58', dirs: ffmpeg_bin_dir),
|
2023-03-02 23:43:20 +00:00
|
|
|
cc.find_library('swresample-4', dirs: ffmpeg_bin_dir),
|
2018-05-13 14:03:39 +00:00
|
|
|
],
|
|
|
|
include_directories: include_directories(ffmpeg_include_dir)
|
|
|
|
)
|
|
|
|
|
2022-02-07 07:52:17 +00:00
|
|
|
prebuilt_libusb = meson.get_cross_property('prebuilt_libusb')
|
2023-02-27 20:43:34 +00:00
|
|
|
libusb_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_libusb + '/bin'
|
|
|
|
libusb_include_dir = 'prebuilt-deps/data/' + prebuilt_libusb + '/include'
|
2022-02-07 07:52:17 +00:00
|
|
|
|
|
|
|
libusb = declare_dependency(
|
|
|
|
dependencies: [
|
2022-04-22 11:33:50 +00:00
|
|
|
cc.find_library('msys-usb-1.0', dirs: libusb_bin_dir),
|
2022-02-07 07:52:17 +00:00
|
|
|
],
|
|
|
|
include_directories: include_directories(libusb_include_dir)
|
|
|
|
)
|
|
|
|
|
2018-05-13 14:03:39 +00:00
|
|
|
dependencies = [
|
|
|
|
ffmpeg,
|
|
|
|
sdl2,
|
2022-02-07 07:52:17 +00:00
|
|
|
libusb,
|
2018-05-13 14:03:39 +00:00
|
|
|
cc.find_library('mingw32')
|
|
|
|
]
|
|
|
|
|
|
|
|
endif
|
2017-12-12 14:12:07 +00:00
|
|
|
|
Replace SDL_net by custom implementation
SDL_net is not very suitable for scrcpy.
For example, SDLNet_TCP_Accept() is non-blocking, so we have to wrap it
by calling many SDL_Net-specific functions to make it blocking.
But above all, SDLNet_TCP_Open() is a server socket only when no IP is
provided; otherwise, it's a client socket. Therefore, it is not possible
to create a server socket bound to localhost, so it accepts connections
from anywhere.
This is a problem for scrcpy, because on start, the application listens
for nearly 1 second until it accepts the first connection, supposedly
from the device. If someone on the local network manages to connect to
the server socket first, then they can stream arbitrary H.264 video.
This may be troublesome, for example during a public presentation ;-)
Provide our own simplified API (net.h) instead, implemented for the
different platforms.
2018-02-15 21:59:21 +00:00
|
|
|
if host_machine.system() == 'windows'
|
|
|
|
dependencies += cc.find_library('ws2_32')
|
|
|
|
endif
|
|
|
|
|
2021-11-24 18:38:33 +00:00
|
|
|
check_functions = [
|
|
|
|
'strdup',
|
2021-11-24 18:55:00 +00:00
|
|
|
'asprintf',
|
|
|
|
'vasprintf',
|
2023-01-21 18:35:04 +00:00
|
|
|
'nrand48',
|
|
|
|
'jrand48',
|
2023-02-28 20:43:19 +00:00
|
|
|
'reallocarray',
|
2021-11-24 18:38:33 +00:00
|
|
|
]
|
|
|
|
|
2021-01-17 13:11:59 +00:00
|
|
|
foreach f : check_functions
|
|
|
|
if cc.has_function(f)
|
|
|
|
define = 'HAVE_' + f.underscorify().to_upper()
|
|
|
|
conf.set(define, true)
|
|
|
|
endif
|
|
|
|
endforeach
|
|
|
|
|
2021-11-26 07:10:37 +00:00
|
|
|
conf.set('HAVE_SOCK_CLOEXEC', host_machine.system() != 'windows' and
|
|
|
|
cc.has_header_symbol('sys/socket.h', 'SOCK_CLOEXEC'))
|
|
|
|
|
2018-02-07 11:37:53 +00:00
|
|
|
# the version, updated on release
|
2018-11-12 13:09:11 +00:00
|
|
|
conf.set_quoted('SCRCPY_VERSION', meson.project_version())
|
2018-02-07 11:37:53 +00:00
|
|
|
|
2018-02-13 10:55:12 +00:00
|
|
|
# the prefix used during configuration (meson --prefix=PREFIX)
|
2018-02-14 12:37:01 +00:00
|
|
|
conf.set_quoted('PREFIX', get_option('prefix'))
|
2018-02-13 10:55:12 +00:00
|
|
|
|
2019-10-30 22:40:10 +00:00
|
|
|
# build a "portable" version (with scrcpy-server accessible from the same
|
2019-06-10 13:14:10 +00:00
|
|
|
# directory as the executable)
|
2019-06-08 17:03:22 +00:00
|
|
|
conf.set('PORTABLE', get_option('portable'))
|
2018-02-13 10:55:12 +00:00
|
|
|
|
2019-12-09 20:16:09 +00:00
|
|
|
# the default client TCP port range for the "adb reverse" tunnel
|
2018-02-07 11:02:15 +00:00
|
|
|
# overridden by option --port
|
2019-12-09 20:16:09 +00:00
|
|
|
conf.set('DEFAULT_LOCAL_PORT_RANGE_FIRST', '27183')
|
|
|
|
conf.set('DEFAULT_LOCAL_PORT_RANGE_LAST', '27199')
|
2018-02-07 11:02:15 +00:00
|
|
|
|
2019-11-03 18:31:56 +00:00
|
|
|
# run a server debugger and wait for a client to be attached
|
|
|
|
conf.set('SERVER_DEBUGGER', get_option('server_debugger'))
|
|
|
|
|
2020-03-19 18:15:43 +00:00
|
|
|
# select the debugger method ('old' for Android < 9, 'new' for Android >= 9)
|
|
|
|
conf.set('SERVER_DEBUGGER_METHOD_NEW', get_option('server_debugger_method') == 'new')
|
|
|
|
|
2021-04-03 22:10:44 +00:00
|
|
|
# enable V4L2 support (linux only)
|
|
|
|
conf.set('HAVE_V4L2', v4l2_support)
|
|
|
|
|
2021-09-10 10:57:35 +00:00
|
|
|
# enable HID over AOA support (linux only)
|
2022-01-24 21:29:07 +00:00
|
|
|
conf.set('HAVE_USB', usb_support)
|
2021-09-10 10:57:35 +00:00
|
|
|
|
2018-02-14 12:37:01 +00:00
|
|
|
configure_file(configuration: conf, output: 'config.h')
|
2018-02-07 11:02:15 +00:00
|
|
|
|
2018-03-20 13:03:28 +00:00
|
|
|
src_dir = include_directories('src')
|
2018-05-27 19:30:32 +00:00
|
|
|
|
2019-05-29 06:20:05 +00:00
|
|
|
executable('scrcpy', src,
|
|
|
|
dependencies: dependencies,
|
|
|
|
include_directories: src_dir,
|
|
|
|
install: true,
|
2020-12-15 20:50:46 +00:00
|
|
|
c_args: [])
|
2017-12-14 10:38:44 +00:00
|
|
|
|
2022-06-27 10:15:37 +00:00
|
|
|
# <https://mesonbuild.com/Builtin-options.html#directories>
|
|
|
|
datadir = get_option('datadir') # by default 'share'
|
|
|
|
|
2019-10-30 14:14:30 +00:00
|
|
|
install_man('scrcpy.1')
|
2022-02-20 16:56:50 +00:00
|
|
|
install_data('data/icon.png',
|
2021-10-22 16:51:20 +00:00
|
|
|
rename: 'scrcpy.png',
|
2022-06-27 10:15:37 +00:00
|
|
|
install_dir: join_paths(datadir, 'icons/hicolor/256x256/apps'))
|
2022-02-10 14:37:02 +00:00
|
|
|
install_data('data/zsh-completion/_scrcpy',
|
2022-06-27 10:15:37 +00:00
|
|
|
install_dir: join_paths(datadir, 'zsh/site-functions'))
|
2022-02-21 21:38:53 +00:00
|
|
|
install_data('data/bash-completion/scrcpy',
|
2022-06-27 10:15:37 +00:00
|
|
|
install_dir: join_paths(datadir, 'bash-completion/completions'))
|
2019-10-30 14:14:30 +00:00
|
|
|
|
2018-10-14 08:50:35 +00:00
|
|
|
# Desktop entry file for application launchers
|
|
|
|
if host_machine.system() == 'linux'
|
|
|
|
# Install a launcher (ex: /usr/local/share/applications/scrcpy.desktop)
|
|
|
|
install_data('data/scrcpy.desktop',
|
|
|
|
install_dir: join_paths(datadir, 'applications'))
|
2022-06-27 11:32:40 +00:00
|
|
|
install_data('data/scrcpy-console.desktop',
|
|
|
|
install_dir: join_paths(datadir, 'applications'))
|
2018-10-14 08:50:35 +00:00
|
|
|
endif
|
|
|
|
|
2017-12-14 10:38:44 +00:00
|
|
|
|
|
|
|
### TESTS
|
|
|
|
|
2019-12-09 22:23:40 +00:00
|
|
|
# do not build tests in release (assertions would not be executed at all)
|
|
|
|
if get_option('buildtype') == 'debug'
|
|
|
|
tests = [
|
2021-11-25 21:11:59 +00:00
|
|
|
['test_adb_parser', [
|
|
|
|
'tests/test_adb_parser.c',
|
2022-02-05 21:32:40 +00:00
|
|
|
'src/adb/adb_device.c',
|
2022-02-03 21:46:24 +00:00
|
|
|
'src/adb/adb_parser.c',
|
2021-11-25 21:11:59 +00:00
|
|
|
'src/util/str.c',
|
|
|
|
'src/util/strbuf.c',
|
|
|
|
]],
|
2022-08-03 13:13:16 +00:00
|
|
|
['test_binary', [
|
|
|
|
'tests/test_binary.c',
|
2019-12-09 22:23:40 +00:00
|
|
|
]],
|
2023-02-25 13:32:02 +00:00
|
|
|
['test_bytebuf', [
|
|
|
|
'tests/test_bytebuf.c',
|
|
|
|
'src/util/bytebuf.c',
|
|
|
|
]],
|
2019-12-09 22:23:40 +00:00
|
|
|
['test_cli', [
|
|
|
|
'tests/test_cli.c',
|
|
|
|
'src/cli.c',
|
2021-10-27 16:43:47 +00:00
|
|
|
'src/options.c',
|
2022-10-19 13:17:43 +00:00
|
|
|
'src/util/log.c',
|
2021-11-18 00:02:53 +00:00
|
|
|
'src/util/net.c',
|
2021-11-12 22:12:51 +00:00
|
|
|
'src/util/str.c',
|
2021-11-06 19:26:35 +00:00
|
|
|
'src/util/strbuf.c',
|
2021-11-11 14:22:39 +00:00
|
|
|
'src/util/term.c',
|
2019-12-09 22:23:40 +00:00
|
|
|
]],
|
2020-06-04 19:43:07 +00:00
|
|
|
['test_control_msg_serialize', [
|
2019-12-09 22:23:40 +00:00
|
|
|
'tests/test_control_msg_serialize.c',
|
|
|
|
'src/control_msg.c',
|
2021-11-12 22:12:51 +00:00
|
|
|
'src/util/str.c',
|
2021-11-06 19:26:35 +00:00
|
|
|
'src/util/strbuf.c',
|
2019-12-09 22:23:40 +00:00
|
|
|
]],
|
2020-06-04 19:43:07 +00:00
|
|
|
['test_device_msg_deserialize', [
|
2019-12-09 22:23:40 +00:00
|
|
|
'tests/test_device_msg_deserialize.c',
|
|
|
|
'src/device_msg.c',
|
|
|
|
]],
|
2021-11-06 18:51:47 +00:00
|
|
|
['test_strbuf', [
|
|
|
|
'tests/test_strbuf.c',
|
|
|
|
'src/util/strbuf.c',
|
|
|
|
]],
|
2021-11-12 22:12:51 +00:00
|
|
|
['test_str', [
|
|
|
|
'tests/test_str.c',
|
|
|
|
'src/util/str.c',
|
2021-11-06 19:26:35 +00:00
|
|
|
'src/util/strbuf.c',
|
2019-12-09 22:23:40 +00:00
|
|
|
]],
|
2023-02-28 21:56:37 +00:00
|
|
|
['test_vecdeque', [
|
|
|
|
'tests/test_vecdeque.c',
|
|
|
|
'src/util/memory.c',
|
|
|
|
]],
|
2022-02-18 07:34:50 +00:00
|
|
|
['test_vector', [
|
|
|
|
'tests/test_vector.c',
|
|
|
|
]],
|
2019-12-09 22:23:40 +00:00
|
|
|
]
|
2017-12-14 10:38:44 +00:00
|
|
|
|
2019-12-09 22:23:40 +00:00
|
|
|
foreach t : tests
|
2023-03-27 12:59:09 +00:00
|
|
|
sources = t[1] + ['src/compat.c']
|
|
|
|
exe = executable(t[0], sources,
|
2019-12-09 22:23:40 +00:00
|
|
|
include_directories: src_dir,
|
|
|
|
dependencies: dependencies,
|
2020-07-16 22:00:42 +00:00
|
|
|
c_args: ['-DSDL_MAIN_HANDLED', '-DSC_TEST'])
|
2019-12-09 22:23:40 +00:00
|
|
|
test(t[0], exe)
|
|
|
|
endforeach
|
|
|
|
endif
|