Преглед изворни кода

:building_construction: add grpc client libraries

Jeremy Zheng пре 2 година
родитељ
комит
f5c47a8343

+ 90 - 0
clients/cpp/morus.grpc.pb.cc

@@ -0,0 +1,90 @@
+// Generated by the gRPC C++ plugin.
+// If you make any local change, they will be lost.
+// source: morus.proto
+
+#include "morus.pb.h"
+#include "morus.grpc.pb.h"
+
+#include <functional>
+#include <grpcpp/support/async_stream.h>
+#include <grpcpp/support/async_unary_call.h>
+#include <grpcpp/impl/channel_interface.h>
+#include <grpcpp/impl/client_unary_call.h>
+#include <grpcpp/support/client_callback.h>
+#include <grpcpp/support/message_allocator.h>
+#include <grpcpp/support/method_handler.h>
+#include <grpcpp/impl/rpc_service_method.h>
+#include <grpcpp/support/server_callback.h>
+#include <grpcpp/impl/server_callback_handlers.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/impl/service_type.h>
+#include <grpcpp/support/sync_stream.h>
+namespace mint {
+namespace morus {
+namespace v1 {
+
+static const char* Markdown_method_names[] = {
+  "/mint.morus.v1.Markdown/ToHtml",
+};
+
+std::unique_ptr< Markdown::Stub> Markdown::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) {
+  (void)options;
+  std::unique_ptr< Markdown::Stub> stub(new Markdown::Stub(channel, options));
+  return stub;
+}
+
+Markdown::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options)
+  : channel_(channel), rpcmethod_ToHtml_(Markdown_method_names[0], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel)
+  {}
+
+::grpc::Status Markdown::Stub::ToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::mint::morus::v1::MarkdownToHtmlResponse* response) {
+  return ::grpc::internal::BlockingUnaryCall< ::mint::morus::v1::MarkdownToHtmlRequest, ::mint::morus::v1::MarkdownToHtmlResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_ToHtml_, context, request, response);
+}
+
+void Markdown::Stub::async::ToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest* request, ::mint::morus::v1::MarkdownToHtmlResponse* response, std::function<void(::grpc::Status)> f) {
+  ::grpc::internal::CallbackUnaryCall< ::mint::morus::v1::MarkdownToHtmlRequest, ::mint::morus::v1::MarkdownToHtmlResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_ToHtml_, context, request, response, std::move(f));
+}
+
+void Markdown::Stub::async::ToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest* request, ::mint::morus::v1::MarkdownToHtmlResponse* response, ::grpc::ClientUnaryReactor* reactor) {
+  ::grpc::internal::ClientCallbackUnaryFactory::Create< ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_ToHtml_, context, request, response, reactor);
+}
+
+::grpc::ClientAsyncResponseReader< ::mint::morus::v1::MarkdownToHtmlResponse>* Markdown::Stub::PrepareAsyncToHtmlRaw(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) {
+  return ::grpc::internal::ClientAsyncResponseReaderHelper::Create< ::mint::morus::v1::MarkdownToHtmlResponse, ::mint::morus::v1::MarkdownToHtmlRequest, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), cq, rpcmethod_ToHtml_, context, request);
+}
+
+::grpc::ClientAsyncResponseReader< ::mint::morus::v1::MarkdownToHtmlResponse>* Markdown::Stub::AsyncToHtmlRaw(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) {
+  auto* result =
+    this->PrepareAsyncToHtmlRaw(context, request, cq);
+  result->StartCall();
+  return result;
+}
+
+Markdown::Service::Service() {
+  AddMethod(new ::grpc::internal::RpcServiceMethod(
+      Markdown_method_names[0],
+      ::grpc::internal::RpcMethod::NORMAL_RPC,
+      new ::grpc::internal::RpcMethodHandler< Markdown::Service, ::mint::morus::v1::MarkdownToHtmlRequest, ::mint::morus::v1::MarkdownToHtmlResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(
+          [](Markdown::Service* service,
+             ::grpc::ServerContext* ctx,
+             const ::mint::morus::v1::MarkdownToHtmlRequest* req,
+             ::mint::morus::v1::MarkdownToHtmlResponse* resp) {
+               return service->ToHtml(ctx, req, resp);
+             }, this)));
+}
+
+Markdown::Service::~Service() {
+}
+
+::grpc::Status Markdown::Service::ToHtml(::grpc::ServerContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest* request, ::mint::morus::v1::MarkdownToHtmlResponse* response) {
+  (void) context;
+  (void) request;
+  (void) response;
+  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+}
+
+
+}  // namespace mint
+}  // namespace morus
+}  // namespace v1
+

+ 245 - 0
clients/cpp/morus.grpc.pb.h

@@ -0,0 +1,245 @@
+// Generated by the gRPC C++ plugin.
+// If you make any local change, they will be lost.
+// source: morus.proto
+#ifndef GRPC_morus_2eproto__INCLUDED
+#define GRPC_morus_2eproto__INCLUDED
+
+#include "morus.pb.h"
+
+#include <functional>
+#include <grpcpp/generic/async_generic_service.h>
+#include <grpcpp/support/async_stream.h>
+#include <grpcpp/support/async_unary_call.h>
+#include <grpcpp/support/client_callback.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/support/message_allocator.h>
+#include <grpcpp/support/method_handler.h>
+#include <grpcpp/impl/proto_utils.h>
+#include <grpcpp/impl/rpc_method.h>
+#include <grpcpp/support/server_callback.h>
+#include <grpcpp/impl/server_callback_handlers.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/impl/service_type.h>
+#include <grpcpp/support/status.h>
+#include <grpcpp/support/stub_options.h>
+#include <grpcpp/support/sync_stream.h>
+
+namespace mint {
+namespace morus {
+namespace v1 {
+
+// ----------------------------------------------------------------------------
+class Markdown final {
+ public:
+  static constexpr char const* service_full_name() {
+    return "mint.morus.v1.Markdown";
+  }
+  class StubInterface {
+   public:
+    virtual ~StubInterface() {}
+    virtual ::grpc::Status ToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::mint::morus::v1::MarkdownToHtmlResponse* response) = 0;
+    std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::mint::morus::v1::MarkdownToHtmlResponse>> AsyncToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) {
+      return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::mint::morus::v1::MarkdownToHtmlResponse>>(AsyncToHtmlRaw(context, request, cq));
+    }
+    std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::mint::morus::v1::MarkdownToHtmlResponse>> PrepareAsyncToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) {
+      return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::mint::morus::v1::MarkdownToHtmlResponse>>(PrepareAsyncToHtmlRaw(context, request, cq));
+    }
+    class async_interface {
+     public:
+      virtual ~async_interface() {}
+      virtual void ToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest* request, ::mint::morus::v1::MarkdownToHtmlResponse* response, std::function<void(::grpc::Status)>) = 0;
+      virtual void ToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest* request, ::mint::morus::v1::MarkdownToHtmlResponse* response, ::grpc::ClientUnaryReactor* reactor) = 0;
+    };
+    typedef class async_interface experimental_async_interface;
+    virtual class async_interface* async() { return nullptr; }
+    class async_interface* experimental_async() { return async(); }
+   private:
+    virtual ::grpc::ClientAsyncResponseReaderInterface< ::mint::morus::v1::MarkdownToHtmlResponse>* AsyncToHtmlRaw(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) = 0;
+    virtual ::grpc::ClientAsyncResponseReaderInterface< ::mint::morus::v1::MarkdownToHtmlResponse>* PrepareAsyncToHtmlRaw(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) = 0;
+  };
+  class Stub final : public StubInterface {
+   public:
+    Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
+    ::grpc::Status ToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::mint::morus::v1::MarkdownToHtmlResponse* response) override;
+    std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::mint::morus::v1::MarkdownToHtmlResponse>> AsyncToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) {
+      return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::mint::morus::v1::MarkdownToHtmlResponse>>(AsyncToHtmlRaw(context, request, cq));
+    }
+    std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::mint::morus::v1::MarkdownToHtmlResponse>> PrepareAsyncToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) {
+      return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::mint::morus::v1::MarkdownToHtmlResponse>>(PrepareAsyncToHtmlRaw(context, request, cq));
+    }
+    class async final :
+      public StubInterface::async_interface {
+     public:
+      void ToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest* request, ::mint::morus::v1::MarkdownToHtmlResponse* response, std::function<void(::grpc::Status)>) override;
+      void ToHtml(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest* request, ::mint::morus::v1::MarkdownToHtmlResponse* response, ::grpc::ClientUnaryReactor* reactor) override;
+     private:
+      friend class Stub;
+      explicit async(Stub* stub): stub_(stub) { }
+      Stub* stub() { return stub_; }
+      Stub* stub_;
+    };
+    class async* async() override { return &async_stub_; }
+
+   private:
+    std::shared_ptr< ::grpc::ChannelInterface> channel_;
+    class async async_stub_{this};
+    ::grpc::ClientAsyncResponseReader< ::mint::morus::v1::MarkdownToHtmlResponse>* AsyncToHtmlRaw(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) override;
+    ::grpc::ClientAsyncResponseReader< ::mint::morus::v1::MarkdownToHtmlResponse>* PrepareAsyncToHtmlRaw(::grpc::ClientContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest& request, ::grpc::CompletionQueue* cq) override;
+    const ::grpc::internal::RpcMethod rpcmethod_ToHtml_;
+  };
+  static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
+
+  class Service : public ::grpc::Service {
+   public:
+    Service();
+    virtual ~Service();
+    virtual ::grpc::Status ToHtml(::grpc::ServerContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest* request, ::mint::morus::v1::MarkdownToHtmlResponse* response);
+  };
+  template <class BaseClass>
+  class WithAsyncMethod_ToHtml : public BaseClass {
+   private:
+    void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
+   public:
+    WithAsyncMethod_ToHtml() {
+      ::grpc::Service::MarkMethodAsync(0);
+    }
+    ~WithAsyncMethod_ToHtml() override {
+      BaseClassMustBeDerivedFromService(this);
+    }
+    // disable synchronous version of this method
+    ::grpc::Status ToHtml(::grpc::ServerContext* /*context*/, const ::mint::morus::v1::MarkdownToHtmlRequest* /*request*/, ::mint::morus::v1::MarkdownToHtmlResponse* /*response*/) override {
+      abort();
+      return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+    }
+    void RequestToHtml(::grpc::ServerContext* context, ::mint::morus::v1::MarkdownToHtmlRequest* request, ::grpc::ServerAsyncResponseWriter< ::mint::morus::v1::MarkdownToHtmlResponse>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+      ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag);
+    }
+  };
+  typedef WithAsyncMethod_ToHtml<Service > AsyncService;
+  template <class BaseClass>
+  class WithCallbackMethod_ToHtml : public BaseClass {
+   private:
+    void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
+   public:
+    WithCallbackMethod_ToHtml() {
+      ::grpc::Service::MarkMethodCallback(0,
+          new ::grpc::internal::CallbackUnaryHandler< ::mint::morus::v1::MarkdownToHtmlRequest, ::mint::morus::v1::MarkdownToHtmlResponse>(
+            [this](
+                   ::grpc::CallbackServerContext* context, const ::mint::morus::v1::MarkdownToHtmlRequest* request, ::mint::morus::v1::MarkdownToHtmlResponse* response) { return this->ToHtml(context, request, response); }));}
+    void SetMessageAllocatorFor_ToHtml(
+        ::grpc::MessageAllocator< ::mint::morus::v1::MarkdownToHtmlRequest, ::mint::morus::v1::MarkdownToHtmlResponse>* allocator) {
+      ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(0);
+      static_cast<::grpc::internal::CallbackUnaryHandler< ::mint::morus::v1::MarkdownToHtmlRequest, ::mint::morus::v1::MarkdownToHtmlResponse>*>(handler)
+              ->SetMessageAllocator(allocator);
+    }
+    ~WithCallbackMethod_ToHtml() override {
+      BaseClassMustBeDerivedFromService(this);
+    }
+    // disable synchronous version of this method
+    ::grpc::Status ToHtml(::grpc::ServerContext* /*context*/, const ::mint::morus::v1::MarkdownToHtmlRequest* /*request*/, ::mint::morus::v1::MarkdownToHtmlResponse* /*response*/) override {
+      abort();
+      return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+    }
+    virtual ::grpc::ServerUnaryReactor* ToHtml(
+      ::grpc::CallbackServerContext* /*context*/, const ::mint::morus::v1::MarkdownToHtmlRequest* /*request*/, ::mint::morus::v1::MarkdownToHtmlResponse* /*response*/)  { return nullptr; }
+  };
+  typedef WithCallbackMethod_ToHtml<Service > CallbackService;
+  typedef CallbackService ExperimentalCallbackService;
+  template <class BaseClass>
+  class WithGenericMethod_ToHtml : public BaseClass {
+   private:
+    void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
+   public:
+    WithGenericMethod_ToHtml() {
+      ::grpc::Service::MarkMethodGeneric(0);
+    }
+    ~WithGenericMethod_ToHtml() override {
+      BaseClassMustBeDerivedFromService(this);
+    }
+    // disable synchronous version of this method
+    ::grpc::Status ToHtml(::grpc::ServerContext* /*context*/, const ::mint::morus::v1::MarkdownToHtmlRequest* /*request*/, ::mint::morus::v1::MarkdownToHtmlResponse* /*response*/) override {
+      abort();
+      return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+    }
+  };
+  template <class BaseClass>
+  class WithRawMethod_ToHtml : public BaseClass {
+   private:
+    void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
+   public:
+    WithRawMethod_ToHtml() {
+      ::grpc::Service::MarkMethodRaw(0);
+    }
+    ~WithRawMethod_ToHtml() override {
+      BaseClassMustBeDerivedFromService(this);
+    }
+    // disable synchronous version of this method
+    ::grpc::Status ToHtml(::grpc::ServerContext* /*context*/, const ::mint::morus::v1::MarkdownToHtmlRequest* /*request*/, ::mint::morus::v1::MarkdownToHtmlResponse* /*response*/) override {
+      abort();
+      return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+    }
+    void RequestToHtml(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+      ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag);
+    }
+  };
+  template <class BaseClass>
+  class WithRawCallbackMethod_ToHtml : public BaseClass {
+   private:
+    void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
+   public:
+    WithRawCallbackMethod_ToHtml() {
+      ::grpc::Service::MarkMethodRawCallback(0,
+          new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
+            [this](
+                   ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->ToHtml(context, request, response); }));
+    }
+    ~WithRawCallbackMethod_ToHtml() override {
+      BaseClassMustBeDerivedFromService(this);
+    }
+    // disable synchronous version of this method
+    ::grpc::Status ToHtml(::grpc::ServerContext* /*context*/, const ::mint::morus::v1::MarkdownToHtmlRequest* /*request*/, ::mint::morus::v1::MarkdownToHtmlResponse* /*response*/) override {
+      abort();
+      return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+    }
+    virtual ::grpc::ServerUnaryReactor* ToHtml(
+      ::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/)  { return nullptr; }
+  };
+  template <class BaseClass>
+  class WithStreamedUnaryMethod_ToHtml : public BaseClass {
+   private:
+    void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
+   public:
+    WithStreamedUnaryMethod_ToHtml() {
+      ::grpc::Service::MarkMethodStreamed(0,
+        new ::grpc::internal::StreamedUnaryHandler<
+          ::mint::morus::v1::MarkdownToHtmlRequest, ::mint::morus::v1::MarkdownToHtmlResponse>(
+            [this](::grpc::ServerContext* context,
+                   ::grpc::ServerUnaryStreamer<
+                     ::mint::morus::v1::MarkdownToHtmlRequest, ::mint::morus::v1::MarkdownToHtmlResponse>* streamer) {
+                       return this->StreamedToHtml(context,
+                         streamer);
+                  }));
+    }
+    ~WithStreamedUnaryMethod_ToHtml() override {
+      BaseClassMustBeDerivedFromService(this);
+    }
+    // disable regular version of this method
+    ::grpc::Status ToHtml(::grpc::ServerContext* /*context*/, const ::mint::morus::v1::MarkdownToHtmlRequest* /*request*/, ::mint::morus::v1::MarkdownToHtmlResponse* /*response*/) override {
+      abort();
+      return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+    }
+    // replace default version of method with streamed unary
+    virtual ::grpc::Status StreamedToHtml(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::mint::morus::v1::MarkdownToHtmlRequest,::mint::morus::v1::MarkdownToHtmlResponse>* server_unary_streamer) = 0;
+  };
+  typedef WithStreamedUnaryMethod_ToHtml<Service > StreamedUnaryService;
+  typedef Service SplitStreamedService;
+  typedef WithStreamedUnaryMethod_ToHtml<Service > StreamedService;
+};
+
+}  // namespace v1
+}  // namespace morus
+}  // namespace mint
+
+
+#endif  // GRPC_morus_2eproto__INCLUDED

+ 591 - 0
clients/cpp/morus.pb.cc

@@ -0,0 +1,591 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: morus.proto
+
+#include "morus.pb.h"
+
+#include <algorithm>
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/extension_set.h"
+#include "google/protobuf/wire_format_lite.h"
+#include "google/protobuf/descriptor.h"
+#include "google/protobuf/generated_message_reflection.h"
+#include "google/protobuf/reflection_ops.h"
+#include "google/protobuf/wire_format.h"
+// @@protoc_insertion_point(includes)
+
+// Must be included last.
+#include "google/protobuf/port_def.inc"
+PROTOBUF_PRAGMA_INIT_SEG
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = ::PROTOBUF_NAMESPACE_ID::internal;
+namespace mint {
+namespace morus {
+namespace v1 {
+template <typename>
+PROTOBUF_CONSTEXPR MarkdownToHtmlRequest::MarkdownToHtmlRequest(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.payload_)*/ {
+    &::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized {}
+  }
+
+  , /*decltype(_impl_.sanitize_)*/ false
+
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct MarkdownToHtmlRequestDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MarkdownToHtmlRequestDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MarkdownToHtmlRequestDefaultTypeInternal() {}
+  union {
+    MarkdownToHtmlRequest _instance;
+  };
+};
+
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
+    PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MarkdownToHtmlRequestDefaultTypeInternal _MarkdownToHtmlRequest_default_instance_;
+template <typename>
+PROTOBUF_CONSTEXPR MarkdownToHtmlResponse::MarkdownToHtmlResponse(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.payload_)*/ {
+    &::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized {}
+  }
+
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct MarkdownToHtmlResponseDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MarkdownToHtmlResponseDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MarkdownToHtmlResponseDefaultTypeInternal() {}
+  union {
+    MarkdownToHtmlResponse _instance;
+  };
+};
+
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
+    PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MarkdownToHtmlResponseDefaultTypeInternal _MarkdownToHtmlResponse_default_instance_;
+}  // namespace v1
+}  // namespace morus
+}  // namespace mint
+static ::_pb::Metadata file_level_metadata_morus_2eproto[2];
+static constexpr const ::_pb::EnumDescriptor**
+    file_level_enum_descriptors_morus_2eproto = nullptr;
+static constexpr const ::_pb::ServiceDescriptor**
+    file_level_service_descriptors_morus_2eproto = nullptr;
+const ::uint32_t TableStruct_morus_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(
+    protodesc_cold) = {
+    ~0u,  // no _has_bits_
+    PROTOBUF_FIELD_OFFSET(::mint::morus::v1::MarkdownToHtmlRequest, _internal_metadata_),
+    ~0u,  // no _extensions_
+    ~0u,  // no _oneof_case_
+    ~0u,  // no _weak_field_map_
+    ~0u,  // no _inlined_string_donated_
+    ~0u,  // no _split_
+    ~0u,  // no sizeof(Split)
+    PROTOBUF_FIELD_OFFSET(::mint::morus::v1::MarkdownToHtmlRequest, _impl_.payload_),
+    PROTOBUF_FIELD_OFFSET(::mint::morus::v1::MarkdownToHtmlRequest, _impl_.sanitize_),
+    ~0u,  // no _has_bits_
+    PROTOBUF_FIELD_OFFSET(::mint::morus::v1::MarkdownToHtmlResponse, _internal_metadata_),
+    ~0u,  // no _extensions_
+    ~0u,  // no _oneof_case_
+    ~0u,  // no _weak_field_map_
+    ~0u,  // no _inlined_string_donated_
+    ~0u,  // no _split_
+    ~0u,  // no sizeof(Split)
+    PROTOBUF_FIELD_OFFSET(::mint::morus::v1::MarkdownToHtmlResponse, _impl_.payload_),
+};
+
+static const ::_pbi::MigrationSchema
+    schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+        { 0, -1, -1, sizeof(::mint::morus::v1::MarkdownToHtmlRequest)},
+        { 10, -1, -1, sizeof(::mint::morus::v1::MarkdownToHtmlResponse)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+    &::mint::morus::v1::_MarkdownToHtmlRequest_default_instance_._instance,
+    &::mint::morus::v1::_MarkdownToHtmlResponse_default_instance_._instance,
+};
+const char descriptor_table_protodef_morus_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+    "\n\013morus.proto\022\rmint.morus.v1\":\n\025Markdown"
+    "ToHtmlRequest\022\017\n\007payload\030\001 \001(\t\022\020\n\010saniti"
+    "ze\030\002 \001(\010\")\n\026MarkdownToHtmlResponse\022\017\n\007pa"
+    "yload\030\001 \001(\t2c\n\010Markdown\022W\n\006ToHtml\022$.mint"
+    ".morus.v1.MarkdownToHtmlRequest\032%.mint.m"
+    "orus.v1.MarkdownToHtmlResponse\"\000B2\n.com."
+    "github.iapt_platform.mint.plugins.morus."
+    "v1P\001b\006proto3"
+};
+static ::absl::once_flag descriptor_table_morus_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_morus_2eproto = {
+    false,
+    false,
+    292,
+    descriptor_table_protodef_morus_2eproto,
+    "morus.proto",
+    &descriptor_table_morus_2eproto_once,
+    nullptr,
+    0,
+    2,
+    schemas,
+    file_default_instances,
+    TableStruct_morus_2eproto::offsets,
+    file_level_metadata_morus_2eproto,
+    file_level_enum_descriptors_morus_2eproto,
+    file_level_service_descriptors_morus_2eproto,
+};
+
+// This function exists to be marked as weak.
+// It can significantly speed up compilation by breaking up LLVM's SCC
+// in the .pb.cc translation units. Large translation units see a
+// reduction of more than 35% of walltime for optimized builds. Without
+// the weak attribute all the messages in the file, including all the
+// vtables and everything they use become part of the same SCC through
+// a cycle like:
+// GetMetadata -> descriptor table -> default instances ->
+//   vtables -> GetMetadata
+// By adding a weak function here we break the connection from the
+// individual vtables back into the descriptor table.
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_morus_2eproto_getter() {
+  return &descriptor_table_morus_2eproto;
+}
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
+static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_morus_2eproto(&descriptor_table_morus_2eproto);
+namespace mint {
+namespace morus {
+namespace v1 {
+// ===================================================================
+
+class MarkdownToHtmlRequest::_Internal {
+ public:
+};
+
+MarkdownToHtmlRequest::MarkdownToHtmlRequest(::PROTOBUF_NAMESPACE_ID::Arena* arena)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena) {
+  SharedCtor(arena);
+  // @@protoc_insertion_point(arena_constructor:mint.morus.v1.MarkdownToHtmlRequest)
+}
+MarkdownToHtmlRequest::MarkdownToHtmlRequest(const MarkdownToHtmlRequest& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  MarkdownToHtmlRequest* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.payload_) {}
+
+    , decltype(_impl_.sanitize_) {}
+
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.payload_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+        _impl_.payload_.Set("", GetArenaForAllocation());
+  #endif  // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_payload().empty()) {
+    _this->_impl_.payload_.Set(from._internal_payload(), _this->GetArenaForAllocation());
+  }
+  _this->_impl_.sanitize_ = from._impl_.sanitize_;
+  // @@protoc_insertion_point(copy_constructor:mint.morus.v1.MarkdownToHtmlRequest)
+}
+
+inline void MarkdownToHtmlRequest::SharedCtor(::_pb::Arena* arena) {
+  (void)arena;
+  new (&_impl_) Impl_{
+      decltype(_impl_.payload_) {}
+
+    , decltype(_impl_.sanitize_) { false }
+
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.payload_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+        _impl_.payload_.Set("", GetArenaForAllocation());
+  #endif  // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+MarkdownToHtmlRequest::~MarkdownToHtmlRequest() {
+  // @@protoc_insertion_point(destructor:mint.morus.v1.MarkdownToHtmlRequest)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void MarkdownToHtmlRequest::SharedDtor() {
+  ABSL_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.payload_.Destroy();
+}
+
+void MarkdownToHtmlRequest::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void MarkdownToHtmlRequest::Clear() {
+// @@protoc_insertion_point(message_clear_start:mint.morus.v1.MarkdownToHtmlRequest)
+  ::uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.payload_.ClearToEmpty();
+  _impl_.sanitize_ = false;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* MarkdownToHtmlRequest::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    ::uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string payload = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_payload();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "mint.morus.v1.MarkdownToHtmlRequest.payload"));
+        } else {
+          goto handle_unusual;
+        }
+        continue;
+      // bool sanitize = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 16)) {
+          _impl_.sanitize_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else {
+          goto handle_unusual;
+        }
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+::uint8_t* MarkdownToHtmlRequest::_InternalSerialize(
+    ::uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:mint.morus.v1.MarkdownToHtmlRequest)
+  ::uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string payload = 1;
+  if (!this->_internal_payload().empty()) {
+    const std::string& _s = this->_internal_payload();
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+        _s.data(), static_cast<int>(_s.length()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, "mint.morus.v1.MarkdownToHtmlRequest.payload");
+    target = stream->WriteStringMaybeAliased(1, _s, target);
+  }
+
+  // bool sanitize = 2;
+  if (this->_internal_sanitize() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(
+        2, this->_internal_sanitize(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:mint.morus.v1.MarkdownToHtmlRequest)
+  return target;
+}
+
+::size_t MarkdownToHtmlRequest::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:mint.morus.v1.MarkdownToHtmlRequest)
+  ::size_t total_size = 0;
+
+  ::uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string payload = 1;
+  if (!this->_internal_payload().empty()) {
+    total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+                                    this->_internal_payload());
+  }
+
+  // bool sanitize = 2;
+  if (this->_internal_sanitize() != 0) {
+    total_size += 2;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MarkdownToHtmlRequest::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    MarkdownToHtmlRequest::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MarkdownToHtmlRequest::GetClassData() const { return &_class_data_; }
+
+
+void MarkdownToHtmlRequest::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<MarkdownToHtmlRequest*>(&to_msg);
+  auto& from = static_cast<const MarkdownToHtmlRequest&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:mint.morus.v1.MarkdownToHtmlRequest)
+  ABSL_DCHECK_NE(&from, _this);
+  ::uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_payload().empty()) {
+    _this->_internal_set_payload(from._internal_payload());
+  }
+  if (from._internal_sanitize() != 0) {
+    _this->_internal_set_sanitize(from._internal_sanitize());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void MarkdownToHtmlRequest::CopyFrom(const MarkdownToHtmlRequest& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:mint.morus.v1.MarkdownToHtmlRequest)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool MarkdownToHtmlRequest::IsInitialized() const {
+  return true;
+}
+
+void MarkdownToHtmlRequest::InternalSwap(MarkdownToHtmlRequest* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.payload_, lhs_arena,
+                                       &other->_impl_.payload_, rhs_arena);
+
+  swap(_impl_.sanitize_, other->_impl_.sanitize_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata MarkdownToHtmlRequest::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_morus_2eproto_getter, &descriptor_table_morus_2eproto_once,
+      file_level_metadata_morus_2eproto[0]);
+}
+// ===================================================================
+
+class MarkdownToHtmlResponse::_Internal {
+ public:
+};
+
+MarkdownToHtmlResponse::MarkdownToHtmlResponse(::PROTOBUF_NAMESPACE_ID::Arena* arena)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena) {
+  SharedCtor(arena);
+  // @@protoc_insertion_point(arena_constructor:mint.morus.v1.MarkdownToHtmlResponse)
+}
+MarkdownToHtmlResponse::MarkdownToHtmlResponse(const MarkdownToHtmlResponse& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  MarkdownToHtmlResponse* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.payload_) {}
+
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.payload_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+        _impl_.payload_.Set("", GetArenaForAllocation());
+  #endif  // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_payload().empty()) {
+    _this->_impl_.payload_.Set(from._internal_payload(), _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:mint.morus.v1.MarkdownToHtmlResponse)
+}
+
+inline void MarkdownToHtmlResponse::SharedCtor(::_pb::Arena* arena) {
+  (void)arena;
+  new (&_impl_) Impl_{
+      decltype(_impl_.payload_) {}
+
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.payload_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+        _impl_.payload_.Set("", GetArenaForAllocation());
+  #endif  // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+MarkdownToHtmlResponse::~MarkdownToHtmlResponse() {
+  // @@protoc_insertion_point(destructor:mint.morus.v1.MarkdownToHtmlResponse)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void MarkdownToHtmlResponse::SharedDtor() {
+  ABSL_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.payload_.Destroy();
+}
+
+void MarkdownToHtmlResponse::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void MarkdownToHtmlResponse::Clear() {
+// @@protoc_insertion_point(message_clear_start:mint.morus.v1.MarkdownToHtmlResponse)
+  ::uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.payload_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* MarkdownToHtmlResponse::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    ::uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string payload = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_payload();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "mint.morus.v1.MarkdownToHtmlResponse.payload"));
+        } else {
+          goto handle_unusual;
+        }
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+::uint8_t* MarkdownToHtmlResponse::_InternalSerialize(
+    ::uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:mint.morus.v1.MarkdownToHtmlResponse)
+  ::uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string payload = 1;
+  if (!this->_internal_payload().empty()) {
+    const std::string& _s = this->_internal_payload();
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+        _s.data(), static_cast<int>(_s.length()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, "mint.morus.v1.MarkdownToHtmlResponse.payload");
+    target = stream->WriteStringMaybeAliased(1, _s, target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:mint.morus.v1.MarkdownToHtmlResponse)
+  return target;
+}
+
+::size_t MarkdownToHtmlResponse::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:mint.morus.v1.MarkdownToHtmlResponse)
+  ::size_t total_size = 0;
+
+  ::uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string payload = 1;
+  if (!this->_internal_payload().empty()) {
+    total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+                                    this->_internal_payload());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MarkdownToHtmlResponse::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    MarkdownToHtmlResponse::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MarkdownToHtmlResponse::GetClassData() const { return &_class_data_; }
+
+
+void MarkdownToHtmlResponse::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<MarkdownToHtmlResponse*>(&to_msg);
+  auto& from = static_cast<const MarkdownToHtmlResponse&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:mint.morus.v1.MarkdownToHtmlResponse)
+  ABSL_DCHECK_NE(&from, _this);
+  ::uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_payload().empty()) {
+    _this->_internal_set_payload(from._internal_payload());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void MarkdownToHtmlResponse::CopyFrom(const MarkdownToHtmlResponse& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:mint.morus.v1.MarkdownToHtmlResponse)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool MarkdownToHtmlResponse::IsInitialized() const {
+  return true;
+}
+
+void MarkdownToHtmlResponse::InternalSwap(MarkdownToHtmlResponse* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.payload_, lhs_arena,
+                                       &other->_impl_.payload_, rhs_arena);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata MarkdownToHtmlResponse::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_morus_2eproto_getter, &descriptor_table_morus_2eproto_once,
+      file_level_metadata_morus_2eproto[1]);
+}
+// @@protoc_insertion_point(namespace_scope)
+}  // namespace v1
+}  // namespace morus
+}  // namespace mint
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::mint::morus::v1::MarkdownToHtmlRequest*
+Arena::CreateMaybeMessage< ::mint::morus::v1::MarkdownToHtmlRequest >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::mint::morus::v1::MarkdownToHtmlRequest >(arena);
+}
+template<> PROTOBUF_NOINLINE ::mint::morus::v1::MarkdownToHtmlResponse*
+Arena::CreateMaybeMessage< ::mint::morus::v1::MarkdownToHtmlResponse >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::mint::morus::v1::MarkdownToHtmlResponse >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+// @@protoc_insertion_point(global_scope)
+#include "google/protobuf/port_undef.inc"

+ 571 - 0
clients/cpp/morus.pb.h

@@ -0,0 +1,571 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: morus.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_morus_2eproto_2epb_2eh
+#define GOOGLE_PROTOBUF_INCLUDED_morus_2eproto_2epb_2eh
+
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "google/protobuf/port_def.inc"
+#if PROTOBUF_VERSION < 4023000
+#error "This file was generated by a newer version of protoc which is"
+#error "incompatible with your Protocol Buffer headers. Please update"
+#error "your headers."
+#endif  // PROTOBUF_VERSION
+
+#if 4023004 < PROTOBUF_MIN_PROTOC_VERSION
+#error "This file was generated by an older version of protoc which is"
+#error "incompatible with your Protocol Buffer headers. Please"
+#error "regenerate this file with a newer version of protoc."
+#endif  // PROTOBUF_MIN_PROTOC_VERSION
+#include "google/protobuf/port_undef.inc"
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/arena.h"
+#include "google/protobuf/arenastring.h"
+#include "google/protobuf/generated_message_util.h"
+#include "google/protobuf/metadata_lite.h"
+#include "google/protobuf/generated_message_reflection.h"
+#include "google/protobuf/message.h"
+#include "google/protobuf/repeated_field.h"  // IWYU pragma: export
+#include "google/protobuf/extension_set.h"  // IWYU pragma: export
+#include "google/protobuf/unknown_field_set.h"
+// @@protoc_insertion_point(includes)
+
+// Must be included last.
+#include "google/protobuf/port_def.inc"
+
+#define PROTOBUF_INTERNAL_EXPORT_morus_2eproto
+
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct TableStruct_morus_2eproto {
+  static const ::uint32_t offsets[];
+};
+extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable
+    descriptor_table_morus_2eproto;
+namespace mint {
+namespace morus {
+namespace v1 {
+class MarkdownToHtmlRequest;
+struct MarkdownToHtmlRequestDefaultTypeInternal;
+extern MarkdownToHtmlRequestDefaultTypeInternal _MarkdownToHtmlRequest_default_instance_;
+class MarkdownToHtmlResponse;
+struct MarkdownToHtmlResponseDefaultTypeInternal;
+extern MarkdownToHtmlResponseDefaultTypeInternal _MarkdownToHtmlResponse_default_instance_;
+}  // namespace v1
+}  // namespace morus
+}  // namespace mint
+PROTOBUF_NAMESPACE_OPEN
+template <>
+::mint::morus::v1::MarkdownToHtmlRequest* Arena::CreateMaybeMessage<::mint::morus::v1::MarkdownToHtmlRequest>(Arena*);
+template <>
+::mint::morus::v1::MarkdownToHtmlResponse* Arena::CreateMaybeMessage<::mint::morus::v1::MarkdownToHtmlResponse>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+
+namespace mint {
+namespace morus {
+namespace v1 {
+
+// ===================================================================
+
+
+// -------------------------------------------------------------------
+
+class MarkdownToHtmlRequest final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:mint.morus.v1.MarkdownToHtmlRequest) */ {
+ public:
+  inline MarkdownToHtmlRequest() : MarkdownToHtmlRequest(nullptr) {}
+  ~MarkdownToHtmlRequest() override;
+  template<typename = void>
+  explicit PROTOBUF_CONSTEXPR MarkdownToHtmlRequest(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  MarkdownToHtmlRequest(const MarkdownToHtmlRequest& from);
+  MarkdownToHtmlRequest(MarkdownToHtmlRequest&& from) noexcept
+    : MarkdownToHtmlRequest() {
+    *this = ::std::move(from);
+  }
+
+  inline MarkdownToHtmlRequest& operator=(const MarkdownToHtmlRequest& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline MarkdownToHtmlRequest& operator=(MarkdownToHtmlRequest&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const MarkdownToHtmlRequest& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const MarkdownToHtmlRequest* internal_default_instance() {
+    return reinterpret_cast<const MarkdownToHtmlRequest*>(
+               &_MarkdownToHtmlRequest_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(MarkdownToHtmlRequest& a, MarkdownToHtmlRequest& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(MarkdownToHtmlRequest* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(MarkdownToHtmlRequest* other) {
+    if (other == this) return;
+    ABSL_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  MarkdownToHtmlRequest* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<MarkdownToHtmlRequest>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const MarkdownToHtmlRequest& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const MarkdownToHtmlRequest& from) {
+    MarkdownToHtmlRequest::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  ::size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  ::uint8_t* _InternalSerialize(
+      ::uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(MarkdownToHtmlRequest* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::absl::string_view FullMessageName() {
+    return "mint.morus.v1.MarkdownToHtmlRequest";
+  }
+  protected:
+  explicit MarkdownToHtmlRequest(::PROTOBUF_NAMESPACE_ID::Arena* arena);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kPayloadFieldNumber = 1,
+    kSanitizeFieldNumber = 2,
+  };
+  // string payload = 1;
+  void clear_payload() ;
+  const std::string& payload() const;
+
+
+
+
+  template <typename Arg_ = const std::string&, typename... Args_>
+  void set_payload(Arg_&& arg, Args_... args);
+  std::string* mutable_payload();
+  PROTOBUF_NODISCARD std::string* release_payload();
+  void set_allocated_payload(std::string* ptr);
+
+  private:
+  const std::string& _internal_payload() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_payload(
+      const std::string& value);
+  std::string* _internal_mutable_payload();
+
+  public:
+  // bool sanitize = 2;
+  void clear_sanitize() ;
+  bool sanitize() const;
+  void set_sanitize(bool value);
+
+  private:
+  bool _internal_sanitize() const;
+  void _internal_set_sanitize(bool value);
+
+  public:
+  // @@protoc_insertion_point(class_scope:mint.morus.v1.MarkdownToHtmlRequest)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr payload_;
+    bool sanitize_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_morus_2eproto;
+};// -------------------------------------------------------------------
+
+class MarkdownToHtmlResponse final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:mint.morus.v1.MarkdownToHtmlResponse) */ {
+ public:
+  inline MarkdownToHtmlResponse() : MarkdownToHtmlResponse(nullptr) {}
+  ~MarkdownToHtmlResponse() override;
+  template<typename = void>
+  explicit PROTOBUF_CONSTEXPR MarkdownToHtmlResponse(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  MarkdownToHtmlResponse(const MarkdownToHtmlResponse& from);
+  MarkdownToHtmlResponse(MarkdownToHtmlResponse&& from) noexcept
+    : MarkdownToHtmlResponse() {
+    *this = ::std::move(from);
+  }
+
+  inline MarkdownToHtmlResponse& operator=(const MarkdownToHtmlResponse& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline MarkdownToHtmlResponse& operator=(MarkdownToHtmlResponse&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const MarkdownToHtmlResponse& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const MarkdownToHtmlResponse* internal_default_instance() {
+    return reinterpret_cast<const MarkdownToHtmlResponse*>(
+               &_MarkdownToHtmlResponse_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(MarkdownToHtmlResponse& a, MarkdownToHtmlResponse& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(MarkdownToHtmlResponse* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(MarkdownToHtmlResponse* other) {
+    if (other == this) return;
+    ABSL_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  MarkdownToHtmlResponse* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<MarkdownToHtmlResponse>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const MarkdownToHtmlResponse& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const MarkdownToHtmlResponse& from) {
+    MarkdownToHtmlResponse::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  ::size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  ::uint8_t* _InternalSerialize(
+      ::uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(MarkdownToHtmlResponse* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::absl::string_view FullMessageName() {
+    return "mint.morus.v1.MarkdownToHtmlResponse";
+  }
+  protected:
+  explicit MarkdownToHtmlResponse(::PROTOBUF_NAMESPACE_ID::Arena* arena);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kPayloadFieldNumber = 1,
+  };
+  // string payload = 1;
+  void clear_payload() ;
+  const std::string& payload() const;
+
+
+
+
+  template <typename Arg_ = const std::string&, typename... Args_>
+  void set_payload(Arg_&& arg, Args_... args);
+  std::string* mutable_payload();
+  PROTOBUF_NODISCARD std::string* release_payload();
+  void set_allocated_payload(std::string* ptr);
+
+  private:
+  const std::string& _internal_payload() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_payload(
+      const std::string& value);
+  std::string* _internal_mutable_payload();
+
+  public:
+  // @@protoc_insertion_point(class_scope:mint.morus.v1.MarkdownToHtmlResponse)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr payload_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_morus_2eproto;
+};
+
+// ===================================================================
+
+
+
+
+// ===================================================================
+
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// MarkdownToHtmlRequest
+
+// string payload = 1;
+inline void MarkdownToHtmlRequest::clear_payload() {
+  _impl_.payload_.ClearToEmpty();
+}
+inline const std::string& MarkdownToHtmlRequest::payload() const {
+  // @@protoc_insertion_point(field_get:mint.morus.v1.MarkdownToHtmlRequest.payload)
+  return _internal_payload();
+}
+template <typename Arg_, typename... Args_>
+inline PROTOBUF_ALWAYS_INLINE void MarkdownToHtmlRequest::set_payload(Arg_&& arg,
+                                                     Args_... args) {
+  ;
+  _impl_.payload_.Set(static_cast<Arg_&&>(arg), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:mint.morus.v1.MarkdownToHtmlRequest.payload)
+}
+inline std::string* MarkdownToHtmlRequest::mutable_payload() {
+  std::string* _s = _internal_mutable_payload();
+  // @@protoc_insertion_point(field_mutable:mint.morus.v1.MarkdownToHtmlRequest.payload)
+  return _s;
+}
+inline const std::string& MarkdownToHtmlRequest::_internal_payload() const {
+  return _impl_.payload_.Get();
+}
+inline void MarkdownToHtmlRequest::_internal_set_payload(const std::string& value) {
+  ;
+
+
+  _impl_.payload_.Set(value, GetArenaForAllocation());
+}
+inline std::string* MarkdownToHtmlRequest::_internal_mutable_payload() {
+  ;
+  return _impl_.payload_.Mutable( GetArenaForAllocation());
+}
+inline std::string* MarkdownToHtmlRequest::release_payload() {
+  // @@protoc_insertion_point(field_release:mint.morus.v1.MarkdownToHtmlRequest.payload)
+  return _impl_.payload_.Release();
+}
+inline void MarkdownToHtmlRequest::set_allocated_payload(std::string* value) {
+  _impl_.payload_.SetAllocated(value, GetArenaForAllocation());
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+        if (_impl_.payload_.IsDefault()) {
+          _impl_.payload_.Set("", GetArenaForAllocation());
+        }
+  #endif  // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:mint.morus.v1.MarkdownToHtmlRequest.payload)
+}
+
+// bool sanitize = 2;
+inline void MarkdownToHtmlRequest::clear_sanitize() {
+  _impl_.sanitize_ = false;
+}
+inline bool MarkdownToHtmlRequest::sanitize() const {
+  // @@protoc_insertion_point(field_get:mint.morus.v1.MarkdownToHtmlRequest.sanitize)
+  return _internal_sanitize();
+}
+inline void MarkdownToHtmlRequest::set_sanitize(bool value) {
+  _internal_set_sanitize(value);
+  // @@protoc_insertion_point(field_set:mint.morus.v1.MarkdownToHtmlRequest.sanitize)
+}
+inline bool MarkdownToHtmlRequest::_internal_sanitize() const {
+  return _impl_.sanitize_;
+}
+inline void MarkdownToHtmlRequest::_internal_set_sanitize(bool value) {
+  ;
+  _impl_.sanitize_ = value;
+}
+
+// -------------------------------------------------------------------
+
+// MarkdownToHtmlResponse
+
+// string payload = 1;
+inline void MarkdownToHtmlResponse::clear_payload() {
+  _impl_.payload_.ClearToEmpty();
+}
+inline const std::string& MarkdownToHtmlResponse::payload() const {
+  // @@protoc_insertion_point(field_get:mint.morus.v1.MarkdownToHtmlResponse.payload)
+  return _internal_payload();
+}
+template <typename Arg_, typename... Args_>
+inline PROTOBUF_ALWAYS_INLINE void MarkdownToHtmlResponse::set_payload(Arg_&& arg,
+                                                     Args_... args) {
+  ;
+  _impl_.payload_.Set(static_cast<Arg_&&>(arg), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:mint.morus.v1.MarkdownToHtmlResponse.payload)
+}
+inline std::string* MarkdownToHtmlResponse::mutable_payload() {
+  std::string* _s = _internal_mutable_payload();
+  // @@protoc_insertion_point(field_mutable:mint.morus.v1.MarkdownToHtmlResponse.payload)
+  return _s;
+}
+inline const std::string& MarkdownToHtmlResponse::_internal_payload() const {
+  return _impl_.payload_.Get();
+}
+inline void MarkdownToHtmlResponse::_internal_set_payload(const std::string& value) {
+  ;
+
+
+  _impl_.payload_.Set(value, GetArenaForAllocation());
+}
+inline std::string* MarkdownToHtmlResponse::_internal_mutable_payload() {
+  ;
+  return _impl_.payload_.Mutable( GetArenaForAllocation());
+}
+inline std::string* MarkdownToHtmlResponse::release_payload() {
+  // @@protoc_insertion_point(field_release:mint.morus.v1.MarkdownToHtmlResponse.payload)
+  return _impl_.payload_.Release();
+}
+inline void MarkdownToHtmlResponse::set_allocated_payload(std::string* value) {
+  _impl_.payload_.SetAllocated(value, GetArenaForAllocation());
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+        if (_impl_.payload_.IsDefault()) {
+          _impl_.payload_.Set("", GetArenaForAllocation());
+        }
+  #endif  // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:mint.morus.v1.MarkdownToHtmlResponse.payload)
+}
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+}  // namespace v1
+}  // namespace morus
+}  // namespace mint
+
+
+// @@protoc_insertion_point(global_scope)
+
+#include "google/protobuf/port_undef.inc"
+
+#endif  // GOOGLE_PROTOBUF_INCLUDED_morus_2eproto_2epb_2eh

+ 464 - 0
clients/csharp/Morus.cs

@@ -0,0 +1,464 @@
+// <auto-generated>
+//     Generated by the protocol buffer compiler.  DO NOT EDIT!
+//     source: morus.proto
+// </auto-generated>
+#pragma warning disable 1591, 0612, 3021, 8981
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Mint.Morus.V1 {
+
+  /// <summary>Holder for reflection information generated from morus.proto</summary>
+  public static partial class MorusReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for morus.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static MorusReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Cgttb3J1cy5wcm90bxINbWludC5tb3J1cy52MSI6ChVNYXJrZG93blRvSHRt",
+            "bFJlcXVlc3QSDwoHcGF5bG9hZBgBIAEoCRIQCghzYW5pdGl6ZRgCIAEoCCIp",
+            "ChZNYXJrZG93blRvSHRtbFJlc3BvbnNlEg8KB3BheWxvYWQYASABKAkyYwoI",
+            "TWFya2Rvd24SVwoGVG9IdG1sEiQubWludC5tb3J1cy52MS5NYXJrZG93blRv",
+            "SHRtbFJlcXVlc3QaJS5taW50Lm1vcnVzLnYxLk1hcmtkb3duVG9IdG1sUmVz",
+            "cG9uc2UiAEIyCi5jb20uZ2l0aHViLmlhcHRfcGxhdGZvcm0ubWludC5wbHVn",
+            "aW5zLm1vcnVzLnYxUAFiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Mint.Morus.V1.MarkdownToHtmlRequest), global::Mint.Morus.V1.MarkdownToHtmlRequest.Parser, new[]{ "Payload", "Sanitize" }, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Mint.Morus.V1.MarkdownToHtmlResponse), global::Mint.Morus.V1.MarkdownToHtmlResponse.Parser, new[]{ "Payload" }, null, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  public sealed partial class MarkdownToHtmlRequest : pb::IMessage<MarkdownToHtmlRequest>
+  #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      , pb::IBufferMessage
+  #endif
+  {
+    private static readonly pb::MessageParser<MarkdownToHtmlRequest> _parser = new pb::MessageParser<MarkdownToHtmlRequest>(() => new MarkdownToHtmlRequest());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pb::MessageParser<MarkdownToHtmlRequest> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Mint.Morus.V1.MorusReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public MarkdownToHtmlRequest() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public MarkdownToHtmlRequest(MarkdownToHtmlRequest other) : this() {
+      payload_ = other.payload_;
+      sanitize_ = other.sanitize_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public MarkdownToHtmlRequest Clone() {
+      return new MarkdownToHtmlRequest(this);
+    }
+
+    /// <summary>Field number for the "payload" field.</summary>
+    public const int PayloadFieldNumber = 1;
+    private string payload_ = "";
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public string Payload {
+      get { return payload_; }
+      set {
+        payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "sanitize" field.</summary>
+    public const int SanitizeFieldNumber = 2;
+    private bool sanitize_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool Sanitize {
+      get { return sanitize_; }
+      set {
+        sanitize_ = value;
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override bool Equals(object other) {
+      return Equals(other as MarkdownToHtmlRequest);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool Equals(MarkdownToHtmlRequest other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Payload != other.Payload) return false;
+      if (Sanitize != other.Sanitize) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Payload.Length != 0) hash ^= Payload.GetHashCode();
+      if (Sanitize != false) hash ^= Sanitize.GetHashCode();
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void WriteTo(pb::CodedOutputStream output) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      output.WriteRawMessage(this);
+    #else
+      if (Payload.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Payload);
+      }
+      if (Sanitize != false) {
+        output.WriteRawTag(16);
+        output.WriteBool(Sanitize);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+      if (Payload.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Payload);
+      }
+      if (Sanitize != false) {
+        output.WriteRawTag(16);
+        output.WriteBool(Sanitize);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(ref output);
+      }
+    }
+    #endif
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public int CalculateSize() {
+      int size = 0;
+      if (Payload.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Payload);
+      }
+      if (Sanitize != false) {
+        size += 1 + 1;
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(MarkdownToHtmlRequest other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Payload.Length != 0) {
+        Payload = other.Payload;
+      }
+      if (other.Sanitize != false) {
+        Sanitize = other.Sanitize;
+      }
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(pb::CodedInputStream input) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      input.ReadRawMessage(this);
+    #else
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+            break;
+          case 10: {
+            Payload = input.ReadString();
+            break;
+          }
+          case 16: {
+            Sanitize = input.ReadBool();
+            break;
+          }
+        }
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+            break;
+          case 10: {
+            Payload = input.ReadString();
+            break;
+          }
+          case 16: {
+            Sanitize = input.ReadBool();
+            break;
+          }
+        }
+      }
+    }
+    #endif
+
+  }
+
+  public sealed partial class MarkdownToHtmlResponse : pb::IMessage<MarkdownToHtmlResponse>
+  #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      , pb::IBufferMessage
+  #endif
+  {
+    private static readonly pb::MessageParser<MarkdownToHtmlResponse> _parser = new pb::MessageParser<MarkdownToHtmlResponse>(() => new MarkdownToHtmlResponse());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pb::MessageParser<MarkdownToHtmlResponse> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Mint.Morus.V1.MorusReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public MarkdownToHtmlResponse() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public MarkdownToHtmlResponse(MarkdownToHtmlResponse other) : this() {
+      payload_ = other.payload_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public MarkdownToHtmlResponse Clone() {
+      return new MarkdownToHtmlResponse(this);
+    }
+
+    /// <summary>Field number for the "payload" field.</summary>
+    public const int PayloadFieldNumber = 1;
+    private string payload_ = "";
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public string Payload {
+      get { return payload_; }
+      set {
+        payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override bool Equals(object other) {
+      return Equals(other as MarkdownToHtmlResponse);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool Equals(MarkdownToHtmlResponse other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Payload != other.Payload) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Payload.Length != 0) hash ^= Payload.GetHashCode();
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void WriteTo(pb::CodedOutputStream output) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      output.WriteRawMessage(this);
+    #else
+      if (Payload.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Payload);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+      if (Payload.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Payload);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(ref output);
+      }
+    }
+    #endif
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public int CalculateSize() {
+      int size = 0;
+      if (Payload.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Payload);
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(MarkdownToHtmlResponse other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Payload.Length != 0) {
+        Payload = other.Payload;
+      }
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(pb::CodedInputStream input) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      input.ReadRawMessage(this);
+    #else
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+            break;
+          case 10: {
+            Payload = input.ReadString();
+            break;
+          }
+        }
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+            break;
+          case 10: {
+            Payload = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+    #endif
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code

+ 158 - 0
clients/csharp/MorusGrpc.cs

@@ -0,0 +1,158 @@
+// <auto-generated>
+//     Generated by the protocol buffer compiler.  DO NOT EDIT!
+//     source: morus.proto
+// </auto-generated>
+#pragma warning disable 0414, 1591, 8981, 0612
+#region Designer generated code
+
+using grpc = global::Grpc.Core;
+
+namespace Mint.Morus.V1 {
+  /// <summary>
+  /// ----------------------------------------------------------------------------
+  /// </summary>
+  public static partial class Markdown
+  {
+    static readonly string __ServiceName = "mint.morus.v1.Markdown";
+
+    [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+    static void __Helper_SerializeMessage(global::Google.Protobuf.IMessage message, grpc::SerializationContext context)
+    {
+      #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION
+      if (message is global::Google.Protobuf.IBufferMessage)
+      {
+        context.SetPayloadLength(message.CalculateSize());
+        global::Google.Protobuf.MessageExtensions.WriteTo(message, context.GetBufferWriter());
+        context.Complete();
+        return;
+      }
+      #endif
+      context.Complete(global::Google.Protobuf.MessageExtensions.ToByteArray(message));
+    }
+
+    [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+    static class __Helper_MessageCache<T>
+    {
+      public static readonly bool IsBufferMessage = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T));
+    }
+
+    [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+    static T __Helper_DeserializeMessage<T>(grpc::DeserializationContext context, global::Google.Protobuf.MessageParser<T> parser) where T : global::Google.Protobuf.IMessage<T>
+    {
+      #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION
+      if (__Helper_MessageCache<T>.IsBufferMessage)
+      {
+        return parser.ParseFrom(context.PayloadAsReadOnlySequence());
+      }
+      #endif
+      return parser.ParseFrom(context.PayloadAsNewBuffer());
+    }
+
+    [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+    static readonly grpc::Marshaller<global::Mint.Morus.V1.MarkdownToHtmlRequest> __Marshaller_mint_morus_v1_MarkdownToHtmlRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Mint.Morus.V1.MarkdownToHtmlRequest.Parser));
+    [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+    static readonly grpc::Marshaller<global::Mint.Morus.V1.MarkdownToHtmlResponse> __Marshaller_mint_morus_v1_MarkdownToHtmlResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Mint.Morus.V1.MarkdownToHtmlResponse.Parser));
+
+    [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+    static readonly grpc::Method<global::Mint.Morus.V1.MarkdownToHtmlRequest, global::Mint.Morus.V1.MarkdownToHtmlResponse> __Method_ToHtml = new grpc::Method<global::Mint.Morus.V1.MarkdownToHtmlRequest, global::Mint.Morus.V1.MarkdownToHtmlResponse>(
+        grpc::MethodType.Unary,
+        __ServiceName,
+        "ToHtml",
+        __Marshaller_mint_morus_v1_MarkdownToHtmlRequest,
+        __Marshaller_mint_morus_v1_MarkdownToHtmlResponse);
+
+    /// <summary>Service descriptor</summary>
+    public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+    {
+      get { return global::Mint.Morus.V1.MorusReflection.Descriptor.Services[0]; }
+    }
+
+    /// <summary>Base class for server-side implementations of Markdown</summary>
+    [grpc::BindServiceMethod(typeof(Markdown), "BindService")]
+    public abstract partial class MarkdownBase
+    {
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      public virtual global::System.Threading.Tasks.Task<global::Mint.Morus.V1.MarkdownToHtmlResponse> ToHtml(global::Mint.Morus.V1.MarkdownToHtmlRequest request, grpc::ServerCallContext context)
+      {
+        throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+      }
+
+    }
+
+    /// <summary>Client for Markdown</summary>
+    public partial class MarkdownClient : grpc::ClientBase<MarkdownClient>
+    {
+      /// <summary>Creates a new client for Markdown</summary>
+      /// <param name="channel">The channel to use to make remote calls.</param>
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      public MarkdownClient(grpc::ChannelBase channel) : base(channel)
+      {
+      }
+      /// <summary>Creates a new client for Markdown that uses a custom <c>CallInvoker</c>.</summary>
+      /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      public MarkdownClient(grpc::CallInvoker callInvoker) : base(callInvoker)
+      {
+      }
+      /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      protected MarkdownClient() : base()
+      {
+      }
+      /// <summary>Protected constructor to allow creation of configured clients.</summary>
+      /// <param name="configuration">The client configuration.</param>
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      protected MarkdownClient(ClientBaseConfiguration configuration) : base(configuration)
+      {
+      }
+
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      public virtual global::Mint.Morus.V1.MarkdownToHtmlResponse ToHtml(global::Mint.Morus.V1.MarkdownToHtmlRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return ToHtml(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      public virtual global::Mint.Morus.V1.MarkdownToHtmlResponse ToHtml(global::Mint.Morus.V1.MarkdownToHtmlRequest request, grpc::CallOptions options)
+      {
+        return CallInvoker.BlockingUnaryCall(__Method_ToHtml, null, options, request);
+      }
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      public virtual grpc::AsyncUnaryCall<global::Mint.Morus.V1.MarkdownToHtmlResponse> ToHtmlAsync(global::Mint.Morus.V1.MarkdownToHtmlRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+      {
+        return ToHtmlAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+      }
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      public virtual grpc::AsyncUnaryCall<global::Mint.Morus.V1.MarkdownToHtmlResponse> ToHtmlAsync(global::Mint.Morus.V1.MarkdownToHtmlRequest request, grpc::CallOptions options)
+      {
+        return CallInvoker.AsyncUnaryCall(__Method_ToHtml, null, options, request);
+      }
+      /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
+      [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+      protected override MarkdownClient NewInstance(ClientBaseConfiguration configuration)
+      {
+        return new MarkdownClient(configuration);
+      }
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+    [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+    public static grpc::ServerServiceDefinition BindService(MarkdownBase serviceImpl)
+    {
+      return grpc::ServerServiceDefinition.CreateBuilder()
+          .AddMethod(__Method_ToHtml, serviceImpl.ToHtml).Build();
+    }
+
+    /// <summary>Register service method with a service binder with or without implementation. Useful when customizing the service binding logic.
+    /// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
+    /// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
+    [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+    public static void BindService(grpc::ServiceBinderBase serviceBinder, MarkdownBase serviceImpl)
+    {
+      serviceBinder.AddMethod(__Method_ToHtml, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::Mint.Morus.V1.MarkdownToHtmlRequest, global::Mint.Morus.V1.MarkdownToHtmlResponse>(serviceImpl.ToHtml));
+    }
+
+  }
+}
+#endregion

+ 311 - 0
clients/java/com/github/iapt_platform/mint/plugins/morus/v1/MarkdownGrpc.java

@@ -0,0 +1,311 @@
+package com.github.iapt_platform.mint.plugins.morus.v1;
+
+import static io.grpc.MethodDescriptor.generateFullMethodName;
+
+/**
+ * <pre>
+ * ----------------------------------------------------------------------------
+ * </pre>
+ */
+@javax.annotation.Generated(
+    value = "by gRPC proto compiler (version 1.57.2)",
+    comments = "Source: morus.proto")
+@io.grpc.stub.annotations.GrpcGenerated
+public final class MarkdownGrpc {
+
+  private MarkdownGrpc() {}
+
+  public static final java.lang.String SERVICE_NAME = "mint.morus.v1.Markdown";
+
+  // Static method descriptors that strictly reflect the proto.
+  private static volatile io.grpc.MethodDescriptor<com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest,
+      com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse> getToHtmlMethod;
+
+  @io.grpc.stub.annotations.RpcMethod(
+      fullMethodName = SERVICE_NAME + '/' + "ToHtml",
+      requestType = com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest.class,
+      responseType = com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse.class,
+      methodType = io.grpc.MethodDescriptor.MethodType.UNARY)
+  public static io.grpc.MethodDescriptor<com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest,
+      com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse> getToHtmlMethod() {
+    io.grpc.MethodDescriptor<com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest, com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse> getToHtmlMethod;
+    if ((getToHtmlMethod = MarkdownGrpc.getToHtmlMethod) == null) {
+      synchronized (MarkdownGrpc.class) {
+        if ((getToHtmlMethod = MarkdownGrpc.getToHtmlMethod) == null) {
+          MarkdownGrpc.getToHtmlMethod = getToHtmlMethod =
+              io.grpc.MethodDescriptor.<com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest, com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse>newBuilder()
+              .setType(io.grpc.MethodDescriptor.MethodType.UNARY)
+              .setFullMethodName(generateFullMethodName(SERVICE_NAME, "ToHtml"))
+              .setSampledToLocalTracing(true)
+              .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
+                  com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest.getDefaultInstance()))
+              .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
+                  com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse.getDefaultInstance()))
+              .setSchemaDescriptor(new MarkdownMethodDescriptorSupplier("ToHtml"))
+              .build();
+        }
+      }
+    }
+    return getToHtmlMethod;
+  }
+
+  /**
+   * Creates a new async stub that supports all call types for the service
+   */
+  public static MarkdownStub newStub(io.grpc.Channel channel) {
+    io.grpc.stub.AbstractStub.StubFactory<MarkdownStub> factory =
+      new io.grpc.stub.AbstractStub.StubFactory<MarkdownStub>() {
+        @java.lang.Override
+        public MarkdownStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
+          return new MarkdownStub(channel, callOptions);
+        }
+      };
+    return MarkdownStub.newStub(factory, channel);
+  }
+
+  /**
+   * Creates a new blocking-style stub that supports unary and streaming output calls on the service
+   */
+  public static MarkdownBlockingStub newBlockingStub(
+      io.grpc.Channel channel) {
+    io.grpc.stub.AbstractStub.StubFactory<MarkdownBlockingStub> factory =
+      new io.grpc.stub.AbstractStub.StubFactory<MarkdownBlockingStub>() {
+        @java.lang.Override
+        public MarkdownBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
+          return new MarkdownBlockingStub(channel, callOptions);
+        }
+      };
+    return MarkdownBlockingStub.newStub(factory, channel);
+  }
+
+  /**
+   * Creates a new ListenableFuture-style stub that supports unary calls on the service
+   */
+  public static MarkdownFutureStub newFutureStub(
+      io.grpc.Channel channel) {
+    io.grpc.stub.AbstractStub.StubFactory<MarkdownFutureStub> factory =
+      new io.grpc.stub.AbstractStub.StubFactory<MarkdownFutureStub>() {
+        @java.lang.Override
+        public MarkdownFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
+          return new MarkdownFutureStub(channel, callOptions);
+        }
+      };
+    return MarkdownFutureStub.newStub(factory, channel);
+  }
+
+  /**
+   * <pre>
+   * ----------------------------------------------------------------------------
+   * </pre>
+   */
+  public interface AsyncService {
+
+    /**
+     */
+    default void toHtml(com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest request,
+        io.grpc.stub.StreamObserver<com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse> responseObserver) {
+      io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getToHtmlMethod(), responseObserver);
+    }
+  }
+
+  /**
+   * Base class for the server implementation of the service Markdown.
+   * <pre>
+   * ----------------------------------------------------------------------------
+   * </pre>
+   */
+  public static abstract class MarkdownImplBase
+      implements io.grpc.BindableService, AsyncService {
+
+    @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() {
+      return MarkdownGrpc.bindService(this);
+    }
+  }
+
+  /**
+   * A stub to allow clients to do asynchronous rpc calls to service Markdown.
+   * <pre>
+   * ----------------------------------------------------------------------------
+   * </pre>
+   */
+  public static final class MarkdownStub
+      extends io.grpc.stub.AbstractAsyncStub<MarkdownStub> {
+    private MarkdownStub(
+        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
+      super(channel, callOptions);
+    }
+
+    @java.lang.Override
+    protected MarkdownStub build(
+        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
+      return new MarkdownStub(channel, callOptions);
+    }
+
+    /**
+     */
+    public void toHtml(com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest request,
+        io.grpc.stub.StreamObserver<com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse> responseObserver) {
+      io.grpc.stub.ClientCalls.asyncUnaryCall(
+          getChannel().newCall(getToHtmlMethod(), getCallOptions()), request, responseObserver);
+    }
+  }
+
+  /**
+   * A stub to allow clients to do synchronous rpc calls to service Markdown.
+   * <pre>
+   * ----------------------------------------------------------------------------
+   * </pre>
+   */
+  public static final class MarkdownBlockingStub
+      extends io.grpc.stub.AbstractBlockingStub<MarkdownBlockingStub> {
+    private MarkdownBlockingStub(
+        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
+      super(channel, callOptions);
+    }
+
+    @java.lang.Override
+    protected MarkdownBlockingStub build(
+        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
+      return new MarkdownBlockingStub(channel, callOptions);
+    }
+
+    /**
+     */
+    public com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse toHtml(com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest request) {
+      return io.grpc.stub.ClientCalls.blockingUnaryCall(
+          getChannel(), getToHtmlMethod(), getCallOptions(), request);
+    }
+  }
+
+  /**
+   * A stub to allow clients to do ListenableFuture-style rpc calls to service Markdown.
+   * <pre>
+   * ----------------------------------------------------------------------------
+   * </pre>
+   */
+  public static final class MarkdownFutureStub
+      extends io.grpc.stub.AbstractFutureStub<MarkdownFutureStub> {
+    private MarkdownFutureStub(
+        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
+      super(channel, callOptions);
+    }
+
+    @java.lang.Override
+    protected MarkdownFutureStub build(
+        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
+      return new MarkdownFutureStub(channel, callOptions);
+    }
+
+    /**
+     */
+    public com.google.common.util.concurrent.ListenableFuture<com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse> toHtml(
+        com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest request) {
+      return io.grpc.stub.ClientCalls.futureUnaryCall(
+          getChannel().newCall(getToHtmlMethod(), getCallOptions()), request);
+    }
+  }
+
+  private static final int METHODID_TO_HTML = 0;
+
+  private static final class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final AsyncService serviceImpl;
+    private final int methodId;
+
+    MethodHandlers(AsyncService serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.Override
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_TO_HTML:
+          serviceImpl.toHtml((com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest) request,
+              (io.grpc.stub.StreamObserver<com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.Override
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
+  public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) {
+    return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
+        .addMethod(
+          getToHtmlMethod(),
+          io.grpc.stub.ServerCalls.asyncUnaryCall(
+            new MethodHandlers<
+              com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest,
+              com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse>(
+                service, METHODID_TO_HTML)))
+        .build();
+  }
+
+  private static abstract class MarkdownBaseDescriptorSupplier
+      implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier {
+    MarkdownBaseDescriptorSupplier() {}
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() {
+      return com.github.iapt_platform.mint.plugins.morus.v1.Morus.getDescriptor();
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() {
+      return getFileDescriptor().findServiceByName("Markdown");
+    }
+  }
+
+  private static final class MarkdownFileDescriptorSupplier
+      extends MarkdownBaseDescriptorSupplier {
+    MarkdownFileDescriptorSupplier() {}
+  }
+
+  private static final class MarkdownMethodDescriptorSupplier
+      extends MarkdownBaseDescriptorSupplier
+      implements io.grpc.protobuf.ProtoMethodDescriptorSupplier {
+    private final java.lang.String methodName;
+
+    MarkdownMethodDescriptorSupplier(java.lang.String methodName) {
+      this.methodName = methodName;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() {
+      return getServiceDescriptor().findMethodByName(methodName);
+    }
+  }
+
+  private static volatile io.grpc.ServiceDescriptor serviceDescriptor;
+
+  public static io.grpc.ServiceDescriptor getServiceDescriptor() {
+    io.grpc.ServiceDescriptor result = serviceDescriptor;
+    if (result == null) {
+      synchronized (MarkdownGrpc.class) {
+        result = serviceDescriptor;
+        if (result == null) {
+          serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME)
+              .setSchemaDescriptor(new MarkdownFileDescriptorSupplier())
+              .addMethod(getToHtmlMethod())
+              .build();
+        }
+      }
+    }
+    return result;
+  }
+}

+ 608 - 0
clients/java/com/github/iapt_platform/mint/plugins/morus/v1/MarkdownToHtmlRequest.java

@@ -0,0 +1,608 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: morus.proto
+
+package com.github.iapt_platform.mint.plugins.morus.v1;
+
+/**
+ * Protobuf type {@code mint.morus.v1.MarkdownToHtmlRequest}
+ */
+public final class MarkdownToHtmlRequest extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:mint.morus.v1.MarkdownToHtmlRequest)
+    MarkdownToHtmlRequestOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use MarkdownToHtmlRequest.newBuilder() to construct.
+  private MarkdownToHtmlRequest(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private MarkdownToHtmlRequest() {
+    payload_ = "";
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new MarkdownToHtmlRequest();
+  }
+
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlRequest_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlRequest_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest.class, com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest.Builder.class);
+  }
+
+  public static final int PAYLOAD_FIELD_NUMBER = 1;
+  @SuppressWarnings("serial")
+  private volatile java.lang.Object payload_ = "";
+  /**
+   * <code>string payload = 1;</code>
+   * @return The payload.
+   */
+  @java.lang.Override
+  public java.lang.String getPayload() {
+    java.lang.Object ref = payload_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      payload_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string payload = 1;</code>
+   * @return The bytes for payload.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getPayloadBytes() {
+    java.lang.Object ref = payload_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      payload_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int SANITIZE_FIELD_NUMBER = 2;
+  private boolean sanitize_ = false;
+  /**
+   * <code>bool sanitize = 2;</code>
+   * @return The sanitize.
+   */
+  @java.lang.Override
+  public boolean getSanitize() {
+    return sanitize_;
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(payload_)) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 1, payload_);
+    }
+    if (sanitize_ != false) {
+      output.writeBool(2, sanitize_);
+    }
+    getUnknownFields().writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(payload_)) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, payload_);
+    }
+    if (sanitize_ != false) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeBoolSize(2, sanitize_);
+    }
+    size += getUnknownFields().getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest)) {
+      return super.equals(obj);
+    }
+    com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest other = (com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest) obj;
+
+    if (!getPayload()
+        .equals(other.getPayload())) return false;
+    if (getSanitize()
+        != other.getSanitize()) return false;
+    if (!getUnknownFields().equals(other.getUnknownFields())) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    hash = (37 * hash) + PAYLOAD_FIELD_NUMBER;
+    hash = (53 * hash) + getPayload().hashCode();
+    hash = (37 * hash) + SANITIZE_FIELD_NUMBER;
+    hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(
+        getSanitize());
+    hash = (29 * hash) + getUnknownFields().hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * Protobuf type {@code mint.morus.v1.MarkdownToHtmlRequest}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:mint.morus.v1.MarkdownToHtmlRequest)
+      com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequestOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlRequest_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlRequest_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest.class, com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest.Builder.class);
+    }
+
+    // Construct using com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest.newBuilder()
+    private Builder() {
+
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      bitField0_ = 0;
+      payload_ = "";
+      sanitize_ = false;
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlRequest_descriptor;
+    }
+
+    @java.lang.Override
+    public com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest getDefaultInstanceForType() {
+      return com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest build() {
+      com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest buildPartial() {
+      com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest result = new com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest(this);
+      if (bitField0_ != 0) { buildPartial0(result); }
+      onBuilt();
+      return result;
+    }
+
+    private void buildPartial0(com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest result) {
+      int from_bitField0_ = bitField0_;
+      if (((from_bitField0_ & 0x00000001) != 0)) {
+        result.payload_ = payload_;
+      }
+      if (((from_bitField0_ & 0x00000002) != 0)) {
+        result.sanitize_ = sanitize_;
+      }
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest) {
+        return mergeFrom((com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest other) {
+      if (other == com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest.getDefaultInstance()) return this;
+      if (!other.getPayload().isEmpty()) {
+        payload_ = other.payload_;
+        bitField0_ |= 0x00000001;
+        onChanged();
+      }
+      if (other.getSanitize() != false) {
+        setSanitize(other.getSanitize());
+      }
+      this.mergeUnknownFields(other.getUnknownFields());
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      if (extensionRegistry == null) {
+        throw new java.lang.NullPointerException();
+      }
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            case 10: {
+              payload_ = input.readStringRequireUtf8();
+              bitField0_ |= 0x00000001;
+              break;
+            } // case 10
+            case 16: {
+              sanitize_ = input.readBool();
+              bitField0_ |= 0x00000002;
+              break;
+            } // case 16
+            default: {
+              if (!super.parseUnknownField(input, extensionRegistry, tag)) {
+                done = true; // was an endgroup tag
+              }
+              break;
+            } // default:
+          } // switch (tag)
+        } // while (!done)
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.unwrapIOException();
+      } finally {
+        onChanged();
+      } // finally
+      return this;
+    }
+    private int bitField0_;
+
+    private java.lang.Object payload_ = "";
+    /**
+     * <code>string payload = 1;</code>
+     * @return The payload.
+     */
+    public java.lang.String getPayload() {
+      java.lang.Object ref = payload_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        payload_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string payload = 1;</code>
+     * @return The bytes for payload.
+     */
+    public com.google.protobuf.ByteString
+        getPayloadBytes() {
+      java.lang.Object ref = payload_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        payload_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string payload = 1;</code>
+     * @param value The payload to set.
+     * @return This builder for chaining.
+     */
+    public Builder setPayload(
+        java.lang.String value) {
+      if (value == null) { throw new NullPointerException(); }
+      payload_ = value;
+      bitField0_ |= 0x00000001;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string payload = 1;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearPayload() {
+      payload_ = getDefaultInstance().getPayload();
+      bitField0_ = (bitField0_ & ~0x00000001);
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string payload = 1;</code>
+     * @param value The bytes for payload to set.
+     * @return This builder for chaining.
+     */
+    public Builder setPayloadBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) { throw new NullPointerException(); }
+      checkByteStringIsUtf8(value);
+      payload_ = value;
+      bitField0_ |= 0x00000001;
+      onChanged();
+      return this;
+    }
+
+    private boolean sanitize_ ;
+    /**
+     * <code>bool sanitize = 2;</code>
+     * @return The sanitize.
+     */
+    @java.lang.Override
+    public boolean getSanitize() {
+      return sanitize_;
+    }
+    /**
+     * <code>bool sanitize = 2;</code>
+     * @param value The sanitize to set.
+     * @return This builder for chaining.
+     */
+    public Builder setSanitize(boolean value) {
+
+      sanitize_ = value;
+      bitField0_ |= 0x00000002;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>bool sanitize = 2;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearSanitize() {
+      bitField0_ = (bitField0_ & ~0x00000002);
+      sanitize_ = false;
+      onChanged();
+      return this;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:mint.morus.v1.MarkdownToHtmlRequest)
+  }
+
+  // @@protoc_insertion_point(class_scope:mint.morus.v1.MarkdownToHtmlRequest)
+  private static final com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest();
+  }
+
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<MarkdownToHtmlRequest>
+      PARSER = new com.google.protobuf.AbstractParser<MarkdownToHtmlRequest>() {
+    @java.lang.Override
+    public MarkdownToHtmlRequest parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      Builder builder = newBuilder();
+      try {
+        builder.mergeFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(builder.buildPartial());
+      } catch (com.google.protobuf.UninitializedMessageException e) {
+        throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(e)
+            .setUnfinishedMessage(builder.buildPartial());
+      }
+      return builder.buildPartial();
+    }
+  };
+
+  public static com.google.protobuf.Parser<MarkdownToHtmlRequest> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<MarkdownToHtmlRequest> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlRequest getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 27 - 0
clients/java/com/github/iapt_platform/mint/plugins/morus/v1/MarkdownToHtmlRequestOrBuilder.java

@@ -0,0 +1,27 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: morus.proto
+
+package com.github.iapt_platform.mint.plugins.morus.v1;
+
+public interface MarkdownToHtmlRequestOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:mint.morus.v1.MarkdownToHtmlRequest)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>string payload = 1;</code>
+   * @return The payload.
+   */
+  java.lang.String getPayload();
+  /**
+   * <code>string payload = 1;</code>
+   * @return The bytes for payload.
+   */
+  com.google.protobuf.ByteString
+      getPayloadBytes();
+
+  /**
+   * <code>bool sanitize = 2;</code>
+   * @return The sanitize.
+   */
+  boolean getSanitize();
+}

+ 541 - 0
clients/java/com/github/iapt_platform/mint/plugins/morus/v1/MarkdownToHtmlResponse.java

@@ -0,0 +1,541 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: morus.proto
+
+package com.github.iapt_platform.mint.plugins.morus.v1;
+
+/**
+ * Protobuf type {@code mint.morus.v1.MarkdownToHtmlResponse}
+ */
+public final class MarkdownToHtmlResponse extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:mint.morus.v1.MarkdownToHtmlResponse)
+    MarkdownToHtmlResponseOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use MarkdownToHtmlResponse.newBuilder() to construct.
+  private MarkdownToHtmlResponse(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private MarkdownToHtmlResponse() {
+    payload_ = "";
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new MarkdownToHtmlResponse();
+  }
+
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlResponse_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlResponse_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse.class, com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse.Builder.class);
+  }
+
+  public static final int PAYLOAD_FIELD_NUMBER = 1;
+  @SuppressWarnings("serial")
+  private volatile java.lang.Object payload_ = "";
+  /**
+   * <code>string payload = 1;</code>
+   * @return The payload.
+   */
+  @java.lang.Override
+  public java.lang.String getPayload() {
+    java.lang.Object ref = payload_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      payload_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string payload = 1;</code>
+   * @return The bytes for payload.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getPayloadBytes() {
+    java.lang.Object ref = payload_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      payload_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(payload_)) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 1, payload_);
+    }
+    getUnknownFields().writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(payload_)) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, payload_);
+    }
+    size += getUnknownFields().getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse)) {
+      return super.equals(obj);
+    }
+    com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse other = (com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse) obj;
+
+    if (!getPayload()
+        .equals(other.getPayload())) return false;
+    if (!getUnknownFields().equals(other.getUnknownFields())) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    hash = (37 * hash) + PAYLOAD_FIELD_NUMBER;
+    hash = (53 * hash) + getPayload().hashCode();
+    hash = (29 * hash) + getUnknownFields().hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * Protobuf type {@code mint.morus.v1.MarkdownToHtmlResponse}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:mint.morus.v1.MarkdownToHtmlResponse)
+      com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponseOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlResponse_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlResponse_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse.class, com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse.Builder.class);
+    }
+
+    // Construct using com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse.newBuilder()
+    private Builder() {
+
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      bitField0_ = 0;
+      payload_ = "";
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.github.iapt_platform.mint.plugins.morus.v1.Morus.internal_static_mint_morus_v1_MarkdownToHtmlResponse_descriptor;
+    }
+
+    @java.lang.Override
+    public com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse getDefaultInstanceForType() {
+      return com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse build() {
+      com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse buildPartial() {
+      com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse result = new com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse(this);
+      if (bitField0_ != 0) { buildPartial0(result); }
+      onBuilt();
+      return result;
+    }
+
+    private void buildPartial0(com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse result) {
+      int from_bitField0_ = bitField0_;
+      if (((from_bitField0_ & 0x00000001) != 0)) {
+        result.payload_ = payload_;
+      }
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse) {
+        return mergeFrom((com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse other) {
+      if (other == com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse.getDefaultInstance()) return this;
+      if (!other.getPayload().isEmpty()) {
+        payload_ = other.payload_;
+        bitField0_ |= 0x00000001;
+        onChanged();
+      }
+      this.mergeUnknownFields(other.getUnknownFields());
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      if (extensionRegistry == null) {
+        throw new java.lang.NullPointerException();
+      }
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            case 10: {
+              payload_ = input.readStringRequireUtf8();
+              bitField0_ |= 0x00000001;
+              break;
+            } // case 10
+            default: {
+              if (!super.parseUnknownField(input, extensionRegistry, tag)) {
+                done = true; // was an endgroup tag
+              }
+              break;
+            } // default:
+          } // switch (tag)
+        } // while (!done)
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.unwrapIOException();
+      } finally {
+        onChanged();
+      } // finally
+      return this;
+    }
+    private int bitField0_;
+
+    private java.lang.Object payload_ = "";
+    /**
+     * <code>string payload = 1;</code>
+     * @return The payload.
+     */
+    public java.lang.String getPayload() {
+      java.lang.Object ref = payload_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        payload_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string payload = 1;</code>
+     * @return The bytes for payload.
+     */
+    public com.google.protobuf.ByteString
+        getPayloadBytes() {
+      java.lang.Object ref = payload_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        payload_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string payload = 1;</code>
+     * @param value The payload to set.
+     * @return This builder for chaining.
+     */
+    public Builder setPayload(
+        java.lang.String value) {
+      if (value == null) { throw new NullPointerException(); }
+      payload_ = value;
+      bitField0_ |= 0x00000001;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string payload = 1;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearPayload() {
+      payload_ = getDefaultInstance().getPayload();
+      bitField0_ = (bitField0_ & ~0x00000001);
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string payload = 1;</code>
+     * @param value The bytes for payload to set.
+     * @return This builder for chaining.
+     */
+    public Builder setPayloadBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) { throw new NullPointerException(); }
+      checkByteStringIsUtf8(value);
+      payload_ = value;
+      bitField0_ |= 0x00000001;
+      onChanged();
+      return this;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:mint.morus.v1.MarkdownToHtmlResponse)
+  }
+
+  // @@protoc_insertion_point(class_scope:mint.morus.v1.MarkdownToHtmlResponse)
+  private static final com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse();
+  }
+
+  public static com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<MarkdownToHtmlResponse>
+      PARSER = new com.google.protobuf.AbstractParser<MarkdownToHtmlResponse>() {
+    @java.lang.Override
+    public MarkdownToHtmlResponse parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      Builder builder = newBuilder();
+      try {
+        builder.mergeFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(builder.buildPartial());
+      } catch (com.google.protobuf.UninitializedMessageException e) {
+        throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(e)
+            .setUnfinishedMessage(builder.buildPartial());
+      }
+      return builder.buildPartial();
+    }
+  };
+
+  public static com.google.protobuf.Parser<MarkdownToHtmlResponse> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<MarkdownToHtmlResponse> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.github.iapt_platform.mint.plugins.morus.v1.MarkdownToHtmlResponse getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 21 - 0
clients/java/com/github/iapt_platform/mint/plugins/morus/v1/MarkdownToHtmlResponseOrBuilder.java

@@ -0,0 +1,21 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: morus.proto
+
+package com.github.iapt_platform.mint.plugins.morus.v1;
+
+public interface MarkdownToHtmlResponseOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:mint.morus.v1.MarkdownToHtmlResponse)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>string payload = 1;</code>
+   * @return The payload.
+   */
+  java.lang.String getPayload();
+  /**
+   * <code>string payload = 1;</code>
+   * @return The bytes for payload.
+   */
+  com.google.protobuf.ByteString
+      getPayloadBytes();
+}

+ 64 - 0
clients/java/com/github/iapt_platform/mint/plugins/morus/v1/Morus.java

@@ -0,0 +1,64 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: morus.proto
+
+package com.github.iapt_platform.mint.plugins.morus.v1;
+
+public final class Morus {
+  private Morus() {}
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistryLite registry) {
+  }
+
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistry registry) {
+    registerAllExtensions(
+        (com.google.protobuf.ExtensionRegistryLite) registry);
+  }
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_mint_morus_v1_MarkdownToHtmlRequest_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_mint_morus_v1_MarkdownToHtmlRequest_fieldAccessorTable;
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_mint_morus_v1_MarkdownToHtmlResponse_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_mint_morus_v1_MarkdownToHtmlResponse_fieldAccessorTable;
+
+  public static com.google.protobuf.Descriptors.FileDescriptor
+      getDescriptor() {
+    return descriptor;
+  }
+  private static  com.google.protobuf.Descriptors.FileDescriptor
+      descriptor;
+  static {
+    java.lang.String[] descriptorData = {
+      "\n\013morus.proto\022\rmint.morus.v1\":\n\025Markdown" +
+      "ToHtmlRequest\022\017\n\007payload\030\001 \001(\t\022\020\n\010saniti" +
+      "ze\030\002 \001(\010\")\n\026MarkdownToHtmlResponse\022\017\n\007pa" +
+      "yload\030\001 \001(\t2c\n\010Markdown\022W\n\006ToHtml\022$.mint" +
+      ".morus.v1.MarkdownToHtmlRequest\032%.mint.m" +
+      "orus.v1.MarkdownToHtmlResponse\"\000B2\n.com." +
+      "github.iapt_platform.mint.plugins.morus." +
+      "v1P\001b\006proto3"
+    };
+    descriptor = com.google.protobuf.Descriptors.FileDescriptor
+      .internalBuildGeneratedFileFrom(descriptorData,
+        new com.google.protobuf.Descriptors.FileDescriptor[] {
+        });
+    internal_static_mint_morus_v1_MarkdownToHtmlRequest_descriptor =
+      getDescriptor().getMessageTypes().get(0);
+    internal_static_mint_morus_v1_MarkdownToHtmlRequest_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_mint_morus_v1_MarkdownToHtmlRequest_descriptor,
+        new java.lang.String[] { "Payload", "Sanitize", });
+    internal_static_mint_morus_v1_MarkdownToHtmlResponse_descriptor =
+      getDescriptor().getMessageTypes().get(1);
+    internal_static_mint_morus_v1_MarkdownToHtmlResponse_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_mint_morus_v1_MarkdownToHtmlResponse_descriptor,
+        new java.lang.String[] { "Payload", });
+  }
+
+  // @@protoc_insertion_point(outer_class_scope)
+}

BIN
clients/php/GPBMetadata/Morus.php


+ 34 - 0
clients/php/Mint/Morus/V1/MarkdownClient.php

@@ -0,0 +1,34 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+namespace Mint\Morus\V1;
+
+/**
+ * ----------------------------------------------------------------------------
+ */
+class MarkdownClient extends \Grpc\BaseStub {
+
+    /**
+     * @param string $hostname hostname
+     * @param array $opts channel options
+     * @param \Grpc\Channel $channel (optional) re-use channel object
+     */
+    public function __construct($hostname, $opts, $channel = null) {
+        parent::__construct($hostname, $opts, $channel);
+    }
+
+    /**
+     * @param \Mint\Morus\V1\MarkdownToHtmlRequest $argument input argument
+     * @param array $metadata metadata
+     * @param array $options call options
+     * @return \Grpc\UnaryCall
+     */
+    public function ToHtml(\Mint\Morus\V1\MarkdownToHtmlRequest $argument,
+      $metadata = [], $options = []) {
+        return $this->_simpleRequest('/mint.morus.v1.Markdown/ToHtml',
+        $argument,
+        ['\Mint\Morus\V1\MarkdownToHtmlResponse', 'decode'],
+        $metadata, $options);
+    }
+
+}

+ 85 - 0
clients/php/Mint/Morus/V1/MarkdownToHtmlRequest.php

@@ -0,0 +1,85 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: morus.proto
+
+namespace Mint\Morus\V1;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Generated from protobuf message <code>mint.morus.v1.MarkdownToHtmlRequest</code>
+ */
+class MarkdownToHtmlRequest extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Generated from protobuf field <code>string payload = 1;</code>
+     */
+    protected $payload = '';
+    /**
+     * Generated from protobuf field <code>bool sanitize = 2;</code>
+     */
+    protected $sanitize = false;
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type string $payload
+     *     @type bool $sanitize
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\Morus::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * Generated from protobuf field <code>string payload = 1;</code>
+     * @return string
+     */
+    public function getPayload()
+    {
+        return $this->payload;
+    }
+
+    /**
+     * Generated from protobuf field <code>string payload = 1;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setPayload($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->payload = $var;
+
+        return $this;
+    }
+
+    /**
+     * Generated from protobuf field <code>bool sanitize = 2;</code>
+     * @return bool
+     */
+    public function getSanitize()
+    {
+        return $this->sanitize;
+    }
+
+    /**
+     * Generated from protobuf field <code>bool sanitize = 2;</code>
+     * @param bool $var
+     * @return $this
+     */
+    public function setSanitize($var)
+    {
+        GPBUtil::checkBool($var);
+        $this->sanitize = $var;
+
+        return $this;
+    }
+
+}
+

+ 58 - 0
clients/php/Mint/Morus/V1/MarkdownToHtmlResponse.php

@@ -0,0 +1,58 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: morus.proto
+
+namespace Mint\Morus\V1;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Generated from protobuf message <code>mint.morus.v1.MarkdownToHtmlResponse</code>
+ */
+class MarkdownToHtmlResponse extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Generated from protobuf field <code>string payload = 1;</code>
+     */
+    protected $payload = '';
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type string $payload
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\Morus::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * Generated from protobuf field <code>string payload = 1;</code>
+     * @return string
+     */
+    public function getPayload()
+    {
+        return $this->payload;
+    }
+
+    /**
+     * Generated from protobuf field <code>string payload = 1;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setPayload($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->payload = $var;
+
+        return $this;
+    }
+
+}
+

+ 31 - 0
clients/python/morus_pb2.py

@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: morus.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0bmorus.proto\x12\rmint.morus.v1\":\n\x15MarkdownToHtmlRequest\x12\x0f\n\x07payload\x18\x01 \x01(\t\x12\x10\n\x08sanitize\x18\x02 \x01(\x08\")\n\x16MarkdownToHtmlResponse\x12\x0f\n\x07payload\x18\x01 \x01(\t2c\n\x08Markdown\x12W\n\x06ToHtml\x12$.mint.morus.v1.MarkdownToHtmlRequest\x1a%.mint.morus.v1.MarkdownToHtmlResponse\"\x00\x42\x32\n.com.github.iapt_platform.mint.plugins.morus.v1P\x01\x62\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'morus_pb2', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+  DESCRIPTOR._options = None
+  DESCRIPTOR._serialized_options = b'\n.com.github.iapt_platform.mint.plugins.morus.v1P\001'
+  _globals['_MARKDOWNTOHTMLREQUEST']._serialized_start=30
+  _globals['_MARKDOWNTOHTMLREQUEST']._serialized_end=88
+  _globals['_MARKDOWNTOHTMLRESPONSE']._serialized_start=90
+  _globals['_MARKDOWNTOHTMLRESPONSE']._serialized_end=131
+  _globals['_MARKDOWN']._serialized_start=133
+  _globals['_MARKDOWN']._serialized_end=232
+# @@protoc_insertion_point(module_scope)

+ 69 - 0
clients/python/morus_pb2_grpc.py

@@ -0,0 +1,69 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+import morus_pb2 as morus__pb2
+
+
+class MarkdownStub(object):
+    """----------------------------------------------------------------------------
+    """
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.ToHtml = channel.unary_unary(
+                '/mint.morus.v1.Markdown/ToHtml',
+                request_serializer=morus__pb2.MarkdownToHtmlRequest.SerializeToString,
+                response_deserializer=morus__pb2.MarkdownToHtmlResponse.FromString,
+                )
+
+
+class MarkdownServicer(object):
+    """----------------------------------------------------------------------------
+    """
+
+    def ToHtml(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+
+def add_MarkdownServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'ToHtml': grpc.unary_unary_rpc_method_handler(
+                    servicer.ToHtml,
+                    request_deserializer=morus__pb2.MarkdownToHtmlRequest.FromString,
+                    response_serializer=morus__pb2.MarkdownToHtmlResponse.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'mint.morus.v1.Markdown', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class Markdown(object):
+    """----------------------------------------------------------------------------
+    """
+
+    @staticmethod
+    def ToHtml(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/mint.morus.v1.Markdown/ToHtml',
+            morus__pb2.MarkdownToHtmlRequest.SerializeToString,
+            morus__pb2.MarkdownToHtmlResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

+ 41 - 0
clients/ruby/morus_pb.rb

@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: morus.proto
+
+require 'google/protobuf'
+
+
+descriptor_data = "\n\x0bmorus.proto\x12\rmint.morus.v1\":\n\x15MarkdownToHtmlRequest\x12\x0f\n\x07payload\x18\x01 \x01(\t\x12\x10\n\x08sanitize\x18\x02 \x01(\x08\")\n\x16MarkdownToHtmlResponse\x12\x0f\n\x07payload\x18\x01 \x01(\t2c\n\x08Markdown\x12W\n\x06ToHtml\x12$.mint.morus.v1.MarkdownToHtmlRequest\x1a%.mint.morus.v1.MarkdownToHtmlResponse\"\x00\x42\x32\n.com.github.iapt_platform.mint.plugins.morus.v1P\x01\x62\x06proto3"
+
+pool = Google::Protobuf::DescriptorPool.generated_pool
+
+begin
+  pool.add_serialized_file(descriptor_data)
+rescue TypeError => e
+  # Compatibility code: will be removed in the next major version.
+  require 'google/protobuf/descriptor_pb'
+  parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
+  parsed.clear_dependency
+  serialized = parsed.class.encode(parsed)
+  file = pool.add_serialized_file(serialized)
+  warn "Warning: Protobuf detected an import path issue while loading generated file #{__FILE__}"
+  imports = [
+  ]
+  imports.each do |type_name, expected_filename|
+    import_file = pool.lookup(type_name).file_descriptor
+    if import_file.name != expected_filename
+      warn "- #{file.name} imports #{expected_filename}, but that import was loaded as #{import_file.name}"
+    end
+  end
+  warn "Each proto file must use a consistent fully-qualified name."
+  warn "This will become an error in the next major version."
+end
+
+module Mint
+  module Morus
+    module V1
+      MarkdownToHtmlRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("mint.morus.v1.MarkdownToHtmlRequest").msgclass
+      MarkdownToHtmlResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("mint.morus.v1.MarkdownToHtmlResponse").msgclass
+    end
+  end
+end

+ 27 - 0
clients/ruby/morus_services_pb.rb

@@ -0,0 +1,27 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# Source: morus.proto for package 'mint.morus.v1'
+
+require 'grpc'
+require 'morus_pb'
+
+module Mint
+  module Morus
+    module V1
+      module Markdown
+        # ----------------------------------------------------------------------------
+        class Service
+
+          include ::GRPC::GenericService
+
+          self.marshal_class_method = :encode
+          self.unmarshal_class_method = :decode
+          self.service_name = 'mint.morus.v1.Markdown'
+
+          rpc :ToHtml, ::Mint::Morus::V1::MarkdownToHtmlRequest, ::Mint::Morus::V1::MarkdownToHtmlResponse
+        end
+
+        Stub = Service.rpc_stub_class
+      end
+    end
+  end
+end

+ 44 - 0
clients/schema.sh

@@ -0,0 +1,44 @@
+#!/bin/bash
+
+set -e
+
+export PROTOBUF_ROOT=$HOME/.local
+export WORKSPACE=$PWD
+
+# -----------------------------------------------------------------------------
+
+function generate_grpc_by_lang() {
+    local target=$WORKSPACE/$1
+    echo "generate code for $1"
+    if [ -d $target ]
+    then
+        rm -r $target
+    fi
+    mkdir -p $target
+    $PROTOBUF_ROOT/bin/protoc -I $WORKSPACE/../protocols \
+        -I $PROTOBUF_ROOT/include/google/protobuf \
+        --${1}_out=$target --grpc_out=$target \
+        --plugin=protoc-gen-grpc=$PROTOBUF_ROOT/bin/grpc_${1}_plugin \
+        $WORKSPACE/../protocols/*.proto
+}
+
+# -----------------------------------------------------------------------------
+
+declare -a languages=(
+    "php"
+    "python"
+    "ruby"
+    "cpp"
+    "csharp"
+    "java"
+)
+
+for l in "${languages[@]}"
+do
+    generate_grpc_by_lang $l
+done
+
+# -----------------------------------------------------------------------------
+
+echo 'done.'
+exit 0

+ 3 - 3
morus/schema.sh

@@ -8,17 +8,17 @@ export WORKSPACE=$PWD
 # -----------------------------------------------------------------------------
 
 function generate_node() {
-    echo "generate morus code for node"
+    echo "generate code for node"
     local target=$WORKSPACE/src/protocols
     if [ -d $target ]
     then
         rm -r $target
     fi
     mkdir -p $target
-    grpc_tools_node_protoc -I $WORKSPACE \
+    grpc_tools_node_protoc -I $WORKSPACE/../protocols \
         -I $PROTOBUF_ROOT/include/google/protobuf \
         --js_out=import_style=commonjs,binary:$target \
-        --grpc_out=grpc_js:$target $WORKSPACE/morus.proto
+        --grpc_out=grpc_js:$target $WORKSPACE/../protocols/morus.proto
 }
 
 # -----------------------------------------------------------------------------

+ 0 - 0
morus/morus.proto → protocols/morus.proto


+ 0 - 783
protocols/nut.proto

@@ -1,783 +0,0 @@
-syntax = "proto3";
-option java_multiple_files = true;
-option java_package = "com.github.saturn_xiv.palm.plugins.nut.v1";
-package palm.nut.v1;
-
-import "google/protobuf/empty.proto";
-import "google/protobuf/timestamp.proto";
-import "google/protobuf/duration.proto";
-
-message IdRequest {
-  int32 id = 1;
-}
-
-message Pager {
-  int64 page = 1;
-  int64 size = 2;
-}
-
-message Pagination {
-  int64 page = 1;
-  int64 size = 2;
-  int64 total = 3;
-  bool has_next = 11;
-  bool has_previous = 12;
-}
-
-message MediaContent {
-  enum Editor {
-    TEXTAREA = 0;
-    QUILL = 1;
-  }
-
-  enum Status {
-    Published = 0;
-    Draft = 1;
-    Pending = 2;
-    Private = 3;
-    Future = 4;
-    Trash = 99;
-  }
-  Editor editor = 1;
-  string body = 2;
-  Status status = 3;
-
-  optional google.protobuf.Timestamp published_at = 11;
-}
-
-message UserDetail {
-  int32 id = 1;
-  string uid = 2;
-  string nickname = 3;
-  string real_name = 4;
-  string email = 5;
-}
-
-message Resource {
-  string type = 1;
-  optional int32 id = 2;
-}
-
-message Permission {
-  oneof subject {
-    int32 user = 1;
-    int32 role = 2;
-  }
-  string operation = 11;
-  Resource resource = 12;
-}
-
-// ----------------------------------------------------------------------------
-
-service User {
-  rpc SignIn(UserSignInRequest) returns (UserSignInResponse) {}
-  rpc SignUp(UserSignUpRequest) returns (google.protobuf.Empty) {}
-  rpc ConfirmByEmail(UserQueryRequest) returns (google.protobuf.Empty) {}
-  rpc ConfirmByToken(UserTokenRequest) returns (google.protobuf.Empty) {}
-  rpc UnlockByEmail(UserQueryRequest) returns (google.protobuf.Empty) {}
-  rpc UnlockByToken(UserTokenRequest) returns (google.protobuf.Empty) {}
-  rpc ForgotPassword(UserQueryRequest) returns (google.protobuf.Empty) {}
-  rpc ResetPassword(UserResetPasswordRequest) returns (google.protobuf.Empty) {}
-
-  rpc Refresh(google.protobuf.Duration) returns (UserSignInResponse) {}
-  rpc Logs(Pager) returns (UserLogsResponse) {}
-  rpc SetProfile(UserSetProfileRequest) returns (google.protobuf.Empty) {}
-  rpc ChangePassword(UserChangePasswordRequest)
-      returns (google.protobuf.Empty) {}
-  rpc SignOut(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-
-  rpc Index(Pager) returns (UserIndexResponse) {}
-  rpc Show(IdRequest) returns (UserIndexResponse.Item) {}
-  rpc Disable(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Enable(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Lock(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Unlock(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Confirm(IdRequest) returns (google.protobuf.Empty) {}
-  rpc SetPassword(UserSetPasswordRequest) returns (google.protobuf.Empty) {}
-}
-
-message UserSignInRequest {
-  UserQueryRequest query = 1;
-  string password = 2;
-  google.protobuf.Duration ttl = 11;
-}
-
-message UserQueryRequest {
-  oneof user {
-    string nickname = 1;
-    string email = 2;
-  }
-  string home = 9;
-}
-
-message UserSignInResponse {
-  message Payload {
-    string nickname = 1;
-    string email = 2;
-    string real_name = 11;
-    string lang = 12;
-    string time_zone = 13;
-    string avatar = 99;
-  }
-  string token = 1;
-  Payload payload = 2;
-  repeated string roles = 11;
-  repeated Permission permissions = 12;
-}
-
-message UserSignUpRequest {
-  string real_name = 1;
-  string nickname = 2;
-  string email = 3;
-  string password = 4;
-  string lang = 11;
-  string time_zone = 12;
-  string home = 21;
-}
-
-message UserTokenRequest {
-  string payload = 1;
-}
-
-message UserResetPasswordRequest {
-  string token = 1;
-  string password = 2;
-}
-
-message UserSetPasswordRequest {
-  int32 id = 1;
-  string password = 2;
-}
-
-message UserSetProfileRequest {
-  string real_name = 1;
-  string avatar = 2;
-  string time_zone = 8;
-  string lang = 9;
-  string wechat = 11;
-  string phone = 12;
-}
-
-message UserGetProfileResponse {
-  string real_name = 1;
-  string avatar = 2;
-  string nickname = 3;
-  string email = 4;
-  string time_zone = 8;
-  string lang = 9;
-  string wechat = 11;
-  string phone = 12;
-}
-
-message UserLogsResponse {
-  message Item {
-    enum Level {
-      DEBUG = 0;
-      INFO = 1;
-      WARNING = 2;
-      ERROR = 3;
-      PANIC = 4;
-    }
-    int32 id = 1;
-    int32 user_id = 2;
-    string ip = 3;
-    Level level = 4;
-    string message = 5;
-    Resource resource = 6;
-    google.protobuf.Timestamp created_at = 11;
-  }
-
-  Pagination pagination = 1;
-  repeated Item items = 11;
-}
-message UserChangePasswordRequest {
-  string current_password = 1;
-  string new_password = 2;
-}
-
-message UserProvider {
-  enum Type {
-    EMAIL = 0;
-    GMAIL = 1;
-    WECHAT = 2;
-    FACEBOOK = 3;
-    GITHUB = 4;
-  }
-  Type type = 1;
-  string id = 2;
-}
-
-message UserIndexResponse {
-  message Item {
-    int32 id = 1;
-    string uid = 2;
-    string email = 3;
-    string nickname = 4;
-    string real_name = 5;
-    UserProvider.Type provider_type = 6;
-    google.protobuf.Timestamp updated_at = 9;
-    optional google.protobuf.Timestamp last_sign_in_at = 11;
-    optional string last_sign_in_ip = 12;
-    optional google.protobuf.Timestamp current_sign_in_at = 13;
-    optional string current_sign_in_ip = 14;
-    int32 sign_in_count = 19;
-    string lang = 21;
-    string time_zone = 22;
-    string avatar = 23;
-    optional google.protobuf.Timestamp confirmed_at = 27;
-    optional google.protobuf.Timestamp locked_at = 28;
-    optional google.protobuf.Timestamp deleted_at = 29;
-  }
-
-  Pagination pagination = 1;
-  repeated Item items = 11;
-}
-
-// ----------------------------------------------------------------------------
-
-service Attachment {
-  rpc Index(Pager) returns (AttachmentIndexResponse) {}
-  rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Show(AttachmentShowRequest) returns (AttachmentShowResponse) {}
-}
-message AttachmentShowRequest {
-  int32 id = 1;
-  google.protobuf.Duration ttl = 2;
-}
-message AttachmentShowResponse {
-  AttachmentIndexResponse.Item item = 1;
-  string url = 2;
-}
-
-message AttachmentIndexResponse {
-  message Item {
-    int32 id = 1;
-    string bucket = 2;
-    string name = 3;
-    string title = 4;
-    int64 size = 5;
-    string content_type = 6;
-    MediaContent.Status status = 7;
-
-    google.protobuf.Timestamp updated_at = 11;
-  }
-  Pagination pagination = 1;
-  repeated Item items = 11;
-}
-
-// ----------------------------------------------------------------------------
-
-service Policy {
-  rpc AddRole(PolicyAddRoleRequest) returns (google.protobuf.Empty) {}
-  rpc GetAllRoles(google.protobuf.Empty) returns (PolicyRoleListResponse) {}
-  rpc DeleteRole(IdRequest) returns (google.protobuf.Empty) {}
-  rpc GetRolesForUser(IdRequest) returns (PolicyRolesForUserResponse) {}
-  rpc GetUsersForRole(IdRequest) returns (PolicyUsersForRoleResponse) {}
-  rpc AddRolesForUser(PolicyAddRolesForUserRequest)
-      returns (google.protobuf.Empty) {}
-  rpc DeleteRolesForUser(PolicyDeleteRolesForUserRequest)
-      returns (google.protobuf.Empty) {}
-  rpc GetImplicitRolesForUser(IdRequest)
-      returns (PolicyImplicitRolesForUserResponse) {}
-  rpc GetImplicitUsersForRole(IdRequest)
-      returns (PolicyImplicitUsersForRoleResponse) {}
-
-  rpc GetPermissionsForUser(IdRequest) returns (PolicyPermissionList) {}
-  rpc GetPermissionsForRole(IdRequest) returns (PolicyPermissionList) {}
-  rpc GetImplicitPermissionsForUser(IdRequest) returns (PolicyPermissionList) {}
-  rpc GetImplicitPermissionsForRole(IdRequest) returns (PolicyPermissionList) {}
-
-  rpc AddPermissions(PolicyPermissionList) returns (google.protobuf.Empty) {}
-  rpc DeletePermissions(PolicyPermissionList) returns (google.protobuf.Empty) {}
-}
-
-message PolicyAddRoleRequest {
-  string code = 1;
-  oneof nested {
-    int32 left = 2;
-    int32 parent = 3;
-  }
-}
-
-message PolicyUsersForRoleResponse {
-  message Item {
-    UserDetail user = 1;
-    google.protobuf.Timestamp not_before = 11;
-    google.protobuf.Timestamp expired_at = 12;
-  }
-  repeated Item items = 1;
-}
-message PolicyImplicitUsersForRoleResponse {
-  repeated UserDetail items = 1;
-}
-
-message PolicyRolesForUserResponse {
-  message Item {
-    int32 id = 1;
-    string code = 2;
-    google.protobuf.Timestamp not_before = 11;
-    google.protobuf.Timestamp expired_at = 12;
-  }
-  repeated Item items = 1;
-}
-
-message PolicyImplicitRolesForUserResponse {
-  repeated string items = 1;
-}
-
-message PolicyRoleListResponse {
-  message Item {
-    int32 id = 1;
-    string code = 2;
-    int32 left = 3;
-    int32 right = 4;
-    google.protobuf.Timestamp updated_at = 9;
-  }
-  repeated Item items = 1;
-}
-
-message PolicyAddRolesForUserRequest {
-  int32 user = 1;
-  repeated int32 roles = 2;
-  google.protobuf.Timestamp not_before = 11;
-  google.protobuf.Timestamp expired_at = 12;
-}
-
-message PolicyDeleteRolesForUserRequest {
-  int32 user = 1;
-  repeated int32 roles = 2;
-}
-
-message PolicyPermissionList {
-  repeated Permission items = 1;
-}
-
-// ----------------------------------------------------------------------------
-
-service Locale {
-  rpc Set(LocaleSetRequest) returns (google.protobuf.Empty) {}
-  rpc Get(LocaleGetRequest) returns (LocaleIndexResponse.Item) {}
-  rpc ByLang(LocaleByLangRequest) returns (LocaleByLangResponse) {}
-  rpc Index(Pager) returns (LocaleIndexResponse) {}
-  rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
-}
-
-message LocaleByLangRequest {
-  string lang = 1;
-}
-
-message LocaleByLangResponse {
-  repeated LocaleIndexResponse.Item items = 1;
-}
-
-message LocaleIndexResponse {
-  message Item {
-    int32 id = 1;
-    string lang = 2;
-    string code = 3;
-    string message = 4;
-    google.protobuf.Timestamp updated_at = 9;
-  }
-  repeated Item items = 1;
-  Pagination pagination = 9;
-}
-
-message LocaleGetRequest {
-  string lang = 1;
-  string code = 2;
-}
-message LocaleSetRequest {
-  string lang = 1;
-  string code = 2;
-  string message = 3;
-}
-// ----------------------------------------------------------------------------
-service Notification {
-  rpc Index(Pager) returns (IndexNotificationResponse) {}
-}
-
-message IndexNotificationResponse {
-  message Item {
-    oneof message {
-      EmailTask email = 1;
-      SmsTask sms = 2;
-    }
-    google.protobuf.Timestamp created_at = 19;
-  }
-  repeated Item items = 1;
-  Pagination pagination = 9;
-}
-
-// ----------------------------------------------------------------------------
-
-service LeaveWord {
-  rpc Create(MediaContent) returns (google.protobuf.Empty) {}
-  rpc Index(Pager) returns (LeaveWordIndexResponse) {}
-  rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
-}
-
-message LeaveWordIndexResponse {
-  message Item {
-    int32 id = 1;
-    string lang = 2;
-    string ip = 3;
-    MediaContent content = 8;
-    google.protobuf.Timestamp updated_at = 11;
-    google.protobuf.Timestamp created_at = 12;
-  }
-  repeated Item items = 1;
-  Pagination pagination = 9;
-}
-
-// ----------------------------------------------------------------------------
-
-service Site {
-  rpc SetMaintenanceMode(SiteMaintenanceModeRequest)
-      returns (google.protobuf.Empty) {}
-
-  rpc Install(SiteInstallRequest) returns (google.protobuf.Empty) {}
-
-  rpc ClearCache(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-
-  rpc Layout(google.protobuf.Empty) returns (SiteLayoutResponse) {}
-  rpc SetAuthor(SiteLayoutResponse.Author) returns (google.protobuf.Empty) {}
-  rpc SetCopyright(SiteSetCopyrightRequest) returns (google.protobuf.Empty) {}
-  rpc SetKeywords(SiteSetKeywordsRequest) returns (google.protobuf.Empty) {}
-  rpc SetInfo(SiteSetInfoRequest) returns (google.protobuf.Empty) {}
-  rpc SetLogo(SiteSetLogoRequest) returns (google.protobuf.Empty) {}
-
-  rpc SetMinio(MinioProfile) returns (google.protobuf.Empty) {}
-  rpc GetMinio(google.protobuf.Empty) returns (MinioProfile) {}
-  rpc TestMinio(MinioProfile) returns (SiteMinioTestResponse) {}
-
-  rpc SetTwilio(TwilioProfile) returns (google.protobuf.Empty) {}
-  rpc GetTwilio(google.protobuf.Empty) returns (TwilioProfile) {}
-  rpc TestTwilio(SiteTwilioTestRequest) returns (google.protobuf.Empty) {}
-
-  rpc SetSmtp(SmtpProfile) returns (google.protobuf.Empty) {}
-  rpc GetSmtp(google.protobuf.Empty) returns (SmtpProfile) {}
-  rpc TestSmtp(SiteSmtpTestRequest) returns (google.protobuf.Empty) {}
-
-  rpc SetBing(BingProfile) returns (google.protobuf.Empty) {}
-  rpc GetBing(google.protobuf.Empty) returns (BingProfile) {}
-
-  rpc SetIndexNow(IndexNowProfile) returns (google.protobuf.Empty) {}
-  rpc GetIndexNow(google.protobuf.Empty) returns (IndexNowProfile) {}
-  rpc PingIndexNow(IndexNowPingRequest) returns (google.protobuf.Empty) {}
-
-  rpc SetGoogle(GoogleProfile) returns (google.protobuf.Empty) {}
-  rpc GetGoogle(google.protobuf.Empty) returns (GoogleProfile) {}
-  rpc PingGoogle(SitemapPingRequest) returns (google.protobuf.Empty) {}
-
-  rpc SetBaidu(BaiduProfile) returns (google.protobuf.Empty) {}
-  rpc GetBaidu(google.protobuf.Empty) returns (BaiduProfile) {}
-  rpc PingBaidu(SitemapPingRequest) returns (google.protobuf.Empty) {}
-
-  rpc Status(google.protobuf.Empty) returns (SiteStatusResponse) {}
-}
-
-message IndexNowProfile {
-  string key = 1;
-}
-
-message IndexNowPingRequest {
-  string key = 1;
-  string home = 9;
-}
-
-message SitemapPingRequest {
-  string home = 1;
-}
-
-message SiteMaintenanceModeRequest {
-  message Item {
-    google.protobuf.Duration duration = 1;
-    string reason = 2;
-  }
-  optional Item item = 1;
-}
-
-message SiteInstallRequest {
-  UserSignUpRequest user = 1;
-}
-
-message MinioProfile {
-  optional string region = 1;
-  string host = 2;
-  int32 port = 3;
-  bool https = 4;
-  string access_key = 8;
-  string secret_key = 9;
-}
-
-message SiteMinioTestResponse {
-  repeated string buckets = 1;
-}
-
-message TwilioProfile {
-  string from = 1;
-  string account_sid = 2;
-  string auth_token = 3;
-  optional string sms_status_callback = 9;
-}
-
-message SmtpProfile {
-  // https://github.com/karastojko/mailio/blob/master/include/mailio/smtp.hpp#L229
-  enum AuthMethod {
-    None = 0;
-    Login = 1;
-    StartTls = 2;
-  }
-  string host = 1;
-  uint32 port = 2;
-  AuthMethod auth_method = 3;
-  repeated EmailTask.Address cc = 8;
-  repeated EmailTask.Address bcc = 9;
-
-  EmailTask.Address user = 11;
-  string password = 12;
-}
-
-message EmailTask {
-  message Address {
-    string name = 1;
-    string email = 2;
-  }
-  enum ContentType {
-    Plain = 0;
-    Html = 1;
-  }
-  message Attachment {
-    string name = 1;
-    string content_type = 2;
-    bytes payload = 3;
-  }
-  string subject = 1;
-  string content = 2;
-  ContentType content_type = 3;
-
-  Address to = 11;
-  repeated Address cc = 12;
-  repeated Address bcc = 13;
-  repeated Attachment attachments = 21;
-}
-
-message SiteTwilioTestRequest {
-  string to = 1;
-  string message = 2;
-  TwilioProfile profile = 9;
-}
-
-message SiteSmtpTestRequest {
-  EmailTask.Address to = 1;
-  string subject = 2;
-  string content = 3;
-  SmtpProfile profile = 9;
-}
-
-message SiteSetLogoRequest {
-  string url = 1;
-}
-message SiteSetCopyrightRequest {
-  string payload = 1;
-}
-message SiteSetKeywordsRequest {
-  repeated string items = 1;
-}
-message SiteSetInfoRequest {
-  string lang = 1;
-  string title = 11;
-  string subhead = 12;
-  string description = 13;
-}
-
-message SiteLayoutResponse {
-  message Author {
-    string name = 1;
-    string email = 2;
-  }
-  string title = 1;
-  string subhead = 2;
-  repeated string keywords = 3;
-  string description = 4;
-  Author author = 5;
-  string copyright = 6;
-  string logo = 7;
-  repeated string languages = 9;
-}
-
-message GoogleProfile {
-  // https://developers.google.com/recaptcha/intro
-  message ReCaptcha {
-    string site_key = 1;
-    string secret = 2;
-  }
-  optional string site_verify_id = 1;
-  optional ReCaptcha re_captcha = 2;
-}
-message BaiduProfile {
-  message SiteVerify {
-    string id = 1;
-    string content = 2;
-  }
-  optional SiteVerify site_verify = 1;
-}
-message BingProfile {
-  optional string site_verify_id = 1;
-}
-
-message SmsTask {
-  string from = 1;
-  repeated string to = 2;
-  string body = 3;
-}
-
-message SiteStatusResponse {
-  message Database {
-    string name = 1;
-    string size = 2;
-  }
-  message PostgreSql {
-    string version = 1;
-    google.protobuf.Timestamp now = 2;
-    repeated Database databases = 9;
-  }
-  message MySql {
-    uint64 size = 1;
-    string version = 2;
-  }
-  message Redis {
-    message Item {
-      string key = 1;
-      int64 ttl = 2;
-    };
-    string info = 1;
-    repeated Item items = 2;
-  }
-  message RabbitMq {
-    string protocol = 1;
-  }
-  message OpenSearch {
-    string url = 1;
-    string info = 2;
-  }
-  message Health {
-    string name = 1;
-    string status = 2;
-  }
-  message System {
-    string version = 1;
-    string cpu = 2;
-    string memory = 3;
-    string boot = 4;
-    string disk = 5;
-    string load = 6;
-    string fs = 7;
-    string swap = 8;
-    string uptime = 9;
-    string network = 10;
-  }
-
-  PostgreSql postgresql = 1;
-  MySql mysql = 2;
-  Redis redis = 3;
-  RabbitMq rabbitmq = 4;
-  OpenSearch opensearch = 5;
-  System system = 11;
-  repeated Health healthes = 21;
-}
-
-// ----------------------------------------------------------------------------
-
-service ShorterLink {
-  rpc Create(ShorterLinkCreateRequest) returns (google.protobuf.Empty) {}
-  rpc Update(ShorterLinkUpdateRequest) returns (google.protobuf.Empty) {}
-  rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Index(Pager) returns (ShorterLinkIndexResponse) {}
-}
-
-message ShorterLinkIndexResponse {
-  message Item {
-    int32 id = 1;
-    string url = 2;
-    string details = 3;
-    string code = 9;
-
-    google.protobuf.Timestamp updated_at = 11;
-  }
-  Pagination pagination = 1;
-  repeated Item items = 11;
-}
-
-message ShorterLinkCreateRequest {
-  string url = 1;
-  string details = 2;
-}
-
-message ShorterLinkUpdateRequest {
-  int32 id = 1;
-  string url = 2;
-  string details = 3;
-}
-// ----------------------------------------------------------------------------
-
-service Tag {
-  rpc Create(TagCreateRequest) returns (google.protobuf.Empty) {}
-  rpc Update(TagUpdateRequest) returns (google.protobuf.Empty) {}
-  rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Index(google.protobuf.Empty) returns (TagIndexResponse) {}
-}
-
-message TagIndexResponse {
-  message Item {
-    int32 id = 1;
-    string code = 2;
-    int32 priority = 3;
-    google.protobuf.Timestamp updated_at = 11;
-  }
-  repeated Item items = 1;
-}
-
-message TagCreateRequest {
-  string code = 1;
-  int32 priority = 11;
-}
-
-message TagUpdateRequest {
-  int32 id = 1;
-  string code = 2;
-  int32 priority = 11;
-}
-// ----------------------------------------------------------------------------
-
-service Category {
-  rpc Create(CategoryCreateRequest) returns (google.protobuf.Empty) {}
-  rpc Update(CategoryUpdateRequest) returns (google.protobuf.Empty) {}
-  rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Index(google.protobuf.Empty) returns (CategoryIndexResponse) {}
-}
-message CategoryIndexResponse {
-  message Item {
-    int32 id = 1;
-    string code = 2;
-    int32 left = 3;
-    int32 right = 4;
-
-    google.protobuf.Timestamp updated_at = 11;
-  }
-  repeated Item items = 1;
-}
-message CategoryCreateRequest {
-  string code = 1;
-  oneof by {
-    int32 left = 2;
-    int32 parent = 3;
-  }
-}
-
-message CategoryUpdateRequest {
-  int32 id = 1;
-  string code = 2;
-}
-
-// ----------------------------------------------------------------------------