Documentation improvements for 2.1.1.
- Fix typos and broken links. - Add documentation for functions introduced in 2.1.1. - Add copyright header to `FLV.m` and remove `hello.c`. - Update documentation for `mj_ray` and `mj_contactForce`. - Delete out-of-date comments in `XMLreference.rst`. - Add geom:size table to `XMLreference.rst`. PiperOrigin-RevId: 425318966
This commit is contained in:
committed by
Saran Tunyasuvunakool
parent
ee39340ae7
commit
1ef7ec6dde
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Don't commit binaries
|
||||||
|
*.a
|
||||||
|
*.asm
|
||||||
|
*.dll
|
||||||
|
*.dylib
|
||||||
|
*.exe
|
||||||
|
*.lib
|
||||||
|
*.out
|
||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Exclude editor config
|
||||||
|
.vscode/
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Exclude temporary folders
|
||||||
|
*.egg-info/
|
||||||
|
build/
|
||||||
|
build_cmake/
|
||||||
@@ -12,4 +12,3 @@ python:
|
|||||||
version: 3.7
|
version: 3.7
|
||||||
install:
|
install:
|
||||||
- requirements: doc/requirements.txt
|
- requirements: doc/requirements.txt
|
||||||
|
|
||||||
|
|||||||
@@ -103,4 +103,3 @@ This is not an officially supported Google product.
|
|||||||
[GitHub Issues]: https://github.com/deepmind/mujoco/issues
|
[GitHub Issues]: https://github.com/deepmind/mujoco/issues
|
||||||
[documentation source files]: https://github.com/deepmind/mujoco/tree/main/doc
|
[documentation source files]: https://github.com/deepmind/mujoco/tree/main/doc
|
||||||
[mujoco.org/book]: https://mujoco.org/book
|
[mujoco.org/book]: https://mujoco.org/book
|
||||||
|
|
||||||
|
|||||||
+55
-28
@@ -3142,7 +3142,7 @@ Numeric constants
|
|||||||
+------------------+--------+----------------------------------------------------------------------------------------+
|
+------------------+--------+----------------------------------------------------------------------------------------+
|
||||||
| mjMAXUIRECT | 15 | Maximum number of UI rectangles. Defined in mjui.h. |
|
| mjMAXUIRECT | 15 | Maximum number of UI rectangles. Defined in mjui.h. |
|
||||||
+------------------+--------+----------------------------------------------------------------------------------------+
|
+------------------+--------+----------------------------------------------------------------------------------------+
|
||||||
| mjVERSION_HEADER | 210 | The version of the MuJoCo headers; changes with every release. This is an integer |
|
| mjVERSION_HEADER | 211 | The version of the MuJoCo headers; changes with every release. This is an integer |
|
||||||
| | | equal to 100x the software version, so 210 corresponds to version 2.1. Defined in |
|
| | | equal to 100x the software version, so 210 corresponds to version 2.1. Defined in |
|
||||||
| | | mujoco.h. The API function :ref:`mj_version` returns a number with the same meaning |
|
| | | mujoco.h. The API function :ref:`mj_version` returns a number with the same meaning |
|
||||||
| | | but for the compiled library. |
|
| | | but for the compiled library. |
|
||||||
@@ -3153,16 +3153,11 @@ Numeric constants
|
|||||||
API functions
|
API functions
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
| The main header `mujoco.h <https://github.com/deepmind/mujoco/blob/main/include/mujoco.h>`_ exposes a very large number of functions. However the functions that
|
The main header `mujoco.h <https://github.com/deepmind/mujoco/blob/main/include/mujoco.h>`_ exposes a very large number
|
||||||
most users are likely to need are a small fraction. For example, simulate.cc which is as elaborate as a MuJoCo
|
of functions. However the functions that most users are likely to need are a small fraction. For example,
|
||||||
application is likely to get, calls around 40 of these functions, while basic.cc calls around 20. The rest are
|
``simulate.cc`` which is as elaborate as a MuJoCo application is likely to get, calls around 40 of these functions,
|
||||||
explosed just in case someone has a use for them. This includes us as users of MuJoCo - we do our own work with the
|
while basic.cc calls around 20. The rest are explosed just in case someone has a use for them. This includes us as users
|
||||||
public library instead of relying on internal builds.
|
of MuJoCo -- we do our own work with the public library instead of relying on internal builds.
|
||||||
|
|
||||||
| A drawback of this liberal function exposure policy is that documenting of all them properly is not realistic. Of
|
|
||||||
course we can always add documentation, and we encourage users to ask questions on the Forum about functions they
|
|
||||||
would like to use but do not find sufficiently documented. The documentation below contains the comments from the
|
|
||||||
header file, with some additional comments regarding groups of functions or commonly used functions.
|
|
||||||
|
|
||||||
.. _Activation:
|
.. _Activation:
|
||||||
|
|
||||||
@@ -3198,20 +3193,19 @@ Does nothing.
|
|||||||
Virtual file system
|
Virtual file system
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
| Virtual file system (VFS) functionality was introduced in MuJoCo 1.50. It enables the user to load all necessary files
|
Virtual file system (VFS) functionality was introduced in MuJoCo 1.50. It enables the user to load all necessary files
|
||||||
in memory, including MJB binary model files, XML files (MJCF, URDF and included files), STL meshes, PNGs for textures
|
in memory, including MJB binary model files, XML files (MJCF, URDF and included files), STL meshes, PNGs for textures
|
||||||
and height fields, and HF files in our custom height field format. Model and resource files in the VFS can also be
|
and height fields, and HF files in our custom height field format. Model and resource files in the VFS can also be
|
||||||
constructed programmatically (say using a Python library that writes to memory). Once all desired files are in the
|
constructed programmatically (say using a Python library that writes to memory). Once all desired files are in the VFS,
|
||||||
VFS, the user can call :ref:`mj_loadModel` or :ref:`mj_loadXML` with a pointer to the VFS. When
|
the user can call :ref:`mj_loadModel` or :ref:`mj_loadXML` with a pointer to the VFS. When this pointer is not NULL, the
|
||||||
this pointer is not NULL, the loaders will first check the VFS for any file they are about to load, and only access
|
loaders will first check the VFS for any file they are about to load, and only access the disk if the file is not found
|
||||||
the disk if the file is not found in the VFS. The file names stored in the VFS have their name and extension but the
|
in the VFS. The file names stored in the VFS have their name and extension but the path information is stripped; this
|
||||||
path information is stripped; this can be bypassed however by using a custom path symbol in the file names, say
|
can be bypassed however by using a custom path symbol in the file names, say "mydir_myfile.xml".
|
||||||
"mydir_myfile.xml".
|
|
||||||
|
|
||||||
| The entire VFS is contained in the data structure :ref:`mjVFS`. All utility functions for maintaining the VFS
|
The entire VFS is contained in the data structure :ref:`mjVFS`. All utility functions for maintaining the VFS operate on
|
||||||
operate on this data structure. The common usage pattern is to first clear it with mj_defaultVFS, then add disk files
|
this data structure. The common usage pattern is to first clear it with mj_defaultVFS, then add disk files to it with
|
||||||
to it with mj_addFileVFS (which allocates memory buffers and loads the file content in memory), then call mj_loadXML
|
mj_addFileVFS (which allocates memory buffers and loads the file content in memory), then call mj_loadXML or
|
||||||
or mj_loadModel, and then clear everything with mj_deleteVFS.
|
mj_loadModel, and then clear everything with mj_deleteVFS.
|
||||||
|
|
||||||
.. _mj_defaultVFS:
|
.. _mj_defaultVFS:
|
||||||
|
|
||||||
@@ -3335,7 +3329,7 @@ mj_printSchema
|
|||||||
int mj_printSchema(const char* filename, char* buffer, int buffer_sz,
|
int mj_printSchema(const char* filename, char* buffer, int buffer_sz,
|
||||||
int flg_html, int flg_pad);
|
int flg_html, int flg_pad);
|
||||||
|
|
||||||
Print internal XML schema as plain text or HTML, with style-padding or .
|
Print internal XML schema as plain text or HTML, with style-padding or `` ``.
|
||||||
|
|
||||||
.. _Mainsimulation:
|
.. _Mainsimulation:
|
||||||
|
|
||||||
@@ -3670,6 +3664,19 @@ Printing
|
|||||||
|
|
||||||
These functions can be used to print various quantities to the screen for debugging purposes.
|
These functions can be used to print various quantities to the screen for debugging purposes.
|
||||||
|
|
||||||
|
|
||||||
|
.. _mj_printFormattedModel:
|
||||||
|
|
||||||
|
mj_printFormattedModel
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
void mj_printFormattedModel(const mjModel* m, const char* filename, const char* float_format_str);
|
||||||
|
|
||||||
|
Print ``mjModel`` to text file, specifying format. ``float_format_str`` must be a valid printf-style format string for a
|
||||||
|
single float value.
|
||||||
|
|
||||||
.. _mj_printModel:
|
.. _mj_printModel:
|
||||||
|
|
||||||
mj_printModel
|
mj_printModel
|
||||||
@@ -3941,6 +3948,8 @@ mj_checkAcc
|
|||||||
|
|
||||||
Check qacc, reset if any element is too big or nan.
|
Check qacc, reset if any element is too big or nan.
|
||||||
|
|
||||||
|
.. _mj_kinematics:
|
||||||
|
|
||||||
mj_kinematics
|
mj_kinematics
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -4411,7 +4420,7 @@ mj_contactForce
|
|||||||
|
|
||||||
void mj_contactForce(const mjModel* m, const mjData* d, int id, mjtNum* result);
|
void mj_contactForce(const mjModel* m, const mjData* d, int id, mjtNum* result);
|
||||||
|
|
||||||
Extract 6D force:torque for one contact, in contact frame.
|
Extract 6D force:torque given contact id, in the contact frame.
|
||||||
|
|
||||||
.. _mj_differentiatePos:
|
.. _mj_differentiatePos:
|
||||||
|
|
||||||
@@ -4498,6 +4507,17 @@ mj_version
|
|||||||
|
|
||||||
Return version number: 1.0.2 is encoded as 102.
|
Return version number: 1.0.2 is encoded as 102.
|
||||||
|
|
||||||
|
.. mj_versionString:
|
||||||
|
|
||||||
|
mj_versionString
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
const char* mj_versionString();
|
||||||
|
|
||||||
|
Return the current version of MuJoCo as a null-terminated string.
|
||||||
|
|
||||||
.. _Raycollisions:
|
.. _Raycollisions:
|
||||||
|
|
||||||
Ray collisions
|
Ray collisions
|
||||||
@@ -4509,6 +4529,9 @@ the direction. All functions in this family return the distance to the nearest g
|
|||||||
intersection. Note that if p is inside a geom, the ray will intersect the surface from the inside which still counts as
|
intersection. Note that if p is inside a geom, the ray will intersect the surface from the inside which still counts as
|
||||||
an intersection.
|
an intersection.
|
||||||
|
|
||||||
|
All ray collision functions rely on quantities computed by :ref:`mj_kinematics` (see :ref:`mjData`), so must be called
|
||||||
|
after :ref:`mj_kinematics`, or functions that call it (e.g. :ref:`mj_fwdPosition`).
|
||||||
|
|
||||||
.. _mj_ray:
|
.. _mj_ray:
|
||||||
|
|
||||||
mj_ray
|
mj_ray
|
||||||
@@ -4521,8 +4544,12 @@ mj_ray
|
|||||||
int* geomid);
|
int* geomid);
|
||||||
|
|
||||||
Intersect ray (pnt+x*vec, x>=0) with visible geoms, except geoms in bodyexclude. Return geomid and distance (x) to
|
Intersect ray (pnt+x*vec, x>=0) with visible geoms, except geoms in bodyexclude. Return geomid and distance (x) to
|
||||||
nearest surface, or -1 if no intersection. geomgroup, flg_static are as in mjvOption; geomgroup==NULL skips group
|
nearest surface, or -1 if no intersection.
|
||||||
exclusion.
|
|
||||||
|
geomgroup is an array of length mjNGROUP, where 1 means the group should be included. Pass geomgroup=NULL to skip
|
||||||
|
group exclusion.
|
||||||
|
If flg_static is 0, static geoms will be excluded.
|
||||||
|
bodyexclude=-1 can be used to indicate that all bodies are included.
|
||||||
|
|
||||||
.. _mj_rayHfield:
|
.. _mj_rayHfield:
|
||||||
|
|
||||||
|
|||||||
+25
-4
@@ -1892,9 +1892,7 @@ lower, this means that the GPU is over-loaded and the visualization should someh
|
|||||||
This attribute specifies the size of the square texture used for shadow mapping. Higher values result is smoother
|
This attribute specifies the size of the square texture used for shadow mapping. Higher values result is smoother
|
||||||
shadows. The size of the area over which a :ref:`light <light>` can cast shadows also affects smoothness, so these
|
shadows. The size of the area over which a :ref:`light <light>` can cast shadows also affects smoothness, so these
|
||||||
settings should be adjusted jointly. The default here is somewhat conservative. Most modern GPUs are able to handle
|
settings should be adjusted jointly. The default here is somewhat conservative. Most modern GPUs are able to handle
|
||||||
significantly larger textures without slowing down. The OSX version of MuJoCo does not presently render shadows,
|
significantly larger textures without slowing down.
|
||||||
because Apple does not support the necessary compatibility contexts. When MuJoCo detects that shadow mapping (or any
|
|
||||||
other advanced feature) is not supported by the video driver, it automatically disables that feature.
|
|
||||||
:at:`offsamples`: :at-val:`int, "4"`
|
:at:`offsamples`: :at-val:`int, "4"`
|
||||||
This attribute specifies the number of multi-samples for offscreen rendering. Larger values produce better
|
This attribute specifies the number of multi-samples for offscreen rendering. Larger values produce better
|
||||||
anti-aliasing but can slow down the GPU. Set this to 0 to disable multi-sampling. Note that this attribute only
|
anti-aliasing but can slow down the GPU. Set this to 0 to disable multi-sampling. Note that this attribute only
|
||||||
@@ -3218,7 +3216,30 @@ mjModel. If the XML model is saved, it will appear as a regular joint of type "f
|
|||||||
of that type is fitted to the mesh. In that case the sizes are obtained from the mesh, and the geom size parameters
|
of that type is fitted to the mesh. In that case the sizes are obtained from the mesh, and the geom size parameters
|
||||||
are ignored. Thus the number and description of required size parameters in the table below only apply to geoms that
|
are ignored. Thus the number and description of required size parameters in the table below only apply to geoms that
|
||||||
do not reference meshes.
|
do not reference meshes.
|
||||||
Type
|
|
||||||
|
+---------+--------+------------------------------------------------------------------------------------------------+
|
||||||
|
| Type | Number | Description |
|
||||||
|
+=========+========+================================================================================================+
|
||||||
|
| plane | 3 | X half-size; Y half-size; spacing between square grid lines for rendering. If either the X or Y|
|
||||||
|
| | | half-size is 0, the plane is rendered as infinite in the dimension(s) with 0 size. |
|
||||||
|
+---------+--------+------------------------------------------------------------------------------------------------+
|
||||||
|
| hfield | 0 | The geom sizes are ignored and the height field sizes are used instead. |
|
||||||
|
+---------+--------+------------------------------------------------------------------------------------------------+
|
||||||
|
| sphere | 1 | Radius of the sphere. |
|
||||||
|
+---------+--------+------------------------------------------------------------------------------------------------+
|
||||||
|
| capsule | 1 or 2 | Radius of the capsule; half-length of the cylinder part when not using the :at:`fromto` |
|
||||||
|
| | | specification. |
|
||||||
|
+---------+--------+------------------------------------------------------------------------------------------------+
|
||||||
|
|ellipsoid| 1 | X radius; Y radius; Z radius. |
|
||||||
|
+---------+--------+------------------------------------------------------------------------------------------------+
|
||||||
|
|cylinder | 1 or 2 | Radius of the cylinder; half-length of the cylinder when not using the :at:`fromto` |
|
||||||
|
| | | specification. |
|
||||||
|
+---------+--------+------------------------------------------------------------------------------------------------+
|
||||||
|
| box | 3 | X half-size; Y half-size; Z half-size. |
|
||||||
|
+---------+--------+------------------------------------------------------------------------------------------------+
|
||||||
|
| mesh | 0 | The geom sizes are ignored and the mesh sizes are used instead. |
|
||||||
|
+---------+--------+------------------------------------------------------------------------------------------------+
|
||||||
|
|
||||||
:at:`material`: :at-val:`string, optional`
|
:at:`material`: :at-val:`string, optional`
|
||||||
If specified, this attribute applies a material to the geom. The material determines the visual properties of the
|
If specified, this attribute applies a material to the geom. The material determines the visual properties of the
|
||||||
geom. The only exception is color: if the rgba attribute below is different from its internal default, it takes
|
geom. The only exception is color: if the rgba attribute below is different from its internal default, it takes
|
||||||
|
|||||||
Vendored
+15
@@ -1,3 +1,18 @@
|
|||||||
|
% Copyright 2021 DeepMind Technologies Limited
|
||||||
|
%
|
||||||
|
% Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
% you may not use this file except in compliance with the License.
|
||||||
|
% You may obtain a copy of the License at
|
||||||
|
%
|
||||||
|
% http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
%
|
||||||
|
% Unless required by applicable law or agreed to in writing, software
|
||||||
|
% distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
% See the License for the specific language governing permissions and
|
||||||
|
% limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
% Force-Length-Velocity function of MuJoCo muscle model
|
% Force-Length-Velocity function of MuJoCo muscle model
|
||||||
% Defaults: FLV(0.5, 1.6, 1.5, 1.3, 1.2)
|
% Defaults: FLV(0.5, 1.6, 1.5, 1.3, 1.2)
|
||||||
|
|
||||||
|
|||||||
Vendored
-34
@@ -1,34 +0,0 @@
|
|||||||
#include "mujoco.h"
|
|
||||||
#include "stdio.h"
|
|
||||||
|
|
||||||
char error[1000];
|
|
||||||
mjModel* m;
|
|
||||||
mjData* d;
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
// activate MuJoCo Pro
|
|
||||||
mj_activate("mjkey.txt");
|
|
||||||
|
|
||||||
// load model from file and check for errors
|
|
||||||
m = mj_loadXML("hello.xml", NULL, error, 1000);
|
|
||||||
if( !m )
|
|
||||||
{
|
|
||||||
printf("%s\n", error);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make data corresponding to model
|
|
||||||
d = mj_makeData(m);
|
|
||||||
|
|
||||||
// run simulation for 10 seconds
|
|
||||||
while( d->time<10 )
|
|
||||||
mj_step(m, d);
|
|
||||||
|
|
||||||
// free model and data, deactivate
|
|
||||||
mj_deleteData(d);
|
|
||||||
mj_deleteModel(m);
|
|
||||||
mj_deactivate();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
+1
-1
@@ -13,7 +13,7 @@ API changes
|
|||||||
#. Added ``mj_versionString``, which returns human-readable string that represents the version of the MuJoCo binary.
|
#. Added ``mj_versionString``, which returns human-readable string that represents the version of the MuJoCo binary.
|
||||||
#. Converted leading underscores to trailing underscores in private instances of API struct definitions, to conform to
|
#. Converted leading underscores to trailing underscores in private instances of API struct definitions, to conform to
|
||||||
reserved identifier directive, see
|
reserved identifier directive, see
|
||||||
`C standard: Section 7.1.3 <www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf>`__.
|
`C standard: Section 7.1.3 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf>`__.
|
||||||
|
|
||||||
.. attention::
|
.. attention::
|
||||||
This is a minor breaking change. Code which references private instances will break. To fix, replace leading
|
This is a minor breaking change. Code which references private instances will break. To fix, replace leading
|
||||||
|
|||||||
+1
-1
@@ -138,7 +138,7 @@ the model. We start with an example.
|
|||||||
<geom type="box"/>
|
<geom type="box"/>
|
||||||
<body childclass="sub">
|
<body childclass="sub">
|
||||||
<geom type="ellipsoid"/>
|
<geom type="ellipsoid"/>
|
||||||
<geom type="sphere" rgba="0 0 1 0"/>
|
<geom type="sphere" rgba="0 0 1 1"/>
|
||||||
<geom type="cylinder" class="main"/>
|
<geom type="cylinder" class="main"/>
|
||||||
</body>
|
</body>
|
||||||
</worldbody>
|
</worldbody>
|
||||||
|
|||||||
@@ -197,8 +197,6 @@ The built-in OpenGL visualizer renders this model as:
|
|||||||
If this model is simulated, the box will fall on the ground. Basic simulation code for the passive dynamics, without
|
If this model is simulated, the box will fall on the ground. Basic simulation code for the passive dynamics, without
|
||||||
rendering, is given below.
|
rendering, is given below.
|
||||||
|
|
||||||
`hello.c <_static/hello.c>`__:
|
|
||||||
|
|
||||||
.. code:: c
|
.. code:: c
|
||||||
|
|
||||||
#include "mujoco.h"
|
#include "mujoco.h"
|
||||||
|
|||||||
+2
-2
@@ -492,8 +492,8 @@ model, i.e. a model that is softer than desired, so as to obtain more accurate d
|
|||||||
uitools
|
uitools
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
||||||
`(uitools.h) <https://github.com/deepmind/mujoco/blob/main/include/uitools.h>`_
|
`(uitools.h) <https://github.com/deepmind/mujoco/blob/main/sample/uitools.h>`_
|
||||||
`(uitools.c) <https://github.com/deepmind/mujoco/blob/main/include/uitools.c>`_
|
`(uitools.c) <https://github.com/deepmind/mujoco/blob/main/sample/uitools.c>`_
|
||||||
This is not a stand-alone code sample, but rather a small utility used to hook up the new UI to GLFW. It is used in
|
This is not a stand-alone code sample, but rather a small utility used to hook up the new UI to GLFW. It is used in
|
||||||
simulate.cc and can also be used in user projects that involve the new UI. If GLFW is replaced with a different window
|
simulate.cc and can also be used in user projects that involve the new UI. If GLFW is replaced with a different window
|
||||||
library, this is the only file that would have to be changed in order to access the UI functionality.
|
library, this is the only file that would have to be changed in order to access the UI functionality.
|
||||||
|
|||||||
+1
-1
@@ -440,7 +440,7 @@ MJAPI void mj_objectVelocity(const mjModel* m, const mjData* d,
|
|||||||
MJAPI void mj_objectAcceleration(const mjModel* m, const mjData* d,
|
MJAPI void mj_objectAcceleration(const mjModel* m, const mjData* d,
|
||||||
int objtype, int objid, mjtNum* res, int flg_local);
|
int objtype, int objid, mjtNum* res, int flg_local);
|
||||||
|
|
||||||
// Extract 6D force:torque for one contact, in contact frame.
|
// Extract 6D force:torque given contact id, in the contact frame.
|
||||||
MJAPI void mj_contactForce(const mjModel* m, const mjData* d, int id, mjtNum* result);
|
MJAPI void mj_contactForce(const mjModel* m, const mjData* d, int id, mjtNum* result);
|
||||||
|
|
||||||
// Compute velocity by finite-differencing two positions.
|
// Compute velocity by finite-differencing two positions.
|
||||||
|
|||||||
Reference in New Issue
Block a user