-
Notifications
You must be signed in to change notification settings - Fork 151
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Documentation for Proxy 3 * Remove en-us directory * Update doc for basic_facade_builder::add_facade * readme
- Loading branch information
Showing
52 changed files
with
2,762 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Macro `PRO_DEF_FREE_DISPATCH` | ||
|
||
```cpp | ||
#define PRO_DEF_FREE_DISPATCH // see below | ||
``` | ||
Macro `PRO_DEF_FREE_DISPATCH` defines dispatch types for free function expressions with accessibility. It supports two syntaxes: | ||
```cpp | ||
// (1) | ||
PRO_DEF_FREE_DISPATCH(dispatch_name, func_name); | ||
// (2) | ||
PRO_DEF_FREE_DISPATCH(dispatch_name, func_name, accessibility_func_name); | ||
``` | ||
|
||
`(1)` Equivalent to `PRO_DEF_FREE_DISPATCH(dispatch_name, func_name, func_name);` | ||
|
||
`(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility. `dispatch_name` meets the [*ProAccessible*](ProAccessible.md) requirements of types `F`, `C`, and `Os...`, where `F` models concept [`facade`](facade.md), `C` is a tuple element type defined in `typename F::convention_types`, and each type `O` (possibly qualified with *cv ref noex*) in `Os...` is a tuple element type defined in `typename C::overload_types`. The functions provided by `typename dispatch_name::template accessor<F, C, Os...>` are named `accessibility_func_name` and can be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `accessor` is an associated class of the arguments. Let `SELF` be `std::forward<accessor cv ref>(self)`, effectively equivalent to: | ||
|
||
```cpp | ||
struct dispatch_name { | ||
template <class T, class... Args> | ||
decltype(auto) operator()(T&& self, Args&&... args) | ||
noexcept(noexcept(func_name(std::forward<T>(self), std::forward<Args>(args)...))) | ||
requires(requires { func_name(std::forward<T>(self), std::forward<Args>(args)...); }) { | ||
return func_name(std::forward<T>(self), std::forward<Args>(args)...); | ||
} | ||
|
||
template <class F, class C, class... Os> struct accessor { | ||
accessor() = delete; | ||
}; | ||
template <class F, class C, class... Os> | ||
requires(sizeof...(Os) > 1u && (std::is_trivial_v<accessor<F, C, Os>> && ...)) | ||
struct accessor<F, C, Os...> : accessor<F, C, Os>... {}; | ||
template <class F, class C, class R, class... Args> | ||
struct accessor<F, C, R(Args...) cv ref noex> { | ||
friend R accessibility_func_name(accessor cv ref self, Args... args) noex { | ||
return pro::proxy_invoke<C>(pro::access_proxy<F>(SELF), std::forward<Args>(args)...); | ||
} | ||
}; | ||
}; | ||
``` | ||
## Example | ||
```cpp | ||
#include <iostream> | ||
#include <string> | ||
#include "proxy.h" | ||
PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); | ||
struct Stringable : pro::facade_builder | ||
::add_convention<FreeToString, std::string()> | ||
::build {}; | ||
int main() { | ||
pro::proxy<Stringable> p = pro::make_proxy<Stringable>(123); | ||
std::cout << ToString(*p) << "\n"; // Prints: "123" | ||
} | ||
``` | ||
|
||
## See Also | ||
|
||
- [macro `PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md) | ||
- [alias template `basic_facade_builder::add_convention`](basic_facade_builder/add_convention.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Macro `PRO_DEF_MEM_DISPATCH` | ||
|
||
```cpp | ||
#define PRO_DEF_MEM_DISPATCH // see below | ||
``` | ||
Macro `PRO_DEF_MEM_DISPATCH` defines dispatch types for member function expressions with accessibility. It supports two syntaxes: | ||
```cpp | ||
// (1) | ||
PRO_DEF_MEM_DISPATCH(dispatch_name, func_name); | ||
// (2) | ||
PRO_DEF_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name); | ||
``` | ||
|
||
`(1)` Equivalent to `PRO_DEF_MEM_DISPATCH(dispatch_name, func_name, func_name);` | ||
|
||
`(2)` Defines a class named `dispatch_name` of member function call expressions of `func_name` with accessibility. `dispatch_name` meets the [*ProAccessible*](ProAccessible.md) requirements of types `F`, `C`, and `Os...`, where `F` models concept [`facade`](facade.md), `C` is a tuple element type defined in `typename F::convention_types`, and each type `O` (possibly qualified with *cv, ref, noex*) in `Os...` is a tuple element type defined in `typename C::overload_types`. The member functions provided by `typename dispatch_name::template accessor<F, C, Os...>` are named `accessibility_func_name`. Let `SELF` be `std::forward<accessor cv ref>(*this)`, effectively equivalent to: | ||
|
||
```cpp | ||
struct dispatch_name { | ||
template <class T, class... Args> | ||
decltype(auto) operator()(T&& self, Args&&... args) | ||
noexcept(noexcept(std::forward<T>(self).func_name(std::forward<Args>(args)...))) | ||
requires(requires { std::forward<T>(self).func_name(std::forward<Args>(args)...); }) { | ||
return std::forward<T>(self).func_name(std::forward<Args>(args)...); | ||
} | ||
|
||
template <class F, class C, class... Os> | ||
struct accessor { | ||
accessor() = delete; | ||
}; | ||
template <class F, class C, class... Os> | ||
requires(sizeof...(Os) > 1u && (std::is_trivial_v<accessor<F, C, Os>> && ...)) | ||
struct accessor<F, C, Os...> : accessor<F, C, Os>... { | ||
using accessor<F, C, Os>::accessibility_func_name ...; | ||
}; | ||
template <class F, class C, class R, class... Args> | ||
struct accessor<F, C, R(Args...) cv ref noex> { | ||
R accessibility_func_name(Args... args) cv ref noex { | ||
return pro::proxy_invoke<C>(pro::access_proxy<F>(SELF), std::forward<Args>(args)...); | ||
} | ||
}; | ||
}; | ||
``` | ||
## Example | ||
```cpp | ||
#include <iostream> | ||
#include <string> | ||
#include <vector> | ||
#include "proxy.h" | ||
PRO_DEF_MEM_DISPATCH(MemAt, at); | ||
struct Dictionary : pro::facade_builder | ||
::add_convention<MemAt, std::string(int index) const> | ||
::build {}; | ||
int main() { | ||
std::vector<const char*> v{"hello", "world"}; | ||
pro::proxy<Dictionary> p = &v; | ||
std::cout << p->at(1) << "\n"; // Prints: "world" | ||
} | ||
``` | ||
|
||
## See Also | ||
|
||
- [macro `PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md) | ||
- [alias template `basic_facade_builder::add_convention`](basic_facade_builder/add_convention.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Macro `PRO_DEF_WEAK_DISPATCH` | ||
|
||
```cpp | ||
#define PRO_DEF_WEAK_DISPATCH // see below | ||
``` | ||
Macro `PRO_DEF_WEAK_DISPATCH` defines a "weak" dispatch type with a default implementation. It supports the following syntax: | ||
```cpp | ||
PRO_DEF_WEAK_DISPATCH(dispatch_name, existing_dispatch, default_func_name); | ||
``` | ||
|
||
Defines a class named `dispatch_name` that inherits `existing_dispatch` and provides additional overloads of `operator()` calling `default_func_name`. Effectively equivalent to: | ||
|
||
```cpp | ||
struct dispatch_name : existing_dispatch { | ||
using existing_dispatch::operator(); | ||
template <class... Args> | ||
decltype(auto) operator()(std::nullptr_t, Args&&... args) | ||
noexcept(noexcept(default_func_name(std::forward<Args>(args)...))) | ||
requires(requires { default_func_name(std::forward<Args>(args)...); }) { | ||
return default_func_name(std::forward<Args>(args)...); | ||
} | ||
}; | ||
``` | ||
## Notes | ||
A weak dispatch can extend an existing dispatch with a default implementation. This is useful when instantiating a `proxy<F>` with a value that does not support some conventions defined by `F`. Similar with [`PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md), `default_func_name` can be the name of an arbitrary function or anything that supports `()` syntax, including a constructor. | ||
## Example | ||
```cpp | ||
#include <iostream> | ||
#include <string> | ||
#include <vector> | ||
#include "proxy.h" | ||
struct NotImplemented { | ||
explicit NotImplemented(auto&&...) { throw std::runtime_error{ "Not implemented!" }; } | ||
template <class T> | ||
operator T() const noexcept { std::terminate(); } // Or std::unreachable() in C++23 | ||
}; | ||
PRO_DEF_MEM_DISPATCH(MemAt, at); | ||
PRO_DEF_WEAK_DISPATCH(WeakMemAt, MemAt, NotImplemented); | ||
struct WeakDictionary : pro::facade_builder | ||
::add_convention<WeakMemAt, std::string(int index) const> | ||
::build {}; | ||
int main() { | ||
std::vector<const char*> v{"hello", "world"}; | ||
pro::proxy<WeakDictionary> p1 = &v; | ||
std::cout << p1->at(1) << "\n"; // Prints: "world" | ||
pro::proxy<WeakDictionary> p2 = pro::make_proxy<WeakDictionary>(123); | ||
try { | ||
p2->at(1); | ||
} catch (const std::runtime_error& e) { | ||
std::cout << e.what() << "\n"; // Prints: "Not implemented!" | ||
} | ||
} | ||
``` | ||
|
||
## See Also | ||
|
||
- [named requirements *ProDispatch*](ProDispatch.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Named requirements: *ProAccessible* | ||
|
||
Given that `F` is a type meeting the [*ProBasicFacade* requirements](ProBasicFacade.md), a type `T` meets the *ProAccessible* requirements of types `F, Args...`, if the following expressions are well-formed and have the specified semantics. | ||
|
||
| Expressions | Semantics | | ||
| ------------------------------------------- | ------------------------------------------------------------ | | ||
| `typename T::template accessor<F, Args...>` | A type that provides accessibility to `proxy`. It shall be a trivial class type and not [final](https://en.cppreference.com/w/cpp/language/final). | | ||
|
||
## See Also | ||
|
||
- [class template `proxy`](proxy.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Named requirements: *ProBasicConvention* | ||
|
||
A type `C` meets the *ProBasicConvention* requirements if the following expressions are well-formed and have the specified semantics. | ||
|
||
| Expressions | Semantics | | ||
| ---------------------------- | ------------------------------------------------------------ | | ||
| `C::is_direct` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type `bool`, specifying whether the convention applies to a pointer type itself (`true`), or the element type of a pointer type (`false`). | | ||
| `typename C::dispatch_type` | A [trivial type](https://en.cppreference.com/w/cpp/named_req/TrivialType) that defines how the calls are forwarded to the concrete types. | | ||
| `typename C::overload_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of one or more distinct types `Os`. Each type `O` in `Os` shall meet the [*ProOverload* requirements](ProOverload.md). | | ||
|
||
## See Also | ||
|
||
- [*ProBasicFacade* requirements](ProBasicFacade.md) | ||
- [*ProConvention* requirements](ProConvention.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Named requirements: *ProBasicFacade* | ||
|
||
A type `F` meets the *ProBasicFacade* requirements if the following expressions are well-formed and have the specified semantics. | ||
|
||
| Expressions | Semantics | | ||
| ------------------------------ | ------------------------------------------------------------ | | ||
| `typename F::convention_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains any number of distinct types `Cs`. Each type `C` in `Cs` shall meet the [*ProBasicConvention* requirements](ProBasicConvention.md). | | ||
| `typename F::reflection_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains any number of distinct types `Rs`. Each type `R` in `Rs` shall define reflection on pointer types. | | ||
| `F::constraints` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type [`proxiable_ptr_constraints`](proxiable_ptr_constraints.md) that defines constraints to pointer types. | | ||
|
||
## See Also | ||
|
||
- [concept `facade`](facade.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Named requirements: *ProConvention* | ||
|
||
A type `C` meets the *ProConvention* requirements of a type `P` if `C` meets the [*ProBasicConvention* requirements](ProBasicConvention.md), and the following expressions are well-formed and have the specified semantics. | ||
|
||
| Expressions | Semantics | | ||
| ---------------------------- | ------------------------------------------------------------ | | ||
| `typename C::overload_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains one or more distinct types `Os`. Each type `O` in `Os` shall meet the [*ProOverload* requirements](ProOverload.md), and<br />- when `C::is_direct` is `true`, `typename C::dispatch_type` shall meet the [*ProDispatch* requirements](ProDispatch.md) of `P` and `O`, <br />- or otherwise, when `C::is_direct` is `false`, let `QP` be a qualified reference type of `P` with the *cv ref* qualifiers defined by `O` (`QP` is an lvalue reference type if `O` does not define a *ref* qualifier), `qp` be a value of `QP`, `*std::forward<QP>(qp)` shall be well-formed, and `typename C::dispatch_type` shall meet the [*ProDispatch* requirements](ProDispatch.md) of `decltype(*std::forward<QP>(qp))` and `O`. | | ||
|
||
## See Also | ||
|
||
- [*ProFacade* requirements](ProFacade.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Named requirements: *ProDispatch* | ||
|
||
A type `D` meets the *ProDispatch* requirements of types `T` and `O` if `D` is a [trivial type](https://en.cppreference.com/w/cpp/named_req/TrivialType), `O` meets the [*ProOverload* requirelemts](ProOverload.md), and the following expressions are well-formed and have the specified semantics (let `R` be return type of `O`, `Args...` be the argument types of `O`. `args...` denotes values of type `Args...`, `v` denotes a value of type `T`, `cv` denotes a value of type `const T`). | ||
|
||
| Definitions of `O` | Expressions | Semantics | | ||
| ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | ||
| `R(Args...)` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, v, std::forward<Args>(args)...)` | Invokes dispatch type `D` with an lvalue reference of type `T` and `args...`, may throw. | | ||
| `R(Args...) noexcept` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, v, std::forward<Args>(args)...)` | Invokes dispatch type `D` with an lvalue reference of type `T` and `args...`, shall not throw. | | ||
| `R(Args...) &` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, v, std::forward<Args>(args)...)` | Invokes dispatch type `D` with an lvalue reference of type `T` and `args...`, may throw. | | ||
| `R(Args...) & noexcept` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, v, std::forward<Args>(args)...)` | Invokes dispatch type `D` with an lvalue reference of type `T` and `args...`, shall not throw. | | ||
| `R(Args...) &&` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, std::move(v), std::forward<Args>(args)...)` | Invokes dispatch type `D` with a rvalue reference of type `T` and `args...`, may throw. | | ||
| `R(Args...) && noexcept` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, std::move(v), std::forward<Args>(args)...)` | Invokes dispatch type `D` with a rvalue reference of type `T` and `args...`, shall not throw. | | ||
| `R(Args...) const` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, cv, std::forward<Args>(args)...)` | Invokes dispatch type `D` with a const reference of type `T` and `args...`, may throw. | | ||
| `R(Args...) const noexcept` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, cv, std::forward<Args>(args)...)` | Invokes dispatch type `D` with a const reference of type `T` and `args...`, shall not throw. | | ||
| `R(Args...) cosnt&` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, cv, std::forward<Args>(args)...)`, or<br />`d(nullptr, std::forward<Args>(args)...)` | Invokes dispatch type `D` with a const reference of type `T` and `args...`, may throw. | | ||
| `R(Args...) const& noexcept` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, cv, std::forward<Args>(args)...)` | Invokes dispatch type `D` with a const reference of type `T` and `args...`, shall not throw. | | ||
| `R(Args...) const&&` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, std::move(cv), std::forward<Args>(args)...)` | Invokes dispatch type `D` with a const rvalue reference of type `T` and `args...`, may throw. | | ||
| `R(Args...) const&& noexcept` | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, std::move(cv), std::forward<Args>(args)...)` | Invokes dispatch type `D` with a const rvalue reference of type `T` and `args...`, shall not throw. | | ||
|
||
Or, | ||
|
||
| Definitions of `O` | Expressions | Semantics | | ||
| -------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | ||
| `R(Args...)` *cv ref noex* | [`INVOKE<R>`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, nullptr, std::forward<Args>(args)...)` | Invokes the dispatch type `D` with `nullptr` and `args...`, may or may not throw depending on `noex`. | | ||
|
||
## See Also | ||
|
||
- [*ProConvention* requirements](ProConvention.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Named requirements: *ProFacade* | ||
|
||
A type `F` meets the *ProFacade* requirements of a type `P` if `F` meets the [*ProBasicFacade* requirements](ProBasicFacade.md), and `P` meets the requirements defined by [`F::constraints`](proxiable_ptr_constraints.md), and the following expressions are well-formed and have the specified semantics. | ||
|
||
| Expressions | Semantics | | ||
| ------------------------------ | ------------------------------------------------------------ | | ||
| `typename F::convention_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains any number of distinct types `Cs`. Each type `C` in `Cs` shall meet the [*ProConvention* requirements](ProConvention.md) of `P`. | | ||
| `typename F::reflection_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains any number of distinct types `Rs`. Each type `R` in `Rs` shall meet the [*ProReflection* requirements](ProReflection.md) of `P`. | | ||
|
||
## See Also | ||
|
||
- [concept `proxiable`](proxiable.md) | ||
- [*ProBasicFacade* requirements](ProBasicFacade.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Named requirements: *ProOverload* | ||
|
||
A type `O` meets the *ProOverload* requirements if it matches one of the following definitions, where `R` is the *return type*, `Args...` are the *argument types*. | ||
|
||
| Definitions of `O` | | ||
| ----------------------------- | | ||
| `R(Args...)` | | ||
| `R(Args...) noexcept` | | ||
| `R(Args...) &` | | ||
| `R(Args...) & noexcept` | | ||
| `R(Args...) &&` | | ||
| `R(Args...) && noexcept` | | ||
| `R(Args...) const` | | ||
| `R(Args...) const noexcept` | | ||
| `R(Args...) cosnt&` | | ||
| `R(Args...) const& noexcept` | | ||
| `R(Args...) const&&` | | ||
| `R(Args...) const&& noexcept` | | ||
|
||
## See Also | ||
|
||
- [*ProConvention* requirements](ProConvention.md) | ||
- [class template `std::move_only_function`](https://en.cppreference.com/w/cpp/utility/functional/move_only_function) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Named requirements: *ProReflection* | ||
|
||
A type `R` meets the *ProReflection* requirements of a type `P` if the following expressions are well-formed and have the specified semantics. | ||
|
||
| Expressions | Semantics | | ||
| -------------------------- | ------------------------------------------------------------ | | ||
| `R{std::in_place_type<P>}` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) that constructs a value of type `R`, reflecting implementation-defined metadata of type `P`. | | ||
|
||
## See Also | ||
|
||
[*ProFacade* requirements](ProFacade.md) |
Oops, something went wrong.