Signed-off-by: falkTX <falktx@falktx.com>tags/22.06
@@ -0,0 +1 @@ | |||
../CardinalCommon.cpp |
@@ -0,0 +1 @@ | |||
../Cardinal/DistrhoPluginInfo.h |
@@ -0,0 +1,292 @@ | |||
#!/usr/bin/make -f | |||
# Makefile for DISTRHO Plugins # | |||
# ---------------------------- # | |||
# Created by falkTX | |||
# | |||
# -------------------------------------------------------------- | |||
# Carla stuff | |||
CWD = ../../carla/source | |||
STATIC_PLUGIN_TARGET = true | |||
include $(CWD)/Makefile.deps.mk | |||
CARLA_BUILD_DIR = ../../carla/build | |||
ifeq ($(DEBUG),true) | |||
CARLA_BUILD_TYPE = Debug | |||
else | |||
CARLA_BUILD_TYPE = Release | |||
endif | |||
CARLA_EXTRA_LIBS = $(CARLA_BUILD_DIR)/plugin/$(CARLA_BUILD_TYPE)/carla-host-plugin.cpp.o | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_engine_plugin.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_plugin.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/native-plugins.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/audio_decoder.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/jackbridge.min.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/lilv.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/rtmempool.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/sfzero.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/water.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/ysfx.a | |||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/zita-resampler.a | |||
# -------------------------------------------------------------- | |||
# Import base definitions | |||
USE_NANOVG_FBO = true | |||
include ../../dpf/Makefile.base.mk | |||
# -------------------------------------------------------------- | |||
# Build config | |||
PREFIX ?= /usr/local | |||
ifeq ($(BSD),true) | |||
SYSDEPS ?= true | |||
else | |||
SYSDEPS ?= false | |||
endif | |||
ifeq ($(SYSDEPS),true) | |||
DEP_LIB_PATH = $(abspath ../../deps/sysroot/lib) | |||
else | |||
DEP_LIB_PATH = $(abspath ../Rack/dep/lib) | |||
endif | |||
# -------------------------------------------------------------- | |||
# Extra libraries to link against | |||
RACK_EXTRA_LIBS = ../../plugins/plugins.a | |||
RACK_EXTRA_LIBS += ../rack.a | |||
RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libquickjs.a | |||
ifneq ($(SYSDEPS),true) | |||
RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libjansson.a | |||
RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libsamplerate.a | |||
RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libspeexdsp.a | |||
ifeq ($(WINDOWS),true) | |||
RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libarchive_static.a | |||
else | |||
RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libarchive.a | |||
endif | |||
RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libzstd.a | |||
endif | |||
# -------------------------------------------------------------- | |||
EXTRA_DEPENDENCIES = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) | |||
EXTRA_LIBS = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) $(STATIC_CARLA_PLUGIN_LIBS) | |||
ifeq ($(shell pkg-config --exists fftw3f && echo true),true) | |||
EXTRA_DEPENDENCIES += ../../deps/aubio/libaubio.a | |||
EXTRA_LIBS += ../../deps/aubio/libaubio.a | |||
EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs fftw3f) | |||
endif | |||
# -------------------------------------------------------------- | |||
# Extra flags for liblo | |||
BASE_FLAGS += -DHAVE_LIBLO | |||
BASE_FLAGS += $(LIBLO_FLAGS) | |||
LINK_FLAGS += $(LIBLO_LIBS) | |||
# -------------------------------------------------------------- | |||
# Extra flags for VCV stuff | |||
ifeq ($(MACOS),true) | |||
BASE_FLAGS += -DARCH_MAC | |||
else ifeq ($(WINDOWS),true) | |||
BASE_FLAGS += -DARCH_WIN | |||
else | |||
BASE_FLAGS += -DARCH_LIN | |||
endif | |||
BASE_FLAGS += -DPRIVATE= | |||
BASE_FLAGS += -I.. | |||
BASE_FLAGS += -I../../dpf/dgl/src/nanovg | |||
BASE_FLAGS += -I../../include | |||
BASE_FLAGS += -I../../include/neon-compat | |||
BASE_FLAGS += -I../Rack/include | |||
ifeq ($(SYSDEPS),true) | |||
BASE_FLAGS += -DCARDINAL_SYSDEPS | |||
BASE_FLAGS += $(shell pkg-config --cflags jansson libarchive samplerate speexdsp) | |||
else | |||
BASE_FLAGS += -DZSTDLIB_VISIBILITY= | |||
BASE_FLAGS += -I../Rack/dep/include | |||
endif | |||
BASE_FLAGS += -I../Rack/dep/glfw/include | |||
BASE_FLAGS += -I../Rack/dep/nanosvg/src | |||
BASE_FLAGS += -I../Rack/dep/oui-blendish | |||
ifeq ($(WASM),true) | |||
BASE_FLAGS += -DNANOVG_GLES2=1 | |||
BASE_FLAGS += -msse -msse2 -msse3 -msimd128 | |||
else ifneq ($(HAIKU),true) | |||
BASE_FLAGS += -pthread | |||
endif | |||
ifeq ($(WINDOWS),true) | |||
BASE_FLAGS += -D_USE_MATH_DEFINES | |||
BASE_FLAGS += -DWIN32_LEAN_AND_MEAN | |||
BASE_FLAGS += -I../../include/mingw-compat | |||
BASE_FLAGS += -I../../include/mingw-std-threads | |||
endif | |||
BUILD_C_FLAGS += -std=gnu11 | |||
BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing | |||
BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing | |||
ifneq ($(MACOS),true) | |||
BUILD_CXX_FLAGS += -faligned-new -Wno-abi | |||
endif | |||
# Rack code is not tested for this flag, unset it | |||
BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | |||
# -------------------------------------------------------------- | |||
# FIXME lots of warnings from VCV side | |||
BASE_FLAGS += -Wno-unused-parameter | |||
BASE_FLAGS += -Wno-unused-variable | |||
# -------------------------------------------------------------- | |||
# extra linker flags | |||
ifeq ($(HAIKU),true) | |||
LINK_FLAGS += -lpthread | |||
else | |||
LINK_FLAGS += -pthread | |||
endif | |||
ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | |||
ifneq ($(STATIC_BUILD),true) | |||
LINK_FLAGS += -ldl | |||
endif | |||
endif | |||
ifeq ($(BSD),true) | |||
ifeq ($(DEBUG),true) | |||
LINK_FLAGS += -lexecinfo | |||
endif | |||
endif | |||
ifeq ($(MACOS),true) | |||
LINK_FLAGS += -framework IOKit | |||
else ifeq ($(WINDOWS),true) | |||
# needed by VCVRack | |||
EXTRA_LIBS += -ldbghelp -lshlwapi -Wl,--stack,0x100000 | |||
# needed by JW-Modules | |||
EXTRA_LIBS += -lws2_32 -lwinmm | |||
endif | |||
ifeq ($(SYSDEPS),true) | |||
EXTRA_LIBS += $(shell pkg-config --libs jansson libarchive samplerate speexdsp) | |||
endif | |||
ifeq ($(WITH_LTO),true) | |||
# false positive | |||
LINK_FLAGS += -Wno-alloc-size-larger-than | |||
ifneq ($(SYSDEPS),true) | |||
# triggered by jansson | |||
LINK_FLAGS += -Wno-stringop-overflow | |||
endif | |||
endif | |||
# -------------------------------------------------------------- | |||
# fallback path to resource files | |||
ifneq ($(CIBUILD),true) | |||
ifneq ($(SYSDEPS),true) | |||
ifeq ($(EXE_WRAPPER),wine) | |||
SOURCE_DIR = Z:$(subst /,\\,$(abspath $(CURDIR)/..)) | |||
else | |||
SOURCE_DIR = $(abspath $(CURDIR)/..) | |||
endif | |||
BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_SOURCE_DIR='"$(SOURCE_DIR)"' | |||
endif | |||
endif | |||
# -------------------------------------------------------------- | |||
# install path prefix for resource files | |||
BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_PREFIX='"$(PREFIX)"' | |||
# -------------------------------------------------------------- | |||
# Files to build | |||
FILES = main.cpp | |||
FILES += RemoteUI.cpp | |||
FILES += CardinalCommon.cpp | |||
FILES += common.cpp | |||
FILES += glfw.cpp | |||
FILES += Window.cpp | |||
ifeq ($(WINDOWS),true) | |||
FILES += distrho.rc | |||
endif | |||
# -------------------------------------------------------------- | |||
# Build setup | |||
TARGET_DIR = ../../bin | |||
BUILD_DIR = ../../build/CardinalRemote | |||
DPF_PATH = ../../dpf | |||
DGL_FLAGS += -DDGL_OPENGL -DHAVE_DGL | |||
DGL_FLAGS += $(OPENGL_FLAGS) | |||
DGL_LIBS += $(OPENGL_LIBS) | |||
DGL_LIBS += $(DGL_SYSTEM_LIBS) -lm | |||
DGL_LIB = $(DPF_PATH)/build/libdgl-opengl.a | |||
BUILD_C_FLAGS += -I. | |||
BUILD_CXX_FLAGS += -I. -I$(DPF_PATH)/distrho -I$(DPF_PATH)/dgl | |||
OBJS = $(FILES:%=$(BUILD_DIR)/%.o) | |||
all: $(TARGET_DIR)/CardinalRemote$(APP_EXT) | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
$(TARGET_DIR)/CardinalRemote$(APP_EXT): $(OBJS) $(DGL_LIB) | |||
-@mkdir -p $(shell dirname $@) | |||
@echo "Linking CardinalRemote" | |||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(JACK_LIBS) -o $@ | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Common | |||
$(BUILD_DIR)/%.S.o: %.S | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
@$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.c.o: %.c | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.cc.o: %.cc | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.cpp.o: %.cpp | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
# -------------------------------------------------------------- | |||
# Extra rules for Windows icon | |||
ifeq ($(WINDOWS),true) | |||
JACK_LIBS += -Wl,-subsystem,windows | |||
$(BUILD_DIR)/distrho.rc.o: ../../utils/distrho.rc ../../utils/distrho.ico | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling distrho.rc" | |||
$(SILENT)$(WINDRES) $< -O coff -o $@ | |||
endif |
@@ -0,0 +1,91 @@ | |||
/* | |||
* DISTRHO Cardinal Plugin | |||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 3 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the LICENSE file. | |||
*/ | |||
#include "RemoteUI.hpp" | |||
// #include <asset.hpp> | |||
// #include <random.hpp> | |||
#include <patch.hpp> | |||
#include <settings.hpp> | |||
#include <system.hpp> | |||
#include <app/Scene.hpp> | |||
#include <engine/Engine.hpp> | |||
CardinalRemoteUI::CardinalRemoteUI(Window& window, const std::string& templatePath) | |||
: NanoTopLevelWidget(window), | |||
context(nullptr) | |||
{ | |||
// create unique temporary path for this instance | |||
try { | |||
char uidBuf[24]; | |||
const std::string tmp = rack::system::getTempDirectory(); | |||
for (int i=1;; ++i) | |||
{ | |||
std::snprintf(uidBuf, sizeof(uidBuf), "CardinalRemote.%04d", i); | |||
const std::string trypath = rack::system::join(tmp, uidBuf); | |||
if (! rack::system::exists(trypath)) | |||
{ | |||
if (rack::system::createDirectories(trypath)) | |||
autosavePath = trypath; | |||
break; | |||
} | |||
} | |||
} DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | |||
rack::contextSet(&context); | |||
context.bufferSize = 512; | |||
rack::settings::sampleRate = context.sampleRate = 48000; | |||
context.engine = new rack::engine::Engine; | |||
context.engine->setSampleRate(context.sampleRate); | |||
context.history = new rack::history::State; | |||
context.patch = new rack::patch::Manager; | |||
context.patch->autosavePath = autosavePath; | |||
context.patch->templatePath = templatePath; | |||
context.event = new rack::widget::EventState; | |||
context.scene = new rack::app::Scene; | |||
context.event->rootWidget = context.scene; | |||
context.window = new rack::window::Window; | |||
context.patch->loadTemplate(); | |||
context.scene->rackScroll->reset(); | |||
context.nativeWindowId = getWindow().getNativeWindowHandle(); | |||
} | |||
CardinalRemoteUI::~CardinalRemoteUI() | |||
{ | |||
rack::contextSet(&context); | |||
context.nativeWindowId = 0; | |||
context.patch->clear(); | |||
if (! autosavePath.empty()) | |||
rack::system::removeRecursively(autosavePath); | |||
} | |||
void CardinalRemoteUI::onNanoDisplay() | |||
{ | |||
rack::contextSet(&context); | |||
context.window->step(); | |||
} |
@@ -0,0 +1,36 @@ | |||
/* | |||
* DISTRHO Cardinal Plugin | |||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 3 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the LICENSE file. | |||
*/ | |||
#pragma once | |||
#include "NanoVG.hpp" | |||
#include "PluginContext.hpp" | |||
class CardinalRemoteUI : public NanoTopLevelWidget | |||
{ | |||
CardinalPluginContext context; | |||
std::string autosavePath; | |||
public: | |||
explicit CardinalRemoteUI(Window& window, const std::string& templatePath); | |||
~CardinalRemoteUI() override; | |||
protected: | |||
void onNanoDisplay() override; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CardinalRemoteUI) | |||
}; |
@@ -0,0 +1 @@ | |||
../override/Window.cpp |
@@ -0,0 +1 @@ | |||
../override/common.cpp |
@@ -0,0 +1 @@ | |||
../custom/glfw.cpp |
@@ -0,0 +1,160 @@ | |||
/* | |||
* DISTRHO Cardinal Plugin | |||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 3 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the LICENSE file. | |||
*/ | |||
#include "Application.hpp" | |||
#include "Window.hpp" | |||
#include "RemoteUI.hpp" | |||
#include <asset.hpp> | |||
#include <random.hpp> | |||
#include <settings.hpp> | |||
#include <system.hpp> | |||
#include <app/Browser.hpp> | |||
#include <ui/common.hpp> | |||
namespace rack { | |||
namespace plugin { | |||
void initStaticPlugins(); | |||
void destroyStaticPlugins(); | |||
} | |||
} | |||
int main(const int argc, const char* argv[]) | |||
{ | |||
using namespace rack; | |||
settings::allowCursorLock = false; | |||
settings::autoCheckUpdates = false; | |||
settings::autosaveInterval = 0; | |||
settings::devMode = true; | |||
settings::discordUpdateActivity = false; | |||
settings::isPlugin = true; | |||
settings::skipLoadOnLaunch = true; | |||
settings::showTipsOnLaunch = false; | |||
settings::windowPos = math::Vec(0, 0); | |||
// copied from https://community.vcvrack.com/t/16-colour-cable-palette/15951 | |||
settings::cableColors = { | |||
color::fromHexString("#ff5252"), | |||
color::fromHexString("#ff9352"), | |||
color::fromHexString("#ffd452"), | |||
color::fromHexString("#e8ff52"), | |||
color::fromHexString("#a8ff52"), | |||
color::fromHexString("#67ff52"), | |||
color::fromHexString("#52ff7d"), | |||
color::fromHexString("#52ffbe"), | |||
color::fromHexString("#52ffff"), | |||
color::fromHexString("#52beff"), | |||
color::fromHexString("#527dff"), | |||
color::fromHexString("#6752ff"), | |||
color::fromHexString("#a852ff"), | |||
color::fromHexString("#e952ff"), | |||
color::fromHexString("#ff52d4"), | |||
color::fromHexString("#ff5293"), | |||
}; | |||
system::init(); | |||
logger::init(); | |||
random::init(); | |||
ui::init(); | |||
std::string templatePath; | |||
#ifdef CARDINAL_PLUGIN_SOURCE_DIR | |||
// Make system dir point to source code location as fallback | |||
asset::systemDir = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "Rack"; | |||
if (system::exists(system::join(asset::systemDir, "res"))) | |||
{ | |||
templatePath = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "template.vcv"; | |||
} | |||
// If source code dir does not exist use install target prefix as system dir | |||
else | |||
#endif | |||
{ | |||
#if defined(ARCH_MAC) | |||
asset::systemDir = "/Library/Application Support/Cardinal"; | |||
#elif defined(ARCH_WIN) | |||
const std::string commonprogfiles = getSpecialPath(kSpecialPathCommonProgramFiles); | |||
if (! commonprogfiles.empty()) | |||
asset::systemDir = system::join(commonprogfiles, "Cardinal"); | |||
#else | |||
asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; | |||
#endif | |||
if (! asset::systemDir.empty()) | |||
{ | |||
asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | |||
templatePath = system::join(asset::systemDir, "template.vcv"); | |||
} | |||
} | |||
asset::userDir = asset::systemDir; | |||
// Log environment | |||
INFO("%s %s v%s", APP_NAME.c_str(), APP_EDITION.c_str(), APP_VERSION.c_str()); | |||
INFO("%s", system::getOperatingSystemInfo().c_str()); | |||
// INFO("Binary filename: %s", getBinaryFilename()); | |||
INFO("System directory: %s", asset::systemDir.c_str()); | |||
INFO("User directory: %s", asset::userDir.c_str()); | |||
INFO("Template patch: %s", templatePath.c_str()); | |||
// Report to user if something is wrong with the installation | |||
if (asset::systemDir.empty()) | |||
{ | |||
d_stderr2("Failed to locate Cardinal plugin bundle.\n" | |||
"Install Cardinal with its bundle folder intact and try again."); | |||
} | |||
else if (! system::exists(asset::systemDir)) | |||
{ | |||
d_stderr2("System directory \"%s\" does not exist.\n" | |||
"Make sure Cardinal was downloaded and installed correctly.", asset::systemDir.c_str()); | |||
} | |||
INFO("Initializing plugins"); | |||
plugin::initStaticPlugins(); | |||
INFO("Initializing plugin browser DB"); | |||
app::browserInit(); | |||
Application app; | |||
Window win(app); | |||
win.setTitle("CardinalRemote"); | |||
ScopedPointer<CardinalRemoteUI> remoteUI; | |||
{ | |||
remoteUI = new CardinalRemoteUI(win, templatePath); | |||
} | |||
app.exec(); | |||
INFO("Clearing asset paths"); | |||
asset::bundlePath.clear(); | |||
asset::systemDir.clear(); | |||
asset::userDir.clear(); | |||
INFO("Destroying plugins"); | |||
plugin::destroyStaticPlugins(); | |||
INFO("Destroying settings"); | |||
settings::destroy(); | |||
INFO("Destroying logger"); | |||
logger::destroy(); | |||
return 0; | |||
} |