From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Akib Azmain Turja via "Bug reports for GNU Emacs, the Swiss army knife of text editors" Newsgroups: gmane.emacs.bugs Subject: bug#57607: Feature request: Use the character cell on bottom-right corner of a terminal Date: Mon, 03 Oct 2022 14:31:53 +0600 Message-ID: <87r0zpi9za.fsf@disroot.org> References: <87wnakl5md.fsf@disroot.org> <87o7vt3s58.fsf@disroot.org> <87ilm04xzl.fsf@disroot.org> <875yi0v8r6.fsf@disroot.org> <874jxjhz9l.fsf@disroot.org> <87tu5i9kbg.fsf@disroot.org> Reply-To: Akib Azmain Turja Mime-Version: 1.0 Content-Type: multipart/signed; boundary="==-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="10130"; mail-complaints-to="usenet@ciao.gmane.io" Cc: gerd.moellmann@gmail.com To: 57607@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Mon Oct 03 11:22:50 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1ofHf0-0002Sb-38 for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 03 Oct 2022 11:22:50 +0200 Original-Received: from localhost ([::1]:42754 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ofHey-0003Qn-V8 for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 03 Oct 2022 05:22:49 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:43472) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ofHeE-0003PF-En for bug-gnu-emacs@gnu.org; Mon, 03 Oct 2022 05:22:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:49905) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1ofHeE-0008PE-5K for bug-gnu-emacs@gnu.org; Mon, 03 Oct 2022 05:22:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1ofHeD-0006zS-Vz for bug-gnu-emacs@gnu.org; Mon, 03 Oct 2022 05:22:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Akib Azmain Turja Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Mon, 03 Oct 2022 09:22:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 57607 X-GNU-PR-Package: emacs X-Debbugs-Original-To: Akib Azmain Turja via "Bug reports for GNU Emacs, the Swiss army knife of text editors" X-Debbugs-Original-Cc: Gerd =?UTF-8?Q?M=C3=B6llmann?= , 57607@debbugs.gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.166478891326854 (code B ref -1); Mon, 03 Oct 2022 09:22:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 3 Oct 2022 09:21:53 +0000 Original-Received: from localhost ([127.0.0.1]:48983 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ofHe4-0006z3-IE for submit@debbugs.gnu.org; Mon, 03 Oct 2022 05:21:53 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:37002) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ofHe2-0006yw-TA for submit@debbugs.gnu.org; Mon, 03 Oct 2022 05:21:52 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:40598) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ofHe1-00032Z-5V for bug-gnu-emacs@gnu.org; Mon, 03 Oct 2022 05:21:50 -0400 Original-Received: from knopi.disroot.org ([178.21.23.139]:50882) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ofHdy-0008Ix-2z for bug-gnu-emacs@gnu.org; Mon, 03 Oct 2022 05:21:48 -0400 Original-Received: from localhost (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 11B884C2EC; Mon, 3 Oct 2022 11:21:22 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Original-Received: from knopi.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id AJ4koe02CySF; Mon, 3 Oct 2022 11:21:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1664788880; bh=QjmkHOLZrBZJlapJ7td8aDKqsw3SZTxFMvKLwZ6CxoE=; h=From:To:Cc:Subject:In-Reply-To:References:Date; b=KsnSQNnI6cNDr8UMn+K+1KFcZ1lQ2z14pFITNbfP2PoQNkx5z3fWhG7hXyY4txHvD P/8ZWvKTG2onL5s8y/PdHgUPV5XJ51bjEvf9rgoJZYa84eED+STZneglZMastycXol KN0966XES7ltwLJWUSNZmX0EZTE7XDg0a4AIefga6C8LMyWj2YaFvnr/uVRpHY469T vzfXfQppv/BYWRrF5UW0pzIbBWII9q6NYecT9CoCX6YRAc1T61Q1MPV1CBq2KlenV8 FsJVIOOgDh6Nfy1f2rOymlaZGt8Tib6sp8oQMt2uQHjgBWN8dwnDraV03c4abXDA/K YlkvUaNQSjqZw== In-Reply-To: <87tu5i9kbg.fsf@disroot.org> (Akib Azmain Turja via's message of "Thu, 08 Sep 2022 17:28:35 +0600") Received-SPF: pass client-ip=178.21.23.139; envelope-from=akib@disroot.org; helo=knopi.disroot.org X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:244294 Archived-At: --==-=-= Content-Type: multipart/mixed; boundary="=-=-=" --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Akib Azmain Turja via "Bug reports for GNU Emacs, the Swiss army knife of text editors" writes: > Gerd M=C3=B6llmann writes: > >> Akib Azmain Turja writes: >> >>> Gerd M=C3=B6llmann writes: >>> >>> I mean, what files to change in order to do this? I think it's >>> tty_write_glyphs and tty_write_glyphs_with_face in term.c. >> >> Are you interested in implementing something? You could re-open this >> bug then, no problem. Or are you maybe just evaluating if you'd like to >> do it? Please give a hint. > > Yes, I'm interested, because I think it would help me understand how > Emacs renders text in terminal, which would help me to implement child > frame in terminal. But I don't have the time to do it right now. I > hope I can start doing this by late October. > I have implemented it. Implementing it was easier than I thought. Here is the patch: --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Write-on-the-bottom-right-character-cell-on-terminal.patch Content-Transfer-Encoding: quoted-printable Content-Description: Patch From=2072af00d8610bdc194062b246aab0e38f22174aeb Mon Sep 17 00:00:00 2001 From: Akib Azmain Turja Date: Mon, 3 Oct 2022 14:18:59 +0600 Subject: [PATCH] Write on the bottom-right character cell on terminal Correctly write on the bottom-right character cell on text terminals if the terminal allows to do this. Also fixes bug#57728. * src/term.c (tty_write_glyphs, tty_write_glyphs_with_face): Write on the bottom-right character cell if the terminal supports it. * src/term.c (glyph_on_char_cell_before_last): New static variable to hold the current glyph on the character cell before the cell on the bottom-right corner. =2D-- src/term.c | 266 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 225 insertions(+), 41 deletions(-) diff --git a/src/term.c b/src/term.c index 2e43d892..283a65c4 100644 =2D-- a/src/term.c +++ b/src/term.c @@ -718,7 +718,7 @@ encode_terminal_code (struct glyph *src, int src_len, return (encode_terminal_dst); } =20 =2D +static struct glyph glyph_on_char_cell_before_last; =20 /* An implementation of write_glyphs for termcap frames. */ =20 @@ -727,7 +727,7 @@ tty_write_glyphs (struct frame *f, struct glyph *string= , int len) { unsigned char *conversion_buffer; struct coding_system *coding; =2D int n, stringlen; + int n, stringlen, write_on_last_cell; =20 struct tty_display_info *tty =3D FRAME_TTY (f); =20 @@ -737,55 +737,158 @@ tty_write_glyphs (struct frame *f, struct glyph *str= ing, int len) /* Don't dare write in last column of bottom line, if Auto-Wrap, since that would scroll the whole frame on some terminals. */ =20 =2D if (AutoWrap (tty) =2D && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) =2D && (curX (tty) + len) =3D=3D FRAME_COLS (f)) + write_on_last_cell =3D (AutoWrap (tty) + && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) + && (curX (tty) + len) =3D=3D FRAME_COLS (f)); + if (write_on_last_cell) len --; =2D if (len <=3D 0) =2D return; =20 =2D cmplus (tty, len); + if (FRAME_COLS (f) =3D=3D 1 + || !(tty->TS_ins_char || tty->TS_ins_multi_chars + || (tty->TS_insert_mode && tty->TS_end_insert_mode))) + write_on_last_cell =3D false; + + if (len <=3D 0 && !write_on_last_cell) + return; =20 /* If terminal_coding does any conversion, use it, otherwise use safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here because it always return 1 if the member src_multibyte is 1. */ =2D coding =3D (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_E= NCODING_MASK + coding =3D ((FRAME_TERMINAL_CODING (f)->common_flags + & CODING_REQUIRE_ENCODING_MASK) ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail. */ coding->mode &=3D ~CODING_MODE_LAST_BLOCK; =20 =2D for (stringlen =3D len; stringlen !=3D 0; stringlen -=3D n) + if (len > 0) { =2D /* Identify a run of glyphs with the same face. */ =2D int face_id =3D string->face_id; + cmplus (tty, len); + + if (write_on_last_cell) + glyph_on_char_cell_before_last =3D string[len - 1]; + + for (stringlen =3D len; stringlen !=3D 0; stringlen -=3D n) + { + /* Identify a run of glyphs with the same face. */ + int face_id =3D string->face_id; + + for (n =3D 1; n < stringlen; ++n) + if (string[n].face_id !=3D face_id) + break; + + /* Turn appearance modes of the face of the run on. */ + tty_highlight_if_desired (tty); + turn_on_face (f, face_id); =20 =2D for (n =3D 1; n < stringlen; ++n) =2D if (string[n].face_id !=3D face_id) =2D break; + if (n =3D=3D stringlen && !write_on_last_cell) + /* This is the last run. */ + coding->mode |=3D CODING_MODE_LAST_BLOCK; + conversion_buffer =3D encode_terminal_code (string, n, + coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + string +=3D n; =20 =2D /* Turn appearance modes of the face of the run on. */ + /* Turn appearance modes off. */ + turn_off_face (f, face_id); + tty_turn_off_highlight (tty); + } + } + + /* Write on the bottom-right corner. */ + if (write_on_last_cell) + { + /* Go to the previous position. */ + cmgoto (tty, curY (tty), curX (tty) - 1); + cmplus (tty, 1); + + int face_id =3D string->face_id; + + /* Turn appearance modes of the face. */ tty_highlight_if_desired (tty); turn_on_face (f, face_id); =20 =2D if (n =3D=3D stringlen) =2D /* This is the last run. */ =2D coding->mode |=3D CODING_MODE_LAST_BLOCK; =2D conversion_buffer =3D encode_terminal_code (string, n, coding); + conversion_buffer =3D encode_terminal_code (string, 1, coding); if (coding->produced > 0) { block_input (); =2D fwrite (conversion_buffer, 1, coding->produced, tty->output); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); clearerr (tty->output); if (tty->termscript) =2D fwrite (conversion_buffer, 1, coding->produced, tty->termscript); + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + + /* Go to the previous position. */ + cmgoto (tty, curY (tty), curX (tty) - 1); + cmplus (tty, 1); + + /* Arrange that after writing the next glyph, the glyph on the + current character cell is somehow pushed to the bottom-right + corner. */ + if (tty->TS_ins_char) + { + OUTPUT1 (tty, tty->TS_ins_char); + } + else if (tty->TS_ins_multi_chars) + { + char *buf =3D tparam (tty->TS_ins_multi_chars, 0, 0, 1, 0, + 0, 0); + OUTPUT1 (tty, buf); + xfree (buf); + } + else + { + tty_turn_on_insert (tty); + } + + if (face_id !=3D glyph_on_char_cell_before_last.face_id) + { + + /* Turn appearance modes of the face. */ + turn_off_face (f, face_id); + tty_turn_off_highlight (tty); + + face_id =3D glyph_on_char_cell_before_last.face_id; + + tty_highlight_if_desired (tty); + turn_on_face (f, face_id); + } + + /* This is the last run. */ + coding->mode |=3D CODING_MODE_LAST_BLOCK; + conversion_buffer + =3D encode_terminal_code (&glyph_on_char_cell_before_last, 1, + coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); unblock_input (); } =2D string +=3D n; =20 /* Turn appearance modes off. */ turn_off_face (f, face_id); tty_turn_off_highlight (tty); + + tty_turn_off_insert (tty); } =20 cmcheckmagic (tty); @@ -799,6 +902,7 @@ tty_write_glyphs_with_face (register struct frame *f, r= egister struct glyph *str { unsigned char *conversion_buffer; struct coding_system *coding; + int write_on_last_cell; =20 struct tty_display_info *tty =3D FRAME_TTY (f); =20 @@ -808,38 +912,118 @@ tty_write_glyphs_with_face (register struct frame *f= , register struct glyph *str /* Don't dare write in last column of bottom line, if Auto-Wrap, since that would scroll the whole frame on some terminals. */ =20 =2D if (AutoWrap (tty) =2D && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) =2D && (curX (tty) + len) =3D=3D FRAME_COLS (f)) + write_on_last_cell =3D (AutoWrap (tty) + && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) + && (curX (tty) + len) =3D=3D FRAME_COLS (f)); + if (write_on_last_cell) len --; =2D if (len <=3D 0) =2D return; =20 =2D cmplus (tty, len); + if (FRAME_COLS (f) =3D=3D 1 + || !(tty->TS_ins_char || tty->TS_ins_multi_chars + || (tty->TS_insert_mode && tty->TS_end_insert_mode))) + write_on_last_cell =3D false; + + if (len <=3D 0 && !write_on_last_cell) + return; =20 /* If terminal_coding does any conversion, use it, otherwise use safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here because it always return 1 if the member src_multibyte is 1. */ =2D coding =3D (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_E= NCODING_MASK + coding =3D ((FRAME_TERMINAL_CODING (f)->common_flags + & CODING_REQUIRE_ENCODING_MASK) ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); =2D /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at =2D the tail. */ + + /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only + at the tail. */ coding->mode &=3D ~CODING_MODE_LAST_BLOCK; =20 /* Turn appearance modes of the face. */ tty_highlight_if_desired (tty); turn_on_face (f, face_id); =20 =2D coding->mode |=3D CODING_MODE_LAST_BLOCK; =2D conversion_buffer =3D encode_terminal_code (string, len, coding); =2D if (coding->produced > 0) + if (len > 0) + { + cmplus (tty, len); + if (write_on_last_cell) + glyph_on_char_cell_before_last =3D string[len - 1]; + else + coding->mode |=3D CODING_MODE_LAST_BLOCK; + + conversion_buffer =3D encode_terminal_code (string, len, coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + } + + /* Write on the bottom-right corner. */ + if (write_on_last_cell) { =2D block_input (); =2D fwrite (conversion_buffer, 1, coding->produced, tty->output); =2D clearerr (tty->output); =2D if (tty->termscript) =2D fwrite (conversion_buffer, 1, coding->produced, tty->termscript); =2D unblock_input (); + /* Go to the previous position. */ + cmgoto (tty, curY (tty), curX (tty) - 1); + cmplus (tty, 1); + + conversion_buffer =3D encode_terminal_code (string, 1, coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + + /* Go to the previous position. */ + cmgoto (tty, curY (tty), curX (tty) - 1); + cmplus (tty, 1); + + /* Arrange that after writing the next glyph, the glyph on the + current character cell is somehow pushed to the bottom-right + corner. */ + if (tty->TS_ins_char) + { + OUTPUT1 (tty, tty->TS_ins_char); + } + else if (tty->TS_ins_multi_chars) + { + char *buf =3D tparam (tty->TS_ins_multi_chars, 0, 0, 1, + 0, 0, 0); + OUTPUT1 (tty, buf); + xfree (buf); + } + else + { + tty_turn_on_insert (tty); + } + + /* This is the last run. */ + coding->mode |=3D CODING_MODE_LAST_BLOCK; + conversion_buffer + =3D encode_terminal_code (&glyph_on_char_cell_before_last, 1, + coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + + tty_turn_off_insert (tty); } =20 /* Turn appearance modes off. */ =2D-=20 2.37.1 --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable >> >> The places you mention sound right. It's probably all in term.c. But >> I'd like to add, that in principle all places writing to the terminal >> have to be checked at least. >> >> And corner cases have to be taken into consideration :-). Pulling >> something out of thin air: What happens if we write RGRG to the >> bottom-right corner, where R is one red char, and G is 1 green char, >> say. I tried "RGRG\", where "R" is red, "G" is green, and "\" is the (white) continuation glyph. Looks like this patch also fixes bug#57728. =2D-=20 Akib Azmain Turja Find me on Mastodon at @akib@hostux.social. This message is signed by me with my GnuPG key. Its fingerprint is: 7001 8CE5 819F 17A3 BBA6 66AF E74F 0EFA 922A E7F5 --=-=-=-- --==-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEyVTKmrtL6kNBe3FRVTX89U2IYWsFAmM6nfkACgkQVTX89U2I YWuGcRAAlFVIzp63r3NHprQ5tvwPj+SmJUlcLwl7SDPN1PIWBAqPwqFlLkARVjpq KfhRp21qM5F6gZMqyXV9qQI2prNJIHrsV9UIfuYax/67z/o6fhoBkALbmH4ezUy5 orBMdoQ7ZWBWtoLTm3Xkh4MVqgPWYUznvORh3S0o4xrlS9IgVoFXfgKzOsvTHnRn MJkQOnxLv9va1ihs1x4enJX+LvE81WQyjstRtxRm/AXJLinfIYRUobqBq6d1ZLYw RrJJ0tmBm1yOxlvVullCy2j6KLyzCLsYSLCxvQUYsOIYQvwaCexVy5UPLxxB2Z5R NGjN5QgckSboEkMPK3uhPRSWUKak3/POdhBk6NEsEc6DcPgQw9BT+F+QgLOqj2tf CbXdfevuC49NP1f2lL5kmIykwiL33kqEMp0zUu4HtEsjU2GZalhEU27bStxGuCQI ETc4O+uPCxln5YOMRTaPA5H624BMXbnzujY1/Z1lrU9nFb/7XHk/BCIFgZ2sdlb0 u5f2FQB0ypJ8yNLbjvvsLbkKbb/BgmGXyeyUgKPQrEpom1OqzXKMYZya0J/SjOqF IXaI4+bCsi4t06evWeBZli4B5TJOAhEZBoaiBiaOvxWxvFSgavOR+Gkz5JN80PTc KuRc9XMdUWhjWJ8fTyhK/v/ow81sq3oIDoPiEL59n0b+NpijctE= =LwLw -----END PGP SIGNATURE----- --==-=-=--