Kaydet (Commit) 300dd552 authored tarafından Serhiy Storchaka's avatar Serhiy Storchaka Kaydeden (comit) GitHub

bpo-30872: Update the curses docs to Python 3. (#2620)

üst db12ef7e
......@@ -176,14 +176,12 @@ C library:
Checks for a non-ASCII character (ordinal values 0x80 and above).
These functions accept either integers or strings; when the argument is a
These functions accept either integers or single-character strings; when the argument is a
string, it is first converted using the built-in function :func:`ord`.
Note that all these functions check ordinal bit values derived from the first
Note that all these functions check ordinal bit values derived from the
character of the string you pass in; they do not actually know anything about
the host machine's character encoding. For functions that know about the
character encoding (and handle internationalization properly) see the
:mod:`string` module.
the host machine's character encoding.
The following two functions take either a single-character string or integer
byte value; they return a value of the same type.
......
......@@ -74,7 +74,7 @@ Panel objects have the following methods:
.. method:: Panel.hidden()
Returns true if the panel is hidden (not visible), false otherwise.
Returns ``True`` if the panel is hidden (not visible), ``False`` otherwise.
.. method:: Panel.hide()
......
......@@ -19,6 +19,14 @@ for Windows, DOS, and possibly other systems as well. This extension module is
designed to match the API of ncurses, an open-source curses library hosted on
Linux and the BSD variants of Unix.
.. note::
Whenever the documentation mentions a *character* it can be specified
as an integer, a one-character Unicode string or a one-byte byte string.
Whenever the documentation mentions a *character string* it can be specified
as a Unicode string or a byte string.
.. note::
Since version 5.4, the ncurses library decides how to interpret non-ASCII data
......@@ -104,8 +112,8 @@ The module :mod:`curses` defines the following functions:
.. function:: color_content(color_number)
Return the intensity of the red, green, and blue (RGB) components in the color
*color_number*, which must be between ``0`` and :const:`COLORS`. A 3-tuple is
returned, containing the R,G,B values for the given color, which will be between
*color_number*, which must be between ``0`` and :const:`COLORS`. Return a 3-tuple,
containing the R,G,B values for the given color, which will be between
``0`` (no component) and ``1000`` (maximum amount of component).
......@@ -119,9 +127,9 @@ The module :mod:`curses` defines the following functions:
.. function:: curs_set(visibility)
Set the cursor state. *visibility* can be set to 0, 1, or 2, for invisible,
normal, or very visible. If the terminal supports the visibility requested, the
previous cursor state is returned; otherwise, an exception is raised. On many
Set the cursor state. *visibility* can be set to ``0``, ``1``, or ``2``, for invisible,
normal, or very visible. If the terminal supports the visibility requested, return the
previous cursor state; otherwise raise an exception. On many
terminals, the "visible" mode is an underline cursor and the "very visible" mode
is a block cursor.
......@@ -154,12 +162,12 @@ The module :mod:`curses` defines the following functions:
representing the desired next state. The :func:`doupdate` ground updates the
physical screen to match the virtual screen.
The virtual screen may be updated by a :meth:`noutrefresh` call after write
operations such as :meth:`addstr` have been performed on a window. The normal
:meth:`refresh` call is simply :meth:`noutrefresh` followed by :func:`doupdate`;
The virtual screen may be updated by a :meth:`~window.noutrefresh` call after write
operations such as :meth:`~window.addstr` have been performed on a window. The normal
:meth:`~window.refresh` call is simply :meth:`!noutrefresh` followed by :func:`!doupdate`;
if you have to update multiple windows, you can speed performance and perhaps
reduce screen flicker by issuing :meth:`noutrefresh` calls on all windows,
followed by a single :func:`doupdate`.
reduce screen flicker by issuing :meth:`!noutrefresh` calls on all windows,
followed by a single :func:`!doupdate`.
.. function:: echo()
......@@ -175,7 +183,7 @@ The module :mod:`curses` defines the following functions:
.. function:: erasechar()
Return the user's current erase character. Under Unix operating systems this
Return the user's current erase character as a one-byte bytes object. Under Unix operating systems this
is a property of the controlling tty of the curses program, and is not set by
the curses library itself.
......@@ -183,9 +191,9 @@ The module :mod:`curses` defines the following functions:
.. function:: filter()
The :func:`.filter` routine, if used, must be called before :func:`initscr` is
called. The effect is that, during those calls, :envvar:`LINES` is set to 1; the
capabilities clear, cup, cud, cud1, cuu1, cuu, vpa are disabled; and the home
string is set to the value of cr. The effect is that the cursor is confined to
called. The effect is that, during those calls, :envvar:`LINES` is set to ``1``; the
capabilities ``clear``, ``cup``, ``cud``, ``cud1``, ``cuu1``, ``cuu``, ``vpa`` are disabled; and the ``home``
string is set to the value of ``cr``. The effect is that the cursor is confined to
the current line, and so are screen updates. This may be used for enabling
character-at-a-time line editing without touching the rest of the screen.
......@@ -205,7 +213,7 @@ The module :mod:`curses` defines the following functions:
.. function:: getmouse()
After :meth:`getch` returns :const:`KEY_MOUSE` to signal a mouse event, this
After :meth:`~window.getch` returns :const:`KEY_MOUSE` to signal a mouse event, this
method should be call to retrieve the queued mouse event, represented as a
5-tuple ``(id, x, y, z, bstate)``. *id* is an ID value used to distinguish
multiple devices, and *x*, *y*, *z* are the event's coordinates. (*z* is
......@@ -219,8 +227,8 @@ The module :mod:`curses` defines the following functions:
.. function:: getsyx()
Return the current coordinates of the virtual screen cursor in y and x. If
leaveok is currently true, then -1,-1 is returned.
Return the current coordinates of the virtual screen cursor as a tuple
``(y, x)``. If :meth:`leaveok <window.leaveok>` is currently ``True``, then return ``(-1, -1)``.
.. function:: getwin(file)
......@@ -260,7 +268,7 @@ The module :mod:`curses` defines the following functions:
Used for half-delay mode, which is similar to cbreak mode in that characters
typed by the user are immediately available to the program. However, after
blocking for *tenths* tenths of seconds, an exception is raised if nothing has
blocking for *tenths* tenths of seconds, raise an exception if nothing has
been typed. The value of *tenths* must be a number between ``1`` and ``255``. Use
:func:`nocbreak` to leave half-delay mode.
......@@ -273,7 +281,7 @@ The module :mod:`curses` defines the following functions:
:const:`COLORS`. Each of *r*, *g*, *b*, must be a value between ``0`` and
``1000``. When :func:`init_color` is used, all occurrences of that color on the
screen immediately change to the new definition. This function is a no-op on
most terminals; it is active only if :func:`can_change_color` returns ``1``.
most terminals; it is active only if :func:`can_change_color` returns ``True``.
.. function:: init_pair(pair_number, fg, bg)
......@@ -313,32 +321,32 @@ The module :mod:`curses` defines the following functions:
.. function:: keyname(k)
Return the name of the key numbered *k*. The name of a key generating printable
Return the name of the key numbered *k* as a bytes object. The name of a key generating printable
ASCII character is the key's character. The name of a control-key combination
is a two-character string consisting of a caret followed by the corresponding
is a two-byte bytes object consisting of a caret (``b'^'``) followed by the corresponding
printable ASCII character. The name of an alt-key combination (128--255) is a
string consisting of the prefix 'M-' followed by the name of the corresponding
bytes object consisting of the prefix ``b'M-'`` followed by the name of the corresponding
ASCII character.
.. function:: killchar()
Return the user's current line kill character. Under Unix operating systems
Return the user's current line kill character as a one-byte bytes object. Under Unix operating systems
this is a property of the controlling tty of the curses program, and is not set
by the curses library itself.
.. function:: longname()
Return a string containing the terminfo long name field describing the current
Return a bytes object containing the terminfo long name field describing the current
terminal. The maximum length of a verbose description is 128 characters. It is
defined only after the call to :func:`initscr`.
.. function:: meta(yes)
.. function:: meta(flag)
If *yes* is 1, allow 8-bit characters to be input. If *yes* is 0, allow only
7-bit chars.
If *flag* is ``True``, allow 8-bit characters to be input. If
*flag* is ``False``, allow only 7-bit chars.
.. function:: mouseinterval(interval)
......@@ -352,7 +360,7 @@ The module :mod:`curses` defines the following functions:
Set the mouse events to be reported, and return a tuple ``(availmask,
oldmask)``. *availmask* indicates which of the specified mouse events can be
reported; on complete failure it returns 0. *oldmask* is the previous value of
reported; on complete failure it returns ``0``. *oldmask* is the previous value of
the given window's mouse event mask. If this function is never called, no mouse
events are ever reported.
......@@ -365,13 +373,13 @@ The module :mod:`curses` defines the following functions:
.. function:: newpad(nlines, ncols)
Create and return a pointer to a new pad data structure with the given number
of lines and columns. A pad is returned as a window object.
of lines and columns. Return a pad as a window object.
A pad is like a window, except that it is not restricted by the screen size, and
is not necessarily associated with a particular part of the screen. Pads can be
used when a large window is needed, and only a part of the window will be on the
screen at one time. Automatic refreshes of pads (such as from scrolling or
echoing of input) do not occur. The :meth:`refresh` and :meth:`noutrefresh`
echoing of input) do not occur. The :meth:`~window.refresh` and :meth:`~window.noutrefresh`
methods of a pad require 6 arguments to specify the part of the pad to be
displayed and the location on the screen to be used for the display. The
arguments are *pminrow*, *pmincol*, *sminrow*, *smincol*, *smaxrow*, *smaxcol*; the *p*
......@@ -419,9 +427,9 @@ The module :mod:`curses` defines the following functions:
.. function:: noqiflush()
When the :func:`noqiflush` routine is used, normal flush of input and output queues
associated with the INTR, QUIT and SUSP characters will not be done. You may
want to call :func:`noqiflush` in a signal handler if you want output to
When the :func:`!noqiflush` routine is used, normal flush of input and output queues
associated with the ``INTR``, ``QUIT`` and ``SUSP`` characters will not be done. You may
want to call :func:`!noqiflush` in a signal handler if you want output to
continue as though the interrupt had not occurred, after the handler exits.
......@@ -442,14 +450,14 @@ The module :mod:`curses` defines the following functions:
:func:`color_pair` is the counterpart to this function.
.. function:: putp(string)
.. function:: putp(str)
Equivalent to ``tputs(str, 1, putchar)``; emit the value of a specified
terminfo capability for the current terminal. Note that the output of :func:`putp`
always goes to standard output.
.. function:: qiflush( [flag] )
.. function:: qiflush([flag])
If *flag* is ``False``, the effect is the same as calling :func:`noqiflush`. If
*flag* is ``True``, or no argument is provided, the queues will be flushed when
......@@ -486,7 +494,7 @@ The module :mod:`curses` defines the following functions:
Backend function used by :func:`resizeterm`, performing most of the work;
when resizing the windows, :func:`resize_term` blank-fills the areas that are
extended. The calling application should fill in these areas with
appropriate data. The :func:`resize_term` function attempts to resize all
appropriate data. The :func:`!resize_term` function attempts to resize all
windows. However, due to the calling convention of pads, it is not possible
to resize these without additional interaction with the application.
......@@ -506,16 +514,17 @@ The module :mod:`curses` defines the following functions:
.. function:: setsyx(y, x)
Set the virtual screen cursor to *y*, *x*. If *y* and *x* are both -1, then
leaveok is set.
Set the virtual screen cursor to *y*, *x*. If *y* and *x* are both ``-1``, then
:meth:`leaveok <window.leaveok>` is set ``True``.
.. function:: setupterm([termstr, fd])
.. function:: setupterm(term=None, fd=-1)
Initialize the terminal. *termstr* is a string giving the terminal name; if
omitted, the value of the :envvar:`TERM` environment variable will be used. *fd* is the
Initialize the terminal. *term* is a string giving
the terminal name, or ``None``; if omitted or ``None``, the value of the
:envvar:`TERM` environment variable will be used. *fd* is the
file descriptor to which any initialization sequences will be sent; if not
supplied, the file descriptor for ``sys.stdout`` will be used.
supplied or ``-1``, the file descriptor for ``sys.stdout`` will be used.
.. function:: start_color()
......@@ -540,13 +549,14 @@ The module :mod:`curses` defines the following functions:
.. function:: termname()
Return the value of the environment variable :envvar:`TERM`, truncated to 14 characters.
Return the value of the environment variable :envvar:`TERM`, as a bytes object,
truncated to 14 characters.
.. function:: tigetflag(capname)
Return the value of the Boolean capability corresponding to the terminfo
capability name *capname*. The value ``-1`` is returned if *capname* is not a
capability name *capname* as an integer. Return the value ``-1`` if *capname* is not a
Boolean capability, or ``0`` if it is canceled or absent from the terminal
description.
......@@ -554,7 +564,7 @@ The module :mod:`curses` defines the following functions:
.. function:: tigetnum(capname)
Return the value of the numeric capability corresponding to the terminfo
capability name *capname*. The value ``-2`` is returned if *capname* is not a
capability name *capname* as an integer. Return the value ``-2`` if *capname* is not a
numeric capability, or ``-1`` if it is canceled or absent from the terminal
description.
......@@ -562,13 +572,14 @@ The module :mod:`curses` defines the following functions:
.. function:: tigetstr(capname)
Return the value of the string capability corresponding to the terminfo
capability name *capname*. ``None`` is returned if *capname* is not a string
capability, or is canceled or absent from the terminal description.
capability name *capname* as a bytes object. Return ``None`` if *capname*
is not a terminfo "string capability", or is canceled or absent from the
terminal description.
.. function:: tparm(str[, ...])
Instantiate the string *str* with the supplied parameters, where *str* should
Instantiate the bytes object *str* with the supplied parameters, where *str* should
be a parameterized string obtained from the terminfo database. E.g.
``tparm(tigetstr("cup"), 5, 3)`` could result in ``b'\033[6;4H'``, the exact
result depending on terminal type.
......@@ -588,18 +599,18 @@ The module :mod:`curses` defines the following functions:
.. function:: unctrl(ch)
Return a string which is a printable representation of the character *ch*.
Control characters are displayed as a caret followed by the character, for
example as ``^C``. Printing characters are left as they are.
Return a bytes object which is a printable representation of the character *ch*.
Control characters are represented as a caret followed by the character, for
example as ``b'^C'``. Printing characters are left as they are.
.. function:: ungetch(ch)
Push *ch* so the next :meth:`getch` will return it.
Push *ch* so the next :meth:`~window.getch` will return it.
.. note::
Only one *ch* can be pushed before :meth:`getch` is called.
Only one *ch* can be pushed before :meth:`!getch` is called.
.. function:: update_lines_cols()
......@@ -611,11 +622,11 @@ The module :mod:`curses` defines the following functions:
.. function:: unget_wch(ch)
Push *ch* so the next :meth:`get_wch` will return it.
Push *ch* so the next :meth:`~window.get_wch` will return it.
.. note::
Only one *ch* can be pushed before :meth:`get_wch` is called.
Only one *ch* can be pushed before :meth:`!get_wch` is called.
.. versionadded:: 3.3
......@@ -640,7 +651,7 @@ The module :mod:`curses` defines the following functions:
Allow use of default values for colors on terminals supporting this feature. Use
this to support transparency in your application. The default color is assigned
to the color number -1. After calling this function, ``init_pair(x,
to the color number ``-1``. After calling this function, ``init_pair(x,
curses.COLOR_RED, -1)`` initializes, for instance, color pair *x* to a red
foreground color on the default background.
......@@ -652,7 +663,7 @@ The module :mod:`curses` defines the following functions:
this function will restore the terminal to a sane state before re-raising the
exception and generating a traceback. The callable object *func* is then passed
the main window 'stdscr' as its first argument, followed by any other arguments
passed to :func:`wrapper`. Before calling *func*, :func:`wrapper` turns on
passed to :func:`!wrapper`. Before calling *func*, :func:`!wrapper` turns on
cbreak mode, turns off echo, enables the terminal keypad, and initializes colors
if the terminal has color support. On exit (whether normally or by exception)
it restores cooked mode, turns on echo, and disables the terminal keypad.
......@@ -670,13 +681,6 @@ the following methods and attributes:
.. method:: window.addch(ch[, attr])
window.addch(y, x, ch[, attr])
.. note::
A *character* means a C character (an ASCII code), rather than a Python
character (a string of length 1). (This note is true whenever the
documentation mentions a character.) The built-in :func:`ord` is handy for
conveying strings to codes.
Paint character *ch* at ``(y, x)`` with attributes *attr*, overwriting any
character previously painter at that location. By default, the character
position and attributes are the current settings for the window object.
......@@ -685,15 +689,16 @@ the following methods and attributes:
.. method:: window.addnstr(str, n[, attr])
window.addnstr(y, x, str, n[, attr])
Paint at most *n* characters of the string *str* at ``(y, x)`` with attributes
Paint at most *n* characters of the character string *str* at
``(y, x)`` with attributes
*attr*, overwriting anything previously on the display.
.. method:: window.addstr(str[, attr])
window.addstr(y, x, str[, attr])
Paint the string *str* at ``(y, x)`` with attributes *attr*, overwriting
anything previously on the display.
Paint the character string *str* at ``(y, x)`` with attributes
*attr*, overwriting anything previously on the display.
.. method:: window.attroff(attr)
......@@ -710,8 +715,8 @@ the following methods and attributes:
.. method:: window.attrset(attr)
Set the "background" set of attributes to *attr*. This set is initially 0 (no
attributes).
Set the "background" set of attributes to *attr*. This set is initially
``0`` (no attributes).
.. method:: window.bkgd(ch[, attr])
......@@ -741,8 +746,7 @@ the following methods and attributes:
Draw a border around the edges of the window. Each parameter specifies the
character to use for a specific part of the border; see the table below for more
details. The characters can be specified as integers or as one-character
strings.
details.
.. note::
......@@ -783,7 +787,7 @@ the following methods and attributes:
window.chgat(y, x, num, attr)
Set the attributes of *num* characters at the current cursor position, or at
position ``(y, x)`` if supplied. If no value of *num* is given or *num* = -1,
position ``(y, x)`` if supplied. If *num* is not given or is ``-1``,
the attribute will be set on all the characters to the end of the line. This
function does not move the cursor. The changed line will be touched using the
:meth:`touchline` method so that the contents will be redisplayed by the next
......@@ -796,9 +800,9 @@ the following methods and attributes:
call to :meth:`refresh`.
.. method:: window.clearok(yes)
.. method:: window.clearok(flag)
If *yes* is 1, the next call to :meth:`refresh` will clear the window
If *flag* is ``True``, the next call to :meth:`refresh` will clear the window
completely.
......@@ -880,15 +884,16 @@ the following methods and attributes:
.. method:: window.getch([y, x])
Get a character. Note that the integer returned does *not* have to be in ASCII
range: function keys, keypad keys and so on return numbers higher than 256. In
no-delay mode, -1 is returned if there is no input, else :func:`getch` waits
until a key is pressed.
range: function keys, keypad keys and so on are represented by numbers higher
than 255. In no-delay mode, return ``-1`` if there is no input, otherwise
wait until a key is pressed.
.. method:: window.get_wch([y, x])
Get a wide character. Return a character for most keys, or an integer for
function keys, keypad keys, and other special keys.
In no-delay mode, raise an exception if there is no input.
.. versionadded:: 3.3
......@@ -897,7 +902,7 @@ the following methods and attributes:
Get a character, returning a string instead of an integer, as :meth:`getch`
does. Function keys, keypad keys and other special keys return a multibyte
string containing the key name. In no-delay mode, an exception is raised if
string containing the key name. In no-delay mode, raise an exception if
there is no input.
......@@ -909,13 +914,16 @@ the following methods and attributes:
.. method:: window.getparyx()
Return the beginning coordinates of this window relative to its parent window
into two integer variables y and x. Return ``-1, -1`` if this window has no
as a tuple ``(y, x)``. Return ``(-1, -1)`` if this window has no
parent.
.. method:: window.getstr([y, x])
.. method:: window.getstr()
window.getstr(n)
window.getstr(y, x)
window.getstr(y, x, n)
Read a string from the user, with primitive line editing capacity.
Read a bytes object from the user, with primitive line editing capacity.
.. method:: window.getyx()
......@@ -939,9 +947,9 @@ the following methods and attributes:
insert/delete is enabled by default.
.. method:: window.idlok(yes)
.. method:: window.idlok(flag)
If called with *yes* equal to 1, :mod:`curses` will try and use hardware line
If *flag* is ``True``, :mod:`curses` will try and use hardware line
editing facilities. Otherwise, line insertion/deletion are disabled.
......@@ -1003,7 +1011,7 @@ the following methods and attributes:
.. method:: window.instr([n])
window.instr(y, x[, n])
Return a string of characters, extracted from the window starting at the
Return a bytes object of characters, extracted from the window starting at the
current cursor position, or at *y*, *x* if specified. Attributes are stripped
from the characters. If *n* is specified, :meth:`instr` returns a string
at most *n* characters long (exclusive of the trailing NUL).
......@@ -1022,20 +1030,20 @@ the following methods and attributes:
:meth:`refresh`; otherwise return ``False``.
.. method:: window.keypad(yes)
.. method:: window.keypad(flag)
If *yes* is 1, escape sequences generated by some keys (keypad, function keys)
will be interpreted by :mod:`curses`. If *yes* is 0, escape sequences will be
If *flag* is ``True``, escape sequences generated by some keys (keypad, function keys)
will be interpreted by :mod:`curses`. If *flag* is ``False``, escape sequences will be
left as is in the input stream.
.. method:: window.leaveok(yes)
.. method:: window.leaveok(flag)
If *yes* is 1, cursor is left where it is on update, instead of being at "cursor
If *flag* is ``True``, cursor is left where it is on update, instead of being at "cursor
position." This reduces cursor movement where possible. If possible the cursor
will be made invisible.
If *yes* is 0, cursor will always be at "cursor position" after an update.
If *flag* is ``False``, cursor will always be at "cursor position" after an update.
.. method:: window.move(new_y, new_x)
......@@ -1055,16 +1063,16 @@ the following methods and attributes:
Move the window so its upper-left corner is at ``(new_y, new_x)``.
.. method:: window.nodelay(yes)
.. method:: window.nodelay(flag)
If *yes* is ``1``, :meth:`getch` will be non-blocking.
If *flag* is ``True``, :meth:`getch` will be non-blocking.
.. method:: window.notimeout(yes)
.. method:: window.notimeout(flag)
If *yes* is ``1``, escape sequences will not be timed out.
If *flag* is ``True``, escape sequences will not be timed out.
If *yes* is ``0``, after a few milliseconds, an escape sequence will not be
If *flag* is ``False``, after a few milliseconds, an escape sequence will not be
interpreted, and will be left in the input stream as is.
......@@ -1153,8 +1161,8 @@ the following methods and attributes:
Control what happens when the cursor of a window is moved off the edge of the
window or scrolling region, either as a result of a newline action on the bottom
line, or typing the last character of the last line. If *flag* is false, the
cursor is left on the bottom line. If *flag* is true, the window is scrolled up
line, or typing the last character of the last line. If *flag* is ``False``, the
cursor is left on the bottom line. If *flag* is ``True``, the window is scrolled up
one line. Note that in order to get the physical scrolling effect on the
terminal, it is also necessary to call :meth:`idlok`.
......@@ -1202,7 +1210,7 @@ the following methods and attributes:
.. method:: window.syncok(flag)
If called with *flag* set to ``True``, then :meth:`syncup` is called automatically
If *flag* is ``True``, then :meth:`syncup` is called automatically
whenever there is a change in the window.
......@@ -1216,9 +1224,9 @@ the following methods and attributes:
Set blocking or non-blocking read behavior for the window. If *delay* is
negative, blocking read is used (which will wait indefinitely for input). If
*delay* is zero, then non-blocking read is used, and -1 will be returned by
:meth:`getch` if no input is waiting. If *delay* is positive, then
:meth:`getch` will block for *delay* milliseconds, and return -1 if there is
*delay* is zero, then non-blocking read is used, and :meth:`getch` will
return ``-1`` if no input is waiting. If *delay* is positive, then
:meth:`getch` will block for *delay* milliseconds, and return ``-1`` if there is
still no input at the end of that time.
......@@ -1226,7 +1234,7 @@ the following methods and attributes:
Pretend *count* lines have been changed, starting with line *start*. If
*changed* is supplied, it specifies whether the affected lines are marked as
having been changed (*changed*\ =1) or unchanged (*changed*\ =0).
having been changed (*changed*\ ``=True``) or unchanged (*changed*\ ``=False``).
.. method:: window.touchwin()
......@@ -1268,7 +1276,7 @@ The :mod:`curses` module defines the following data members:
.. data:: version
A string representing the current version of the module. Also available as
A bytes object representing the current version of the module. Also available as
:const:`__version__`.
Some constants are available to specify character cell attributes.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment