Skip to content

Instantly share code, notes, and snippets.

@mulbc
Last active May 6, 2020 03:36
Show Gist options
  • Save mulbc/b9a442d6a42fdea9626fdda6f6ffbd89 to your computer and use it in GitHub Desktop.
Save mulbc/b9a442d6a42fdea9626fdda6f6ffbd89 to your computer and use it in GitHub Desktop.

Revisions

  1. mulbc revised this gist Jul 13, 2018. 1 changed file with 18 additions and 13 deletions.
    31 changes: 18 additions & 13 deletions ceph-client.rb
    Original file line number Diff line number Diff line change
    @@ -60,19 +60,24 @@ def install
    lib.install "build/lib/librbd.1.12.0.dylib"
    lib.install "build/lib/librbd.1.dylib"
    lib.install "build/lib/librbd.dylib"
    man.install "build/doc/man/ceph-conf.8"
    man.install "build/doc/man/ceph.8"
    man.install "build/doc/man/librados-config.8"
    man.install "build/doc/man/rados.8"
    man.install "build/doc/man/rbd-fuse.8"
    man.install "build/doc/man/rbd-ggate.8"
    man.install "build/doc/man/rbd-mirror.8"
    man.install "build/doc/man/rbd-nbd.8"
    man.install "build/doc/man/rbd-replay-many.8"
    man.install "build/doc/man/rbd-replay-prep.8"
    man.install "build/doc/man/rbd-replay.8"
    man.install "build/doc/man/rbd.8"
    man.install "build/doc/man/rbdmap.8"
    man8.install "build/doc/man/ceph-conf.8"
    man8.install "build/doc/man/ceph.8"
    man8.install "build/doc/man/librados-config.8"
    man8.install "build/doc/man/rados.8"
    man8.install "build/doc/man/rbd-fuse.8"
    man8.install "build/doc/man/rbd-ggate.8"
    man8.install "build/doc/man/rbd-mirror.8"
    man8.install "build/doc/man/rbd-nbd.8"
    man8.install "build/doc/man/rbd-replay-many.8"
    man8.install "build/doc/man/rbd-replay-prep.8"
    man8.install "build/doc/man/rbd-replay.8"
    man8.install "build/doc/man/rbd.8"
    man8.install "build/doc/man/rbdmap.8"
    ENV.prepend_create_path "PYTHONPATH", libexec
    libexec.install "src/pybind/ceph_argparse.py"
    libexec.install "src/pybind/ceph_daemon.py"
    libexec.install "src/pybind/ceph_volume_client.py"
    bin.env_script_all_files(libexec/"bin", :PYTHONPATH => ENV["PYTHONPATH"])
    end

    test do
  2. mulbc revised this gist Jul 13, 2018. 1 changed file with 12 additions and 141 deletions.
    153 changes: 12 additions & 141 deletions ceph-client.rb
    Original file line number Diff line number Diff line change
    @@ -45,7 +45,7 @@ def install
    "-DWITH_LZ4=OFF",
    "-DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include"
    system "make", "--directory=build", "rados", "rbd", "ceph-fuse", "manpages"
    # bin.install "build/bin/ceph"
    bin.install "build/bin/ceph"
    bin.install "build/bin/ceph-fuse"
    bin.install "build/bin/rados"
    bin.install "build/bin/rbd"
    @@ -76,7 +76,7 @@ def install
    end

    test do
    # system "#{bin}/ceph", "--version"
    system "#{bin}/ceph", "--version"
    system "#{bin}/ceph-fuse", "--version"
    system "#{bin}/rbd", "--version"
    system "#{bin}/rados", "--version"
    @@ -85,25 +85,23 @@ def install

    __END__
    diff --git a/src/common/convenience.h b/src/common/convenience.h
    index 3989c70d10..ba1635e8fa 100644
    index 3989c70d10..f10a056f5e 100644
    --- a/src/common/convenience.h
    +++ b/src/common/convenience.h
    @@ -14,7 +14,7 @@
    @@ -14,7 +14,6 @@

    #include <mutex>
    #include <memory>
    -#include <optional>
    +#include <boost/optional.hpp>
    #include <shared_mutex>
    #include <type_traits>
    #include <utility>
    @@ -202,33 +202,33 @@ auto maybe_do_or(const boost::optional<T>& t, F&& f, U&& u) ->
    @@ -202,34 +201,6 @@ auto maybe_do_or(const boost::optional<T>& t, F&& f, U&& u) ->
    }


    -// Same thing but for std::optional
    +// // Same thing but for std::optional

    -
    -template<typename T, typename F>
    -auto maybe_do(const std::optional<T>& t, F&& f) ->
    - std::optional<std::result_of_t<F(const std::decay_t<T>)>>
    @@ -113,16 +111,7 @@ def install
    - else
    - return std::nullopt;
    -}
    +// template<typename T, typename F>
    +// auto maybe_do(const std::optional<T>& t, F&& f) ->
    +// std::optional<std::result_of_t<F(const std::decay_t<T>)>>
    +// {
    +// if (t)
    +// return { std::forward<F>(f)(*t) };
    +// else
    +// return std::nullopt;
    +// }

    -
    -// The other obvious function takes an optional but returns an
    -// ‘unwrapped’ value, either the result of evaluating the function or
    -// a provided alternate value.
    @@ -138,24 +127,10 @@ def install
    - else
    - return std::forward<U>(u);
    -}
    +// // The other obvious function takes an optional but returns an
    +// // ‘unwrapped’ value, either the result of evaluating the function or
    +// // a provided alternate value.
    +// //
    +// template<typename T, typename F, typename U>
    +// auto maybe_do_or(const std::optional<T>& t, F&& f, U&& u) ->
    +// std::result_of_t<F(const std::decay_t<T>)>
    +// {
    +// static_assert(std::is_convertible_v<U, std::result_of_t<F(T)>>,
    +// "Alternate value must be convertible to function return type.");
    +// if (t)
    +// return std::forward<F>(f)(*t);
    +// else
    +// return std::forward<U>(u);
    +// }

    -
    namespace _convenience {
    template<typename... Ts, typename F, std::size_t... Is>
    inline void for_each_helper(const std::tuple<Ts...>& t, const F& f,
    diff --git a/src/include/any.h b/src/include/any.h
    index da59c88f48..4a3d547b1b 100644
    --- a/src/include/any.h
    @@ -215,19 +190,18 @@ def install

    // `immobile_any`
    diff --git a/src/include/denc.h b/src/include/denc.h
    index e95c429fb5..4c9091c47c 100644
    index e95c429fb5..6a798768fe 100644
    --- a/src/include/denc.h
    +++ b/src/include/denc.h
    @@ -27,7 +27,7 @@
    @@ -27,7 +27,6 @@
    #include <array>
    #include <cstring>
    #include <map>
    -#include <optional>
    +// #include <optional>
    #include <set>
    #include <string>
    #include <type_traits>
    @@ -1288,109 +1288,109 @@ struct denc_traits<boost::none_t> {
    @@ -1288,109 +1287,6 @@ struct denc_traits<boost::none_t> {
    }
    };

    @@ -334,109 +308,6 @@ def install
    - denc(false, p);
    - }
    -};
    +// //
    +// // std::optional<T>
    +// //
    +// template<typename T>
    +// struct denc_traits<
    +// std::optional<T>,
    +// std::enable_if_t<denc_traits<T>::supported>> {
    +// using traits = denc_traits<T>;
    +
    +// static constexpr bool supported = true;
    +// static constexpr bool featured = traits::featured;
    +// static constexpr bool bounded = false;
    +// static constexpr bool need_contiguous = traits::need_contiguous;
    +
    +// static void bound_encode(const std::optional<T>& v, size_t& p,
    +// uint64_t f = 0) {
    +// p += sizeof(bool);
    +// if (v) {
    +// if constexpr (featured) {
    +// denc(*v, p, f);
    +// } else {
    +// denc(*v, p);
    +// }
    +// }
    +// }
    +
    +// static void encode(const std::optional<T>& v,
    +// bufferlist::contiguous_appender& p,
    +// uint64_t f = 0) {
    +// denc((bool)v, p);
    +// if (v) {
    +// if constexpr (featured) {
    +// denc(*v, p, f);
    +// } else {
    +// denc(*v, p);
    +// }
    +// }
    +// }
    +
    +// static void decode(std::optional<T>& v, buffer::ptr::iterator& p,
    +// uint64_t f = 0) {
    +// bool x;
    +// denc(x, p, f);
    +// if (x) {
    +// v = T{};
    +// denc(*v, p, f);
    +// } else {
    +// v = std::nullopt;
    +// }
    +// }
    +
    +// template<typename U = T>
    +// static std::enable_if_t<!!sizeof(U) && !need_contiguous>
    +// decode(std::optional<T>& v, buffer::list::iterator& p) {
    +// bool x;
    +// denc(x, p);
    +// if (x) {
    +// v = T{};
    +// denc(*v, p);
    +// } else {
    +// v = std::nullopt;
    +// }
    +// }
    +
    +// static void encode_nohead(const std::optional<T>& v,
    +// bufferlist::contiguous_appender& p,
    +// uint64_t f = 0) {
    +// if (v) {
    +// if constexpr (featured) {
    +// denc(*v, p, f);
    +// } else {
    +// denc(*v, p);
    +// }
    +// }
    +// }
    +
    +// static void decode_nohead(bool num, std::optional<T>& v,
    +// buffer::ptr::iterator& p, uint64_t f = 0) {
    +// if (num) {
    +// v = T();
    +// denc(*v, p, f);
    +// } else {
    +// v = std::nullopt;
    +// }
    +// }
    +// };
    +
    +// template<>
    +// struct denc_traits<std::nullopt_t> {
    +// static constexpr bool supported = true;
    +// static constexpr bool featured = false;
    +// static constexpr bool bounded = true;
    +// static constexpr bool need_contiguous = false;
    +
    +// static void bound_encode(const std::nullopt_t& v, size_t& p) {
    +// p += sizeof(bool);
    +// }
    +
    +// static void encode(const std::nullopt_t& v,
    +// bufferlist::contiguous_appender& p) {
    +// denc(false, p);
    +// }
    +// };

    // ----------------------------------------------------------------------
    // class helpers
  3. mulbc created this gist Jul 13, 2018.
    442 changes: 442 additions & 0 deletions ceph-client.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,442 @@
    class CephClient < Formula
    desc "Rados and RBD CLIs and libraries of the Ceph project"
    homepage "https://ceph.com"
    url "[email protected]:ceph/ceph.git", :using => :git, :tag => "v13.2.0"
    sha256 "9469c2af0a997a27ddfced71cef3fd55483ab0e34cc36a07a46ccf0d886a2d91"

    depends_on :python if MacOS.version <= :snow_leopard

    depends_on :osxfuse
    depends_on "openssl" => :build
    depends_on "ccache" => :build
    depends_on "cmake" => :build
    depends_on "cython" => :build
    depends_on "leveldb" => :build
    depends_on "nss"
    depends_on "pkg-config" => :build
    depends_on "yasm"

    patch :DATA

    def install
    ENV.prepend_path "PKG_CONFIG_PATH", "#{Formula["nss"].opt_lib}/pkgconfig"
    ENV.prepend_path "PKG_CONFIG_PATH", "#{Formula["openssl"].opt_lib}/pkgconfig"

    system "./do_cmake.sh",
    "-DCMAKE_CXX_COMPILER=clang++",
    "-DCMAKE_C_COMPILER=clang",
    "-DWITH_EMBEDDED=OFF",
    "-DWITH_MANPAGE=ON",
    "-DWITH_LIBCEPHFS=OFF",
    "-DWITH_XFS=OFF",
    "-DWITH_KRBD=OFF",
    "-DWITH_NSS=ON",
    "-DWITH_LTTNG=OFF",
    "-DCMAKE_BUILD_TYPE=Debug",
    "-DWITH_CCACHE=ON",
    "-DWITH_RADOSGW=OFF",
    "-DWITH_CEPHFS=OFF",
    "-DDIAGNOSTICS_COLOR=always",
    "-DWITH_SYSTEMD=OFF",
    "-DWITH_RDMA=OFF",
    "-DWITH_BABELTRACE=OFF",
    "-DWITH_BLUESTORE=OFF",
    "-DWITH_SPDK=OFF",
    "-DWITH_LZ4=OFF",
    "-DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include"
    system "make", "--directory=build", "rados", "rbd", "ceph-fuse", "manpages"
    # bin.install "build/bin/ceph"
    bin.install "build/bin/ceph-fuse"
    bin.install "build/bin/rados"
    bin.install "build/bin/rbd"
    lib.install "build/lib/libceph-common.0.dylib"
    lib.install "build/lib/libceph-common.dylib"
    lib.install "build/lib/librados.2.0.0.dylib"
    lib.install "build/lib/librados.2.dylib"
    lib.install "build/lib/librados.dylib"
    lib.install "build/lib/libradosstriper.1.0.0.dylib"
    lib.install "build/lib/libradosstriper.1.dylib"
    lib.install "build/lib/libradosstriper.dylib"
    lib.install "build/lib/librbd.1.12.0.dylib"
    lib.install "build/lib/librbd.1.dylib"
    lib.install "build/lib/librbd.dylib"
    man.install "build/doc/man/ceph-conf.8"
    man.install "build/doc/man/ceph.8"
    man.install "build/doc/man/librados-config.8"
    man.install "build/doc/man/rados.8"
    man.install "build/doc/man/rbd-fuse.8"
    man.install "build/doc/man/rbd-ggate.8"
    man.install "build/doc/man/rbd-mirror.8"
    man.install "build/doc/man/rbd-nbd.8"
    man.install "build/doc/man/rbd-replay-many.8"
    man.install "build/doc/man/rbd-replay-prep.8"
    man.install "build/doc/man/rbd-replay.8"
    man.install "build/doc/man/rbd.8"
    man.install "build/doc/man/rbdmap.8"
    end

    test do
    # system "#{bin}/ceph", "--version"
    system "#{bin}/ceph-fuse", "--version"
    system "#{bin}/rbd", "--version"
    system "#{bin}/rados", "--version"
    end
    end

    __END__
    diff --git a/src/common/convenience.h b/src/common/convenience.h
    index 3989c70d10..ba1635e8fa 100644
    --- a/src/common/convenience.h
    +++ b/src/common/convenience.h
    @@ -14,7 +14,7 @@

    #include <mutex>
    #include <memory>
    -#include <optional>
    +#include <boost/optional.hpp>
    #include <shared_mutex>
    #include <type_traits>
    #include <utility>
    @@ -202,33 +202,33 @@ auto maybe_do_or(const boost::optional<T>& t, F&& f, U&& u) ->
    }


    -// Same thing but for std::optional
    +// // Same thing but for std::optional

    -template<typename T, typename F>
    -auto maybe_do(const std::optional<T>& t, F&& f) ->
    - std::optional<std::result_of_t<F(const std::decay_t<T>)>>
    -{
    - if (t)
    - return { std::forward<F>(f)(*t) };
    - else
    - return std::nullopt;
    -}
    +// template<typename T, typename F>
    +// auto maybe_do(const std::optional<T>& t, F&& f) ->
    +// std::optional<std::result_of_t<F(const std::decay_t<T>)>>
    +// {
    +// if (t)
    +// return { std::forward<F>(f)(*t) };
    +// else
    +// return std::nullopt;
    +// }

    -// The other obvious function takes an optional but returns an
    -// ‘unwrapped’ value, either the result of evaluating the function or
    -// a provided alternate value.
    -//
    -template<typename T, typename F, typename U>
    -auto maybe_do_or(const std::optional<T>& t, F&& f, U&& u) ->
    - std::result_of_t<F(const std::decay_t<T>)>
    -{
    - static_assert(std::is_convertible_v<U, std::result_of_t<F(T)>>,
    - "Alternate value must be convertible to function return type.");
    - if (t)
    - return std::forward<F>(f)(*t);
    - else
    - return std::forward<U>(u);
    -}
    +// // The other obvious function takes an optional but returns an
    +// // ‘unwrapped’ value, either the result of evaluating the function or
    +// // a provided alternate value.
    +// //
    +// template<typename T, typename F, typename U>
    +// auto maybe_do_or(const std::optional<T>& t, F&& f, U&& u) ->
    +// std::result_of_t<F(const std::decay_t<T>)>
    +// {
    +// static_assert(std::is_convertible_v<U, std::result_of_t<F(T)>>,
    +// "Alternate value must be convertible to function return type.");
    +// if (t)
    +// return std::forward<F>(f)(*t);
    +// else
    +// return std::forward<U>(u);
    +// }

    namespace _convenience {
    template<typename... Ts, typename F, std::size_t... Is>
    diff --git a/src/include/any.h b/src/include/any.h
    index da59c88f48..4a3d547b1b 100644
    --- a/src/include/any.h
    +++ b/src/include/any.h
    @@ -15,7 +15,7 @@
    #ifndef INCLUDE_STATIC_ANY
    #define INCLUDE_STATIC_ANY

    -#include <any>
    +#include <boost/any.hpp>
    #include <cstddef>
    #include <initializer_list>
    #include <memory>
    @@ -298,7 +298,7 @@ public:
    // only stores the decayed type. I suspect this was to get around
    // the question of whether, for a std::any holding a T&,
    // std::any_cast<T> should return a copy or throw
    - // std::bad_any_cast.
    + // boost::bad_any_cast.
    //
    // I think the appropriate response in that case would be to make a
    // copy if the type supports it and fail otherwise. Once a concrete
    @@ -453,7 +453,7 @@ inline T any_cast(_any::base<U, V>& a) {
    if (p) {
    return static_cast<T>(*p);
    }
    - throw std::bad_any_cast();
    + throw boost::bad_any_cast();
    }

    template<typename T, typename U, typename V>
    @@ -466,7 +466,7 @@ inline T any_cast(const _any::base<U, V>& a) {
    if (p) {
    return static_cast<T>(*p);
    }
    - throw std::bad_any_cast();
    + throw boost::bad_any_cast();
    }

    template<typename T, typename U, typename V>
    @@ -478,7 +478,7 @@ any_cast(_any::base<U, V>&& a) {
    if (p) {
    return std::move((*p));
    }
    - throw std::bad_any_cast();
    + throw boost::bad_any_cast();
    }

    template<typename T, typename U, typename V>
    @@ -488,7 +488,7 @@ any_cast(_any::base<U, V>&& a) {
    if (p) {
    return static_cast<T>(*p);
    }
    - throw std::bad_any_cast();
    + throw boost::bad_any_cast();
    }

    // `immobile_any`
    diff --git a/src/include/denc.h b/src/include/denc.h
    index e95c429fb5..4c9091c47c 100644
    --- a/src/include/denc.h
    +++ b/src/include/denc.h
    @@ -27,7 +27,7 @@
    #include <array>
    #include <cstring>
    #include <map>
    -#include <optional>
    +// #include <optional>
    #include <set>
    #include <string>
    #include <type_traits>
    @@ -1288,109 +1288,109 @@ struct denc_traits<boost::none_t> {
    }
    };

    -//
    -// std::optional<T>
    -//
    -template<typename T>
    -struct denc_traits<
    - std::optional<T>,
    - std::enable_if_t<denc_traits<T>::supported>> {
    - using traits = denc_traits<T>;
    -
    - static constexpr bool supported = true;
    - static constexpr bool featured = traits::featured;
    - static constexpr bool bounded = false;
    - static constexpr bool need_contiguous = traits::need_contiguous;
    -
    - static void bound_encode(const std::optional<T>& v, size_t& p,
    - uint64_t f = 0) {
    - p += sizeof(bool);
    - if (v) {
    - if constexpr (featured) {
    - denc(*v, p, f);
    - } else {
    - denc(*v, p);
    - }
    - }
    - }
    -
    - static void encode(const std::optional<T>& v,
    - bufferlist::contiguous_appender& p,
    - uint64_t f = 0) {
    - denc((bool)v, p);
    - if (v) {
    - if constexpr (featured) {
    - denc(*v, p, f);
    - } else {
    - denc(*v, p);
    - }
    - }
    - }
    -
    - static void decode(std::optional<T>& v, buffer::ptr::iterator& p,
    - uint64_t f = 0) {
    - bool x;
    - denc(x, p, f);
    - if (x) {
    - v = T{};
    - denc(*v, p, f);
    - } else {
    - v = std::nullopt;
    - }
    - }
    -
    - template<typename U = T>
    - static std::enable_if_t<!!sizeof(U) && !need_contiguous>
    - decode(std::optional<T>& v, buffer::list::iterator& p) {
    - bool x;
    - denc(x, p);
    - if (x) {
    - v = T{};
    - denc(*v, p);
    - } else {
    - v = std::nullopt;
    - }
    - }
    -
    - static void encode_nohead(const std::optional<T>& v,
    - bufferlist::contiguous_appender& p,
    - uint64_t f = 0) {
    - if (v) {
    - if constexpr (featured) {
    - denc(*v, p, f);
    - } else {
    - denc(*v, p);
    - }
    - }
    - }
    -
    - static void decode_nohead(bool num, std::optional<T>& v,
    - buffer::ptr::iterator& p, uint64_t f = 0) {
    - if (num) {
    - v = T();
    - denc(*v, p, f);
    - } else {
    - v = std::nullopt;
    - }
    - }
    -};
    -
    -template<>
    -struct denc_traits<std::nullopt_t> {
    - static constexpr bool supported = true;
    - static constexpr bool featured = false;
    - static constexpr bool bounded = true;
    - static constexpr bool need_contiguous = false;
    -
    - static void bound_encode(const std::nullopt_t& v, size_t& p) {
    - p += sizeof(bool);
    - }
    -
    - static void encode(const std::nullopt_t& v,
    - bufferlist::contiguous_appender& p) {
    - denc(false, p);
    - }
    -};
    +// //
    +// // std::optional<T>
    +// //
    +// template<typename T>
    +// struct denc_traits<
    +// std::optional<T>,
    +// std::enable_if_t<denc_traits<T>::supported>> {
    +// using traits = denc_traits<T>;
    +
    +// static constexpr bool supported = true;
    +// static constexpr bool featured = traits::featured;
    +// static constexpr bool bounded = false;
    +// static constexpr bool need_contiguous = traits::need_contiguous;
    +
    +// static void bound_encode(const std::optional<T>& v, size_t& p,
    +// uint64_t f = 0) {
    +// p += sizeof(bool);
    +// if (v) {
    +// if constexpr (featured) {
    +// denc(*v, p, f);
    +// } else {
    +// denc(*v, p);
    +// }
    +// }
    +// }
    +
    +// static void encode(const std::optional<T>& v,
    +// bufferlist::contiguous_appender& p,
    +// uint64_t f = 0) {
    +// denc((bool)v, p);
    +// if (v) {
    +// if constexpr (featured) {
    +// denc(*v, p, f);
    +// } else {
    +// denc(*v, p);
    +// }
    +// }
    +// }
    +
    +// static void decode(std::optional<T>& v, buffer::ptr::iterator& p,
    +// uint64_t f = 0) {
    +// bool x;
    +// denc(x, p, f);
    +// if (x) {
    +// v = T{};
    +// denc(*v, p, f);
    +// } else {
    +// v = std::nullopt;
    +// }
    +// }
    +
    +// template<typename U = T>
    +// static std::enable_if_t<!!sizeof(U) && !need_contiguous>
    +// decode(std::optional<T>& v, buffer::list::iterator& p) {
    +// bool x;
    +// denc(x, p);
    +// if (x) {
    +// v = T{};
    +// denc(*v, p);
    +// } else {
    +// v = std::nullopt;
    +// }
    +// }
    +
    +// static void encode_nohead(const std::optional<T>& v,
    +// bufferlist::contiguous_appender& p,
    +// uint64_t f = 0) {
    +// if (v) {
    +// if constexpr (featured) {
    +// denc(*v, p, f);
    +// } else {
    +// denc(*v, p);
    +// }
    +// }
    +// }
    +
    +// static void decode_nohead(bool num, std::optional<T>& v,
    +// buffer::ptr::iterator& p, uint64_t f = 0) {
    +// if (num) {
    +// v = T();
    +// denc(*v, p, f);
    +// } else {
    +// v = std::nullopt;
    +// }
    +// }
    +// };
    +
    +// template<>
    +// struct denc_traits<std::nullopt_t> {
    +// static constexpr bool supported = true;
    +// static constexpr bool featured = false;
    +// static constexpr bool bounded = true;
    +// static constexpr bool need_contiguous = false;
    +
    +// static void bound_encode(const std::nullopt_t& v, size_t& p) {
    +// p += sizeof(bool);
    +// }
    +
    +// static void encode(const std::nullopt_t& v,
    +// bufferlist::contiguous_appender& p) {
    +// denc(false, p);
    +// }
    +// };

    // ----------------------------------------------------------------------
    // class helpers