| @@ -9,6 +9,9 @@ Option ( ASYNCPP_INSTALL_PACKAGE | |||
| Option ( ASYNCPP_USE_GIT_VERSION | |||
| "Read the git tags to get the version of asyncpp" | |||
| ON ) | |||
| Option ( ASYNCPP_FEATURE_TIMING_ENABLED | |||
| Option ( ASYNCPP_ENABLE_FEATURE_FS | |||
| "Enable the file system features of asyncpp" | |||
| ON ) | |||
| Option ( ASYNCPP_ENABLE_FEATURE_TIMING | |||
| "Enable the timing features of asyncpp" | |||
| ON ) | |||
| @@ -1,3 +1,4 @@ | |||
| #pragma once | |||
| #cmakedefine ASYNCPP_FEATURE_TIMING_ENABLED | |||
| #cmakedefine ASYNCPP_ENABLE_FEATURE_FS | |||
| #cmakedefine ASYNCPP_ENABLE_FEATURE_TIMING | |||
| @@ -4,6 +4,10 @@ | |||
| #include <asyncpp/core.h> | |||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||
| #ifdef ASYNCPP_ENABLE_FEATURE_FS | |||
| #include <asyncpp/fs.h> | |||
| #endif | |||
| #ifdef ASYNCPP_ENABLE_FEATURE_TIMING | |||
| #include <asyncpp/timing.h> | |||
| #endif | |||
| @@ -6,6 +6,6 @@ | |||
| #include "future/lazy.inl" | |||
| #include "future/and_then.inl" | |||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||
| #ifdef ASYNCPP_ENABLE_FEATURE_TIMING | |||
| #include "future/timeout.inl" | |||
| #endif | |||
| @@ -57,7 +57,7 @@ namespace asyncpp | |||
| typename X_lambda> | |||
| inline auto and_then(X_lambda&& p_lambda) &&; | |||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||
| #ifdef ASYNCPP_ENABLE_FEATURE_TIMING | |||
| public: | |||
| /** | |||
| * @brief Throw an execption if the timeout has passed. | |||
| @@ -6,6 +6,6 @@ | |||
| #include "stream/flatten.inl" | |||
| #include "stream/for_each.inl" | |||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||
| #ifdef ASYNCPP_ENABLE_FEATURE_TIMING | |||
| #include "stream/timeout.inl" | |||
| #endif | |||
| @@ -75,7 +75,7 @@ namespace asyncpp | |||
| chaining_mode X_mode = move> | |||
| inline auto flatten() &&; | |||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||
| #ifdef ASYNCPP_ENABLE_FEATURE_TIMING | |||
| public: | |||
| /** | |||
| * @brief Throw an execption if the timeout has passed. | |||
| @@ -1,5 +1,3 @@ | |||
| #pragma once | |||
| #include "fs/directory.h" | |||
| #include "fs/directory.inl" | |||
| @@ -1,42 +1,11 @@ | |||
| #pragma once | |||
| #include <string> | |||
| #include <cppfs/path.h> | |||
| #include <asyncpp/core/stream/stream.pre.h> | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| /** | |||
| * @brief Create future to read the content of a directory. | |||
| */ | |||
| inline auto read_dir(const cppfs::path& p_path); | |||
| /** | |||
| * @brief Create future to read the content of a directory including the subdirectories. | |||
| */ | |||
| inline auto read_dir_all(const cppfs::path& p_path); | |||
| /** | |||
| * @brief Create a new future to create a directory. | |||
| */ | |||
| inline auto create_dir(const cppfs::path& p_path); | |||
| /** | |||
| * @brief Create a new future to create a directory and all it's parent directories. | |||
| */ | |||
| inline auto create_dir_all(const cppfs::path& p_path); | |||
| /** | |||
| * @brief Create a new future to remove an empty directory. | |||
| */ | |||
| inline auto remove_dir(const cppfs::path& p_path); | |||
| /** | |||
| * @brief Create a new future to remove a directory and all it's content. | |||
| */ | |||
| inline auto remove_dir_all(const cppfs::path& p_path); | |||
| } } | |||
| #include "directory/directory.h" | |||
| #include "directory/directory.inl" | |||
| #include "directory/create.inl" | |||
| #include "directory/create_all.inl" | |||
| #include "directory/read.inl" | |||
| #include "directory/read_all.inl" | |||
| #include "directory/remove.inl" | |||
| #include "directory/remove_all.inl" | |||
| @@ -1,167 +0,0 @@ | |||
| #pragma once | |||
| #include <vector> | |||
| #include <cppfs/directory.h> | |||
| #include "directory.h" | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| namespace __impl | |||
| { | |||
| struct read_dir_impl | |||
| : public base_stream< | |||
| cppfs::directory::entry, | |||
| read_dir_impl> | |||
| { | |||
| public: | |||
| using value_type = cppfs::directory::entry; | |||
| using this_type = read_dir_impl; | |||
| using base_future_type = base_stream<value_type, this_type>; | |||
| using result_type = typename base_future_type::result_type; | |||
| private: | |||
| cppfs::directory::iterator _it; | |||
| cppfs::directory::iterator _end; | |||
| public: | |||
| inline read_dir_impl( | |||
| const cppfs::path& p_path) | |||
| { | |||
| cppfs::directory d(p_path); | |||
| if (d.exists()) | |||
| { | |||
| _it = d.begin(); | |||
| _end = d.end(); | |||
| } | |||
| } | |||
| public: | |||
| inline result_type poll() | |||
| { | |||
| if (_it == _end) | |||
| return result_type::done(); | |||
| auto ret = result_type::ready(*_it); | |||
| ++_it; | |||
| return ret; | |||
| } | |||
| }; | |||
| struct read_dir_all_impl | |||
| : public base_stream< | |||
| cppfs::directory::entry, | |||
| read_dir_all_impl> | |||
| { | |||
| public: | |||
| using value_type = cppfs::directory::entry; | |||
| using this_type = read_dir_impl; | |||
| using base_future_type = base_stream<value_type, this_type>; | |||
| using result_type = typename base_future_type::result_type; | |||
| private: | |||
| struct entry | |||
| { | |||
| cppfs::directory::iterator it; | |||
| cppfs::directory::iterator end; | |||
| }; | |||
| using entry_stack = std::vector<entry>; | |||
| entry_stack _stack; | |||
| public: | |||
| inline read_dir_all_impl( | |||
| const cppfs::path& p_path) | |||
| { | |||
| cppfs::directory d(p_path); | |||
| if (d.exists()) | |||
| { | |||
| _stack.emplace_back(entry { | |||
| d.begin(), | |||
| d.end() | |||
| }); | |||
| } | |||
| } | |||
| public: | |||
| inline result_type poll() | |||
| { | |||
| while (true) | |||
| { | |||
| if (_stack.empty()) | |||
| return result_type::done(); | |||
| auto& e = _stack.back(); | |||
| if (e.it == e.end) | |||
| { | |||
| _stack.pop_back(); | |||
| continue; | |||
| } | |||
| auto ret = result_type::ready(std::move(*e.it)); | |||
| cppfs::directory d(e.it->path); | |||
| ++e.it; | |||
| if (d.exists()) | |||
| { | |||
| _stack.emplace_back(entry { | |||
| d.begin(), | |||
| d.end(), | |||
| }); | |||
| } | |||
| return ret; | |||
| } | |||
| } | |||
| }; | |||
| } | |||
| auto read_dir(const cppfs::path& p_path) | |||
| { | |||
| return __impl::read_dir_impl(p_path); | |||
| } | |||
| auto read_dir_all(const cppfs::path& p_path) | |||
| { | |||
| return __impl::read_dir_all_impl(p_path); | |||
| } | |||
| auto create_dir(const cppfs::path& p_path) | |||
| { | |||
| return lazy([d = cppfs::directory(p_path)]{ | |||
| if (!d.exists()) | |||
| d.create(false); | |||
| }); | |||
| } | |||
| auto create_dir_all(const cppfs::path& p_path) | |||
| { | |||
| return lazy([d = cppfs::directory(p_path)]{ | |||
| if (!d.exists()) | |||
| d.create(true); | |||
| }); | |||
| } | |||
| auto remove_dir(const cppfs::path& p_path) | |||
| { | |||
| return lazy([d = cppfs::directory(p_path)]{ | |||
| if (d.exists()) | |||
| d.remove(false); | |||
| }); | |||
| } | |||
| auto remove_dir_all(const cppfs::path& p_path) | |||
| { | |||
| return lazy([d = cppfs::directory(p_path)]{ | |||
| if (d.exists()) | |||
| d.remove(true); | |||
| }); | |||
| } | |||
| } } | |||
| @@ -0,0 +1,49 @@ | |||
| #pragma once | |||
| #include <asyncpp/core/future/future.h> | |||
| #include "directory.h" | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| namespace __directory { | |||
| template< | |||
| chaining_mode X_mode, | |||
| typename X_self> | |||
| inline auto create_impl(X_self&& p_self) | |||
| { | |||
| return lazy([self = std::forward<X_self>(p_self)] { | |||
| if (!self.handle.exists()) | |||
| self.handle.create(false); | |||
| return self; // TODO: use std::forward | |||
| }); | |||
| } | |||
| } } } | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| /* directory::create */ | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::create() & | |||
| { | |||
| return __directory::create_impl<X_mode>(*this); | |||
| } | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::create() && | |||
| { | |||
| static_assert( | |||
| X_mode != ref, | |||
| "Can not store rvalue reference as lvalue reference!"); | |||
| return __directory::create_impl<X_mode>(std::move(*this)); | |||
| } | |||
| } } | |||
| @@ -0,0 +1,49 @@ | |||
| #pragma once | |||
| #include <asyncpp/core/future/future.h> | |||
| #include "directory.h" | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| namespace __directory { | |||
| template< | |||
| chaining_mode X_mode, | |||
| typename X_self> | |||
| inline auto create_all_impl(X_self&& p_self) | |||
| { | |||
| return lazy([self = std::forward<X_self>(p_self)] { | |||
| if (!self.handle.exists()) | |||
| self.handle.create(true); | |||
| return self; // TODO: use std::forward | |||
| }); | |||
| } | |||
| } } } | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| /* directory::create */ | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::create_all() & | |||
| { | |||
| return __directory::create_all_impl<X_mode>(*this); | |||
| } | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::create_all() && | |||
| { | |||
| static_assert( | |||
| X_mode != ref, | |||
| "Can not store rvalue reference as lvalue reference!"); | |||
| return __directory::create_all_impl<X_mode>(std::move(*this)); | |||
| } | |||
| } } | |||
| @@ -0,0 +1,100 @@ | |||
| #pragma once | |||
| #include <cppfs/directory.h> | |||
| #include <asyncpp/core/misc/chaining.h> | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| struct directory | |||
| { | |||
| public: | |||
| cppfs::directory handle; | |||
| public: | |||
| /** | |||
| * @brief Constructor. | |||
| */ | |||
| inline directory(const cppfs::path& p_path); | |||
| public: | |||
| /** | |||
| * @brief Create a new future to create a directory. | |||
| */ | |||
| template<chaining_mode X_mode = copy> | |||
| inline auto create() &; | |||
| /** | |||
| * @brief Create a new future to create a directory. | |||
| */ | |||
| template<chaining_mode X_mode = move> | |||
| inline auto create() &&; | |||
| public: | |||
| /** | |||
| * @brief Create a new future to create a directory and all it's parent directories. | |||
| */ | |||
| template<chaining_mode X_mode = copy> | |||
| inline auto create_all() &; | |||
| /** | |||
| * @brief Create a new future to create a directory and all it's parent directories. | |||
| */ | |||
| template<chaining_mode X_mode = move> | |||
| inline auto create_all() &&; | |||
| public: | |||
| /** | |||
| * @brief Create future to read the content of a directory. | |||
| */ | |||
| template<chaining_mode X_mode = copy> | |||
| inline auto read() &; | |||
| /** | |||
| * @brief Create future to read the content of a directory. | |||
| */ | |||
| template<chaining_mode X_mode = move> | |||
| inline auto read() &&; | |||
| public: | |||
| /** | |||
| * @brief Create future to read the content of a directory including the subdirectories. | |||
| */ | |||
| template<chaining_mode X_mode = copy> | |||
| inline auto read_all() &; | |||
| /** | |||
| * @brief Create future to read the content of a directory including the subdirectories. | |||
| */ | |||
| template<chaining_mode X_mode = move> | |||
| inline auto read_all() &&; | |||
| public: | |||
| /** | |||
| * @brief Create a new future to remove an empty directory. | |||
| */ | |||
| template<chaining_mode X_mode = copy> | |||
| inline auto remove() &; | |||
| /** | |||
| * @brief Create a new future to remove an empty directory. | |||
| */ | |||
| template<chaining_mode X_mode = move> | |||
| inline auto remove() &&; | |||
| public: | |||
| /** | |||
| * @brief Create a new future to remove a directory and all it's content. | |||
| */ | |||
| template<chaining_mode X_mode = copy> | |||
| inline auto remove_all() &; | |||
| /** | |||
| * @brief Create a new future to remove a directory and all it's content. | |||
| */ | |||
| template<chaining_mode X_mode = move> | |||
| inline auto remove_all() &&; | |||
| }; | |||
| } } | |||
| @@ -0,0 +1,14 @@ | |||
| #pragma once | |||
| #include "directory.h" | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| /* directory */ | |||
| inline directory::directory(const cppfs::path& p_path) | |||
| : handle(p_path) | |||
| { } | |||
| } } | |||
| @@ -0,0 +1,80 @@ | |||
| #pragma once | |||
| #include <cppfs/directory.h> | |||
| #include "directory.h" | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| namespace __directory { | |||
| struct read_stream | |||
| : public base_stream< | |||
| cppfs::directory::entry, | |||
| read_stream> | |||
| { | |||
| public: | |||
| using value_type = cppfs::directory::entry; | |||
| using this_type = read_stream; | |||
| using base_future_type = base_stream<value_type, this_type>; | |||
| using result_type = typename base_future_type::result_type; | |||
| private: | |||
| cppfs::directory::iterator _it; | |||
| cppfs::directory::iterator _end; | |||
| public: | |||
| inline read_stream( | |||
| const fs::directory& p_directory) | |||
| { | |||
| auto& d = p_directory.handle; | |||
| if (d.exists()) | |||
| { | |||
| _it = d.begin(); | |||
| _end = d.end(); | |||
| } | |||
| } | |||
| public: | |||
| inline result_type poll() | |||
| { | |||
| if (_it == _end) | |||
| return result_type::done(); | |||
| auto ret = result_type::ready(*_it); | |||
| ++_it; | |||
| return ret; | |||
| } | |||
| }; | |||
| template< | |||
| chaining_mode X_mode, | |||
| typename X_self> | |||
| inline auto read_impl(X_self&& p_self) | |||
| { return read_stream(std::forward<X_self>(p_self)); } | |||
| } } } | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::read() & | |||
| { | |||
| return __directory::read_impl<X_mode>(*this); | |||
| } | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::read() && | |||
| { | |||
| static_assert( | |||
| X_mode != ref, | |||
| "Can not store rvalue reference as lvalue reference!"); | |||
| return __directory::read_impl<X_mode>(std::move(*this)); | |||
| } | |||
| } } | |||
| @@ -0,0 +1,111 @@ | |||
| #pragma once | |||
| #include <vector> | |||
| #include <cppfs/directory.h> | |||
| #include "directory.h" | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| namespace __directory { | |||
| struct read_all_stream | |||
| : public base_stream< | |||
| cppfs::directory::entry, | |||
| read_all_stream> | |||
| { | |||
| public: | |||
| using value_type = cppfs::directory::entry; | |||
| using this_type = read_all_stream; | |||
| using base_future_type = base_stream<value_type, this_type>; | |||
| using result_type = typename base_future_type::result_type; | |||
| private: | |||
| struct entry | |||
| { | |||
| cppfs::directory::iterator it; | |||
| cppfs::directory::iterator end; | |||
| }; | |||
| using entry_stack = std::vector<entry>; | |||
| entry_stack _stack; | |||
| public: | |||
| inline read_all_stream( | |||
| const fs::directory& p_directory) | |||
| { | |||
| auto& d = p_directory.handle; | |||
| if (d.exists()) | |||
| { | |||
| _stack.emplace_back(entry { | |||
| d.begin(), | |||
| d.end() | |||
| }); | |||
| } | |||
| } | |||
| public: | |||
| inline result_type poll() | |||
| { | |||
| while (true) | |||
| { | |||
| if (_stack.empty()) | |||
| return result_type::done(); | |||
| auto& e = _stack.back(); | |||
| if (e.it == e.end) | |||
| { | |||
| _stack.pop_back(); | |||
| continue; | |||
| } | |||
| auto ret = result_type::ready(std::move(*e.it)); | |||
| cppfs::directory d(e.it->path); | |||
| ++e.it; | |||
| if (d.exists()) | |||
| { | |||
| _stack.emplace_back(entry { | |||
| d.begin(), | |||
| d.end(), | |||
| }); | |||
| } | |||
| return ret; | |||
| } | |||
| } | |||
| }; | |||
| template< | |||
| chaining_mode X_mode, | |||
| typename X_self> | |||
| inline auto read_all_impl(X_self&& p_self) | |||
| { return read_all_stream(std::forward<X_self>(p_self)); } | |||
| } } } | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::read_all() & | |||
| { | |||
| return __directory::read_all_impl<X_mode>(*this); | |||
| } | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::read_all() && | |||
| { | |||
| static_assert( | |||
| X_mode != ref, | |||
| "Can not store rvalue reference as lvalue reference!"); | |||
| return __directory::read_all_impl<X_mode>(std::move(*this)); | |||
| } | |||
| } } | |||
| @@ -0,0 +1,49 @@ | |||
| #pragma once | |||
| #include <asyncpp/core/future/future.h> | |||
| #include "directory.h" | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| namespace __directory { | |||
| template< | |||
| chaining_mode X_mode, | |||
| typename X_self> | |||
| inline auto remove_impl(X_self&& p_self) | |||
| { | |||
| return lazy([self = std::forward<X_self>(p_self)] { | |||
| if (self.handle.exists()) | |||
| self.handle.remove(false); | |||
| return self; // TODO: use std::forward | |||
| }); | |||
| } | |||
| } } } | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| /* directory::remove */ | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::remove() & | |||
| { | |||
| return __directory::remove_impl<X_mode>(*this); | |||
| } | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::remove() && | |||
| { | |||
| static_assert( | |||
| X_mode != ref, | |||
| "Can not store rvalue reference as lvalue reference!"); | |||
| return __directory::remove_impl<X_mode>(std::move(*this)); | |||
| } | |||
| } } | |||
| @@ -0,0 +1,49 @@ | |||
| #pragma once | |||
| #include <asyncpp/core/future/future.h> | |||
| #include "directory.h" | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| namespace __directory { | |||
| template< | |||
| chaining_mode X_mode, | |||
| typename X_self> | |||
| inline auto remove_all_impl(X_self&& p_self) | |||
| { | |||
| return lazy([self = std::forward<X_self>(p_self)] { | |||
| if (self.handle.exists()) | |||
| self.handle.remove(true); | |||
| return self; // TODO: use std::forward | |||
| }); | |||
| } | |||
| } } } | |||
| namespace asyncpp { | |||
| namespace fs { | |||
| /* directory::create */ | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::remove_all() & | |||
| { | |||
| return __directory::remove_all_impl<X_mode>(*this); | |||
| } | |||
| template<chaining_mode X_mode> | |||
| auto directory | |||
| ::remove_all() && | |||
| { | |||
| static_assert( | |||
| X_mode != ref, | |||
| "Can not store rvalue reference as lvalue reference!"); | |||
| return __directory::remove_all_impl<X_mode>(std::move(*this)); | |||
| } | |||
| } } | |||
| @@ -1,6 +1,6 @@ | |||
| #pragma once | |||
| #define ASYNCPP_FEATURE_TIMING_ENABLED | |||
| #define ASYNCPP_ENABLE_FEATURE_TIMING | |||
| #include "timing/delay.h" | |||
| #include "timing/interval.h" | |||
| @@ -67,7 +67,7 @@ TEST_F(directory_tests, read_dir) | |||
| using namespace cppfs; | |||
| using namespace std::string_literals; | |||
| auto s = fs::read_dir("."s); | |||
| auto s = fs::directory("."s).read(); | |||
| auto v = std::vector<std::string>(); | |||
| auto r = decltype(s)::result_type::not_ready(); | |||
| @@ -89,7 +89,7 @@ TEST_F(directory_tests, read_dir_all) | |||
| using namespace cppfs; | |||
| using namespace std::string_literals; | |||
| auto s = fs::read_dir_all("."s); | |||
| auto s = fs::directory("."s).read_all(); | |||
| auto r = decltype(s)::result_type::not_ready(); | |||
| auto entries = std::vector<cppfs::directory::entry>(); | |||
| @@ -137,11 +137,8 @@ TEST_F(directory_tests, read_dir_all) | |||
| TEST_F(directory_tests, create_dir) | |||
| { | |||
| auto f = | |||
| lazy([path=path_test_dir_single()]{ | |||
| return path; | |||
| }) | |||
| .and_then(fs::create_dir); | |||
| auto f = fs::directory(path_test_dir_single()) | |||
| .create(); | |||
| auto_remove_dir d(path_test_dir_single()); | |||
| @@ -155,11 +152,8 @@ TEST_F(directory_tests, create_dir) | |||
| TEST_F(directory_tests, create_dir_all) | |||
| { | |||
| auto f = | |||
| lazy([path=path_test_dir_child()]{ | |||
| return path; | |||
| }) | |||
| .and_then(fs::create_dir_all); | |||
| auto f = fs::directory(path_test_dir_child()) | |||
| .create_all(); | |||
| auto_remove_dir d(path_test_dir_child()); | |||
| @@ -173,11 +167,8 @@ TEST_F(directory_tests, create_dir_all) | |||
| TEST_F(directory_tests, remove_dir) | |||
| { | |||
| auto f = | |||
| lazy([path=path_test_dir_single()]{ | |||
| return path; | |||
| }) | |||
| .and_then(fs::remove_dir); | |||
| auto f = fs::directory(path_test_dir_single()) | |||
| .remove(); | |||
| auto_remove_dir d(path_test_dir_single()); | |||
| d.create(true); | |||
| @@ -192,11 +183,8 @@ TEST_F(directory_tests, remove_dir) | |||
| TEST_F(directory_tests, remove_dir_all) | |||
| { | |||
| auto f = | |||
| lazy([path=path_test_dir_parent()]{ | |||
| return path; | |||
| }) | |||
| .and_then(fs::remove_dir_all); | |||
| auto f = fs::directory(path_test_dir_child()) | |||
| .remove_all(); | |||
| auto_remove_dir d(path_test_dir_child()); | |||
| d.create(true); | |||