1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/docs/wiki/ClientLibrary Sat Aug 28 00:28:17 2021 +0200
1.3 @@ -0,0 +1,146 @@
1.4 += Client Library =
1.5 +
1.6 +The filesystem client library offers abstractions and a number of layers of
1.7 +functionality to support interaction with [[Components|components]] and the
1.8 +provision of higher-level mechanisms and abstractions for file access.
1.9 +
1.10 +<<TableOfContents(2,3)>>
1.11 +
1.12 +== File Data Structures ==
1.13 +
1.14 +Since files are accessed using file references, the `file_t` data structure is
1.15 +used to wrap such references and other relevant state. Thus, such structures
1.16 +can be broadly regarded as similar to the traditional `FILE` data structure.
1.17 +
1.18 +The fields of the `file_t` data structure are as follows:
1.19 +
1.20 +|| '''Field''' || '''Description''' ||
1.21 +|| `memory` || The memory address of the exposed file region ||
1.22 +|| `start_pos` || The start position of the region in the file ||
1.23 +|| `end_pos` || The end position of the region in the file ||
1.24 +|| `data_end` || The amount or extent of populated data in the region ||
1.25 +|| `data_current` || The offset used to track client position in the region ||
1.26 +|| `size` || The total size of the file ||
1.27 +|| `object_flags` || Flags indicating support for certain file features ||
1.28 +|| `can_block` || Notification flags for blocking access to the file ||
1.29 +|| `notifications`|| Notification flags set for the file ||
1.30 +
1.31 +== Client Programming Interface ==
1.32 +
1.33 +The client programming interface provides functions somewhat resembling the
1.34 +traditional C library and low-level Unix interfaces for file access, and these
1.35 +functions are intended to support such traditional interfaces.
1.36 +
1.37 +=== Files ===
1.38 +
1.39 +Files are opened and closed using the following functions:
1.40 +
1.41 +{{{
1.42 +file_t *client_open(const char *name, flags_t flags);
1.43 +}}}
1.44 +
1.45 +Each file endpoint may be closed using `client_close`.
1.46 +
1.47 +=== Pipes ===
1.48 +
1.49 +Pipes are opened using a special function:
1.50 +
1.51 +{{{
1.52 +long client_pipe(file_t **reader, file_t **writer, flags_t flags);
1.53 +}}}
1.54 +
1.55 +Each pipe endpoint may be closed using `client_close`.
1.56 +
1.57 +=== Closing Files and Pipes ===
1.58 +
1.59 +Closing files and pipes involves a common operation:
1.60 +
1.61 +{{{
1.62 +void client_close(file_t *file);
1.63 +}}}
1.64 +
1.65 +When client programs terminate, the freeing of their object capabilities
1.66 +should cause the closure of files and pipes, but programs may choose to close
1.67 +such resources explicitly.
1.68 +
1.69 +=== Reading and Writing ===
1.70 +
1.71 +Reading and writing files and pipes involves functions resembling the
1.72 +traditional low-level `read` and `write` functions:
1.73 +
1.74 +{{{
1.75 +offset_t client_read(file_t *file, void *buf, offset_t count);
1.76 +offset_t client_write(file_t *file, const void *buf, offset_t count);
1.77 +}}}
1.78 +
1.79 +=== Navigation in Files ===
1.80 +
1.81 +Support for navigation in files is provided using functions resembling the
1.82 +traditional higher-level `fseek` and `ftell` functions:
1.83 +
1.84 +{{{
1.85 +offset_t client_seek(file_t *file, offset_t offset, int whence);
1.86 +long client_tell(file_t *file);
1.87 +}}}
1.88 +
1.89 +=== Accessing Exposed Memory Regions ===
1.90 +
1.91 +Although the client library (and the provision of files) employs mapped
1.92 +memory, a function can be used to explicitly reference memory for file access:
1.93 +
1.94 +{{{
1.95 +void *client_mmap(file_t *file, offset_t position, offset_t length);
1.96 +}}}
1.97 +
1.98 +Pipes support a different mechanism for navigation involving the following
1.99 +functions:
1.100 +
1.101 +{{{
1.102 +long client_current_region(file_t *file);
1.103 +long client_next_region(file_t *file);
1.104 +}}}
1.105 +
1.106 +Such navigation functions for files and pipes do not need to be used where the
1.107 +higher-level reading, writing and seeking functions are in use.
1.108 +
1.109 +=== Flushing and Synchronisation ===
1.110 +
1.111 +For synchronisation purposes, either with the filesystem itself or with other
1.112 +users of the filesystem, a function resembling the traditional `fflush`
1.113 +function is provided:
1.114 +
1.115 +{{{
1.116 +long client_flush(file_t *file);
1.117 +}}}
1.118 +
1.119 +This updates the file data structure with new details of the file size, also
1.120 +updating any altered details of the extent of the data in the currently
1.121 +accessed region of the file.
1.122 +
1.123 +=== Notifications ===
1.124 +
1.125 +Since files and pipes may be accessed by multiple clients, necessarily for any
1.126 +sensible use of the latter, notifications can be configured to communicate a
1.127 +change in state to other users of these resources when they are accessed.
1.128 +
1.129 +Notification types are specified using values encoding a number of flags, and
1.130 +the following flags are available for this purpose:
1.131 +
1.132 +|| '''Flag''' || '''Notification Type''' ||
1.133 +|| `NOTIFY_CONTENT_AVAILABLE` || Content available to read ||
1.134 +|| `NOTIFY_PEER_CLOSED` || Other party has closed their endpoint ||
1.135 +|| `NOTIFY_SPACE_AVAILABLE` || Space available for writing ||
1.136 +
1.137 +=== Blocking Operations ===
1.138 +
1.139 +Reading and writing operations can be configured to block if data cannot be
1.140 +read or written respectively. The following function is provided for this
1.141 +purpose:
1.142 +
1.143 +{{{
1.144 +long client_set_blocking(file_t *file, notify_flags_t flags);
1.145 +}}}
1.146 +
1.147 +For pipes, blocking behaviour is the default and must be disabled explicitly,
1.148 +either by opening using the `O_NONBLOCK` flag or by calling
1.149 +`client_set_blocking` with no flags set.
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/docs/wiki/Components Sat Aug 28 00:28:17 2021 +0200
2.3 @@ -0,0 +1,227 @@
2.4 += Components =
2.5 +
2.6 +Access to files is provided by a number of programs acting as components. For
2.7 +convenience, the component-level operations are wrapped up in a
2.8 +[[ClientLibrary|client library]] that aims to provide simpler, more familiar
2.9 +mechanisms for opening, reading, writing, and closing files, together with
2.10 +various other operations.
2.11 +
2.12 +<<TableOfContents(2,3)>>
2.13 +
2.14 +Components are accessed via interfaces defined using the interface description
2.15 +language supported by the ``idl4re`` tool. Interface operations in this
2.16 +document are described using excerpts from the appropriate interface
2.17 +descriptions.
2.18 +
2.19 +######## A graph showing the interactions between components
2.20 +
2.21 +{{{#!graphviz
2.22 +#format svg
2.23 +#transform notugly
2.24 +digraph components {
2.25 + node [fontsize="12.0",fontname="sans-serif",shape=box];
2.26 + edge [fontsize="12.0",fontname="sans-serif"];
2.27 + rankdir=LR;
2.28 +
2.29 + subgraph {
2.30 + node [label="Client",style=solid,color="#000000",fontcolor="#000000"];
2.31 + rank=min;
2.32 +
2.33 + Client1; Client3; Client5;
2.34 +
2.35 + subgraph {
2.36 + node [label="Client",color="#999999",fontcolor="#999999"];
2.37 + Client2; Client4; Client6;
2.38 + }
2.39 + }
2.40 +
2.41 + subgraph {
2.42 + rank=same;
2.43 + Filesystem;
2.44 +
2.45 + subgraph {
2.46 + node [label="Opener\n(user)"];
2.47 + Opener1; Opener2;
2.48 + }
2.49 +
2.50 + subgraph {
2.51 + node [label="OpenerContext"];
2.52 + OpenerContext1; OpenerContext2;
2.53 + }
2.54 +
2.55 + MappedFile;
2.56 + }
2.57 +
2.58 + Client1 -> Client2 -> Client3 -> Client4 -> Client5 -> Client6 [arrowhead=none,style=invisible];
2.59 + Opener1 -> Opener2 [arrowhead=none,style=invisible];
2.60 + OpenerContext1 -> OpenerContext2 [arrowhead=none,style=invisible];
2.61 +
2.62 + Client1 -> Filesystem [label="open_for_user(user)"];
2.63 + Filesystem -> Opener1;
2.64 + Opener1 -> Client2 [style=dashed];
2.65 +
2.66 + Client3 -> Opener2 [label="context()"];
2.67 + Opener2 -> OpenerContext1;
2.68 + OpenerContext1 -> Client4 [style=dashed];
2.69 +
2.70 + Client5 -> OpenerContext2 [label="open(flags, ...)"];
2.71 + OpenerContext2 -> MappedFile;
2.72 + MappedFile -> Client6 [style=dashed];
2.73 +}
2.74 +}}}
2.75 +
2.76 +########
2.77 +
2.78 +== Filesystems ==
2.79 +
2.80 +Filesystems implement the `Filesystem` interface which provides the
2.81 +`open_for_user` operation:
2.82 +
2.83 +{{{
2.84 +open_for_user(in user_t user, out cap opener)
2.85 +}}}
2.86 +
2.87 +The operation yields a file opener appropriate for the given [[Users|user]]
2.88 +credentials.
2.89 +
2.90 +== File Openers ==
2.91 +
2.92 +File openers implement the `Opener` interface which provides the `context`
2.93 +operation:
2.94 +
2.95 +{{{
2.96 +context(out cap context)
2.97 +}}}
2.98 +
2.99 +Each client program, task or thread obtains its own context because it will
2.100 +need its own dedicated channel for communication with the filesystem.
2.101 +
2.102 +== Opener Contexts ==
2.103 +
2.104 +An opener context acts as a dataspace, meaning that it can be attached to a
2.105 +task using a region manager and provide a buffer via a region of mapped memory
2.106 +that the task can write to. In the case of a context, the task will write a
2.107 +filesystem path indicating the file to be opened.
2.108 +
2.109 +Each context allows a client program to request access to individual files via
2.110 +operations provided by the `OpenerContext` interface, of which the most
2.111 +pertinent is the `open` operation:
2.112 +
2.113 +{{{
2.114 +open(in flags_t flags, out offset_t size, out cap file,
2.115 + out object_flags_t object_flags)
2.116 +}}}
2.117 +
2.118 +Using the path information written to the context's memory region, the `open`
2.119 +operation will obtain a reference to a file-like object whose characteristics
2.120 +are described by the accompanying `object_flags`, these helping the client to
2.121 +distinguish between files that support arbitrary memory mapping operations and
2.122 +pipes that mandate sequential region-by-region access.
2.123 +
2.124 +Alongside regular files, directories may also be opened. Reading from them
2.125 +yields a listing of directory entries.
2.126 +
2.127 +== Files ==
2.128 +
2.129 +Files themselves act as dataspaces, meaning that they can be attached to a
2.130 +task using a region manager and provide their content via a region of mapped
2.131 +memory. Files implement the `MappedFile` interface.
2.132 +
2.133 +Control over the region of the file provided via mapped memory occurs
2.134 +using the `mmap` operation:
2.135 +
2.136 +{{{
2.137 +mmap(in offset_t position, in offset_t length,
2.138 + out offset_t start_pos, out offset_t end_pos,
2.139 + out offset_t size)
2.140 +}}}
2.141 +
2.142 +Files also implement the more general `File` interface that provides the
2.143 +`resize` operation:
2.144 +
2.145 +{{{
2.146 +resize(inout offset_t size)
2.147 +}}}
2.148 +
2.149 +This allows the portion of the memory region dedicated to the file's contents
2.150 +to be extended.
2.151 +
2.152 +== Directories ==
2.153 +
2.154 +Directories are also meant to be accessed like files, meaning that it should
2.155 +be possible to attach them to a task using a region manager and access the
2.156 +provided content, this being a listing of directory entries, via the mapped
2.157 +region.
2.158 +
2.159 +However, unlike files which may support arbitrary mapping of their contents,
2.160 +the provided content may be supplied by a pipe endpoint, thereby not
2.161 +supporting precisely the same navigation mechanisms as those supported by
2.162 +files.
2.163 +
2.164 +'''Note''' that directories may well be redefined to support multiple
2.165 +operations, one of which supporting the file-like access described above.
2.166 +
2.167 +== Pipe Openers ==
2.168 +
2.169 +Distinct from filesystems but potentially used by them, pipe openers provide a
2.170 +means of obtaining pipes, which are channels that support unidirectional
2.171 +communication via shared memory.
2.172 +
2.173 +Pipe openers implement the `PipeOpener` interface and support the following
2.174 +operation:
2.175 +
2.176 +{{{
2.177 +pipe(in offset_t size, out cap reader, out cap writer)
2.178 +}}}
2.179 +
2.180 +The size is indicated to request pipe regions long enough for the needs of the
2.181 +communicating parties, with both reader and writer endpoint capabilities being
2.182 +returned. Such capabilities may be propagated to the eventual parties, these
2.183 +typically being separate tasks.
2.184 +
2.185 +== Pipes ==
2.186 +
2.187 +Although not generally obtained from filesystems, pipes may be involved in
2.188 +providing content from some filesystem objects such as directories. However,
2.189 +they are also obtained directly from an appropriate pipe server providing pipe
2.190 +opening facilities.
2.191 +
2.192 +Pipes expose single regions of shared memory to their endpoints, with the
2.193 +writing endpoint populating one region while the reading endpoint accesses the
2.194 +other. The reading endpoint may advance to the region being written, and this
2.195 +will free up a new region for the writer when it has filled its region. When
2.196 +the writer itself advances, it permits the reader to consume all data in the
2.197 +fully populated region. Naturally, the reader may not advance ahead of the
2.198 +writer.
2.199 +
2.200 +Pipes implement the `Pipe` interface and a number of operations to support
2.201 +this interaction mechanism.
2.202 +
2.203 +The details of an endpoint's current region can be queried using the following
2.204 +operation:
2.205 +
2.206 +{{{
2.207 +current_region(out offset_t populated_size, out offset_t size)
2.208 +}}}
2.209 +
2.210 +This provides details of the populated size (or amount of written data) in a
2.211 +region along with the size of the region.
2.212 +
2.213 +Navigation to the next available region of the pipe is performed using the
2.214 +following operation:
2.215 +
2.216 +{{{
2.217 +next_region(inout offset_t populated_size, out offset_t size)
2.218 +}}}
2.219 +
2.220 +Here, the populated size may be specified by the writer so that the reader may
2.221 +query the current region's properties using the appropriate operation.
2.222 +
2.223 +The status of the pipe can be queried using the `closed` operation:
2.224 +
2.225 +{{{
2.226 +closed(out int closed)
2.227 +}}}
2.228 +
2.229 +This indicates through a boolean-equivalent parameter whether one or both
2.230 +endpoints have been closed.
3.1 --- a/docs/wiki/Files Sat Aug 28 00:27:23 2021 +0200
3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
3.3 @@ -1,237 +0,0 @@
3.4 -= Files =
3.5 -
3.6 -Access to files is provided by a number of programs acting as components. For
3.7 -convenience, the component-level operations are wrapped up in a client library
3.8 -that aims to provide simpler, more familiar mechanisms for opening, reading,
3.9 -writing, and closing files, together with various other operations.
3.10 -
3.11 -<<TableOfContents(2,3)>>
3.12 -
3.13 -== Components ==
3.14 -
3.15 -At the lowest level in L4Re, files are accessed via a suite of components.
3.16 -These components are principally of interest to library developers since they
3.17 -only provide a limited level of abstraction.
3.18 -
3.19 -=== Filesystems ===
3.20 -
3.21 -Filesystems implement the `Filesystem` interface which provides the
3.22 -`open_for_user` operation:
3.23 -
3.24 -{{{
3.25 -open_for_user(in user_t user, out cap opener)
3.26 -}}}
3.27 -
3.28 -The operation yields a file opener appropriate for the given user credentials.
3.29 -
3.30 -=== File Openers ===
3.31 -
3.32 -File openers implement the `Opener` interface which provides the `context`
3.33 -operation:
3.34 -
3.35 -{{{
3.36 -context(out cap context)
3.37 -}}}
3.38 -
3.39 -Each client program, task or thread obtains its own context because it will
3.40 -need its own dedicated channel for communication with the filesystem.
3.41 -
3.42 -=== Contexts ===
3.43 -
3.44 -A context acts as a dataspace, meaning that it can be attached to a task using
3.45 -a region manager and provide a buffer via a region of mapped memory that the
3.46 -task can write to. In the case of a context, the task will write a filesystem
3.47 -path indicating the file to be opened.
3.48 -
3.49 -Each context allows a client program to request access to individual files via
3.50 -operations provided by the `OpenerContext` interface, of which the most
3.51 -pertinent is the `open` operation:
3.52 -
3.53 -{{{
3.54 -open(in flags_t flags, out offset_t size, out cap file,
3.55 - out object_flags_t object_flags)
3.56 -}}}
3.57 -
3.58 -Using the path information written to the context's memory region, the `open`
3.59 -operation will obtain a reference to a file-like object whose characteristics
3.60 -are described by the accompanying `object_flags`, these helping the client to
3.61 -distinguish between files that support arbitrary memory mapping operations and
3.62 -pipes that mandate sequential region-by-region access.
3.63 -
3.64 -Alongside regular files, directories may also be opened. Reading from them
3.65 -yields a listing of directory entries.
3.66 -
3.67 -=== Files ===
3.68 -
3.69 -Files themselves act as dataspaces, meaning that they can be attached to a
3.70 -task using a region manager and provide their content via a region of mapped
3.71 -memory. Files implement the `MappedFile` interface.
3.72 -
3.73 -Control over the region of the file provided via mapped memory occurs
3.74 -using the `mmap` operation:
3.75 -
3.76 -{{{
3.77 -mmap(in offset_t position, in offset_t length,
3.78 - out offset_t start_pos, out offset_t end_pos,
3.79 - out offset_t size)
3.80 -}}}
3.81 -
3.82 -Files also implement the more general `File` interface that provides the
3.83 -`resize` operation:
3.84 -
3.85 -{{{
3.86 -resize(inout offset_t size)
3.87 -}}}
3.88 -
3.89 -This allows the portion of the memory region dedicated to the file's contents
3.90 -to be extended.
3.91 -
3.92 -=== Directories ===
3.93 -
3.94 -Directories are also meant to be accessed like files, meaning that it should
3.95 -be possible to attach them to a task using a region manager and access the
3.96 -provided content, this being a listing of directory entries, via the mapped
3.97 -region.
3.98 -
3.99 -However, unlike files which may support arbitrary mapping of their contents,
3.100 -the provided content may be supplied by a pipe endpoint, thereby not
3.101 -supporting precisely the same navigation mechanisms as those supported by
3.102 -files.
3.103 -
3.104 -=== Pipe Openers ===
3.105 -
3.106 -Distinct from filesystems but potentially used by them, pipe openers provide a
3.107 -means of obtaining pipes, which are channels that support unidirectional
3.108 -communication via shared memory.
3.109 -
3.110 -Pipe openers implement the `PipeOpener` interface and support the following
3.111 -operation:
3.112 -
3.113 -{{{
3.114 -pipe(in offset_t size, out cap reader, out cap writer)
3.115 -}}}
3.116 -
3.117 -The size is indicated to request pipe regions long enough for the needs of the
3.118 -communicating parties, with both reader and writer endpoint capabilities being
3.119 -returned. Such capabilities may be propagated to the eventual parties, these
3.120 -typically being separate tasks.
3.121 -
3.122 -=== Pipes ===
3.123 -
3.124 -Although not generally obtained from filesystems, pipes may be involved in
3.125 -providing content from some filesystem objects such as directories. However,
3.126 -they are also obtained directly from an appropriate pipe server providing pipe
3.127 -opening facilities.
3.128 -
3.129 -Pipes expose single regions of shared memory to their endpoints, with the
3.130 -writing endpoint populating one region while the reading endpoint accesses the
3.131 -other. The reading endpoint may advance to the region being written, and this
3.132 -will free up a new region for the writer when it has filled its region. When
3.133 -the writer itself advances, it permits the reader to consume all data in the
3.134 -fully populated region. Naturally, the reader may not advance ahead of the
3.135 -writer.
3.136 -
3.137 -Pipes implement the `Pipe` interface and a number of operations to support
3.138 -this interaction mechanism.
3.139 -
3.140 -The details of an endpoint's current region can be queried using the following
3.141 -operation:
3.142 -
3.143 -{{{
3.144 -current_region(out offset_t populated_size, out offset_t size)
3.145 -}}}
3.146 -
3.147 -This provides details of the populated size (or amount of written data) in a
3.148 -region along with the size of the region.
3.149 -
3.150 -Navigation to the next available region of the pipe is performed using the
3.151 -following operation:
3.152 -
3.153 -{{{
3.154 -next_region(inout offset_t populated_size, out offset_t size)
3.155 -}}}
3.156 -
3.157 -Here, the populated size may be specified by the writer so that the reader may
3.158 -query the current region's properties using the appropriate operation.
3.159 -
3.160 -The status of the pipe can be queried using the `closed` operation:
3.161 -
3.162 -{{{
3.163 -closed(out int closed)
3.164 -}}}
3.165 -
3.166 -This indicates through a boolean-equivalent parameter whether one or both
3.167 -endpoints have been closed.
3.168 -
3.169 -== Libraries ==
3.170 -
3.171 -The filesystem client library offers abstractions and a number of layers of
3.172 -functionality to support interaction with components and the provision of
3.173 -higher-level mechanisms and abstractions for file access.
3.174 -
3.175 -=== Client Library ===
3.176 -
3.177 -The client library provides functions somewhat resembling the traditional C
3.178 -library and low-level Unix interfaces for file access, and these functions are
3.179 -intended to support such traditional interfaces.
3.180 -
3.181 -Since files are accessed using file references, the `file_t` data structure is
3.182 -used to wrap such references and other relevant state. Thus, such structures
3.183 -can be broadly regarded as similar to the traditional `FILE` data structure.
3.184 -
3.185 -Files are opened and closed using the following functions:
3.186 -
3.187 -{{{
3.188 -file_t *client_open(const char *name, flags_t flags);
3.189 -void client_close(file_t *file);
3.190 -}}}
3.191 -
3.192 -Pipes are opened using a special function:
3.193 -
3.194 -{{{
3.195 -long client_pipe(file_t **reader, file_t **writer, flags_t flags);
3.196 -}}}
3.197 -
3.198 -Each pipe endpoint may be closed using `client_close`.
3.199 -
3.200 -Reading and writing files and pipes involves functions resembling the
3.201 -traditional low-level `read` and `write` functions:
3.202 -
3.203 -{{{
3.204 -offset_t client_read(file_t *file, void *buf, offset_t count);
3.205 -offset_t client_write(file_t *file, const void *buf, offset_t count);
3.206 -}}}
3.207 -
3.208 -Support for navigation in files is provided using functions resembling the
3.209 -traditional higher-level `fseek` and `ftell` functions:
3.210 -
3.211 -{{{
3.212 -offset_t client_seek(file_t *file, offset_t offset, int whence);
3.213 -long client_tell(file_t *file);
3.214 -}}}
3.215 -
3.216 -Although the client library (and the provision of files) employs mapped
3.217 -memory, a function can be used to explicitly reference memory for file access:
3.218 -
3.219 -{{{
3.220 -void *client_mmap(file_t *file, offset_t position, offset_t length);
3.221 -}}}
3.222 -
3.223 -Pipes support a different mechanism for navigation involving the following
3.224 -functions:
3.225 -
3.226 -{{{
3.227 -long client_current_region(file_t *file);
3.228 -long client_next_region(file_t *file);
3.229 -}}}
3.230 -
3.231 -Such navigation functions for files and pipes do not need to be used where the
3.232 -higher-level reading, writing and seeking functions are in use.
3.233 -
3.234 -For synchronisation purposes, either with the filesystem itself or with other
3.235 -users of the filesystem, a function resembling the traditional `fflush`
3.236 -function is provided:
3.237 -
3.238 -{{{
3.239 -long client_flush(file_t *file);
3.240 -}}}
4.1 --- a/docs/wiki/Filesystems Sat Aug 28 00:27:23 2021 +0200
4.2 +++ b/docs/wiki/Filesystems Sat Aug 28 00:28:17 2021 +0200
4.3 @@ -5,4 +5,6 @@
4.4
4.5 == Topics ==
4.6
4.7 - * [[Files]]
4.8 + * [[Components]]
4.9 + * [[ClientLibrary|Client Library]]
4.10 + * [[Users]]