From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Christopher Allan Webber Newsgroups: gmane.lisp.guile.bugs Subject: bug#27536: Add SRFI 71. Date: Thu, 29 Jun 2017 17:22:51 -0500 Message-ID: <8760fev3gk.fsf@dustycloud.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/signed; boundary="==-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" X-Trace: blaine.gmane.org 1498775055 10744 195.159.176.226 (29 Jun 2017 22:24:15 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Thu, 29 Jun 2017 22:24:15 +0000 (UTC) User-Agent: mu4e 0.9.18; emacs 25.2.1 To: 27536@debbugs.gnu.org Original-X-From: bug-guile-bounces+guile-bugs=m.gmane.org@gnu.org Fri Jun 30 00:24:09 2017 Return-path: Envelope-to: guile-bugs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dQhr6-0002QH-F9 for guile-bugs@m.gmane.org; Fri, 30 Jun 2017 00:24:08 +0200 Original-Received: from localhost ([::1]:41513 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dQhrB-0001Rp-Ai for guile-bugs@m.gmane.org; Thu, 29 Jun 2017 18:24:13 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:45876) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dQhr4-0001RY-DC for bug-guile@gnu.org; Thu, 29 Jun 2017 18:24:08 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dQhr0-0001c3-EI for bug-guile@gnu.org; Thu, 29 Jun 2017 18:24:06 -0400 Original-Received: from debbugs.gnu.org ([208.118.235.43]:42444) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dQhr0-0001be-2F for bug-guile@gnu.org; Thu, 29 Jun 2017 18:24:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1dQhqz-00028w-PV for bug-guile@gnu.org; Thu, 29 Jun 2017 18:24:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Christopher Allan Webber Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Thu, 29 Jun 2017 22:24:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 27536 X-GNU-PR-Package: guile X-GNU-PR-Keywords: X-Debbugs-Original-To: bug-guile@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.14987749978186 (code B ref -1); Thu, 29 Jun 2017 22:24:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 29 Jun 2017 22:23:17 +0000 Original-Received: from localhost ([127.0.0.1]:45121 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dQhqD-00027u-UN for submit@debbugs.gnu.org; Thu, 29 Jun 2017 18:23:17 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:54398) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dQhqB-00027h-OI for submit@debbugs.gnu.org; Thu, 29 Jun 2017 18:23:12 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dQhq3-0000UV-Of for submit@debbugs.gnu.org; Thu, 29 Jun 2017 18:23:06 -0400 Original-Received: from lists.gnu.org ([2001:4830:134:3::11]:37093) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dQhq3-0000U4-K3 for submit@debbugs.gnu.org; Thu, 29 Jun 2017 18:23:03 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:45334) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dQhq1-0000ff-3P for bug-guile@gnu.org; Thu, 29 Jun 2017 18:23:03 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dQhpx-0000JT-8x for bug-guile@gnu.org; Thu, 29 Jun 2017 18:23:01 -0400 Original-Received: from dustycloud.org ([50.116.34.160]:38168) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dQhpx-0000HU-0J for bug-guile@gnu.org; Thu, 29 Jun 2017 18:22:57 -0400 Original-Received: from oolong (localhost [127.0.0.1]) by dustycloud.org (Postfix) with ESMTPS id DB48C26632 for ; Thu, 29 Jun 2017 18:22:53 -0400 (EDT) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-guile@gnu.org List-Id: "Bug reports for GUILE, GNU's Ubiquitous Extension Language" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-guile-bounces+guile-bugs=m.gmane.org@gnu.org Original-Sender: "bug-guile" Xref: news.gmane.org gmane.lisp.guile.bugs:8822 Archived-At: --==-=-= Content-Type: multipart/mixed; boundary="=-=-=" --=-=-= Content-Type: text/plain Hello! SRFI 71 has a pretty cool syntax for assigning multiple values, and I wanted to use it! So here it is, ported to Guile. I've already assigned Guile copyright papers, as you probably know. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Add-SRFI-71-Extended-LET-syntax-for-multiple-values.patch Content-Transfer-Encoding: quoted-printable From=20373aad0f4ee6bde7e34f8b6b74c85be132df108b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 29 Jun 2017 17:19:06 -0500 Subject: [PATCH] Add SRFI 71: Extended LET-syntax for multiple values. * module/srfi/srfi-71.scm: New file. * module/srfi/Makefile.am: Add it. * doc/ref/srfi-modules.texi: Document it. * NEWS: Update. =2D-- NEWS | 6 ++ doc/ref/srfi-modules.texi | 20 ++++ module/srfi/Makefile.am | 3 +- module/srfi/srfi-71.scm | 265 ++++++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 module/srfi/srfi-71.scm diff --git a/NEWS b/NEWS index 7ce583b9b..ee059fb79 100644 =2D-- a/NEWS +++ b/NEWS @@ -17,6 +17,12 @@ The URI standard, RFC 3986, defines additional "relative= -ref" and for these URI subtypes has been improved. See "Universal Resource Identifiers" in the manual, for more. =20 +** SRFI-71 (Extended LET-syntax for multiple values) + +Guile now includes SRFI-71, which extends let, let*, and letrec to +support assigning multiple values. See "SRFI-71" in the manual for +details. + * New deprecations =20 ** Using `uri?' as a predicate on relative-refs deprecated diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi index 3d4415629..4527bebdc 100644 =2D-- a/doc/ref/srfi-modules.texi +++ b/doc/ref/srfi-modules.texi @@ -58,6 +58,7 @@ get the relevant SRFI documents from the SRFI home page * SRFI-64:: A Scheme API for test suites. * SRFI-67:: Compare procedures * SRFI-69:: Basic hash tables. +* SRFI-71:: Extended LET-syntax for multiple values. * SRFI-87:: =3D> in case clauses. * SRFI-88:: Keyword objects. * SRFI-98:: Accessing environment variables. @@ -5211,6 +5212,25 @@ specification of SRFI-64}. See @uref{http://srfi.schemers.org/srfi-67/srfi-67.html, the specification of SRFI-67}. =20 +@node SRFI-71 +@subsection SRFI-71 - Extended LET-syntax for multiple values +@cindex SRFI-71 + +This SRFI shadows the forms for @code{let}, @code{let*}, and @code{letrec} +so that they may accept multiple values. For example: + +@example +(use-modules (srfi srfi-71)) + +(let* ((x y (values 1 2)) + (z (+ x y))) + (* z 2)) +@result{} 6 +@end example + +See @uref{http://srfi.schemers.org/srfi-71/srfi-71.html, the +specification of SRFI-71}. + @node SRFI-69 @subsection SRFI-69 - Basic hash tables @cindex SRFI-69 diff --git a/module/srfi/Makefile.am b/module/srfi/Makefile.am index 7cbac6630..8b7e965c5 100644 =2D-- a/module/srfi/Makefile.am +++ b/module/srfi/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in. ## =2D## Copyright (C) 2000, 2004, 2006, 2008 Free Software Foundation, Inc. +## Copyright (C) 2000, 2004, 2006, 2008, 2017 Free Software Foundation, = Inc. ## ## This file is part of GUILE. ##=20=20=20 @@ -44,6 +44,7 @@ SOURCES =3D \ srfi-39.scm \ srfi-60.scm \ srfi-69.scm \ + srfi-71.scm \ srfi-88.scm =20 # Will poke this later. diff --git a/module/srfi/srfi-71.scm b/module/srfi/srfi-71.scm new file mode 100644 index 000000000..8e8f4c77e =2D-- /dev/null +++ b/module/srfi/srfi-71.scm @@ -0,0 +1,265 @@ +;; Copyright (c) 2005 Sebastian Egner.=20 +;; +;; Permission is hereby granted, free of charge, to any person obtaining a +;; copy of this software and associated documentation files (the +;; ``Software''), to deal in the Software without restriction, including +;; without limitation the rights to use, copy, modify, merge, publish, +;; distribute, sublicense, and/or sell copies of the Software, and to +;; permit persons to whom the Software is furnished to do so, subject to +;; the following conditions: +;; +;; The above copyright notice and this permission notice shall be included +;; in all copies or substantial portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, +;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +;; Reference implementation of SRFI-71 using PLT 208's modules +;; Sebastian.Egner@philips.com, 2005-04-29 +;; +;; Adjusted for Guile module system by +;; Christopher Allan Webber , 2017-06-29 + +(define-module (srfi srfi-71) + #:export (uncons unlist unvector values->list + values->vector) + #:replace ((srfi-let . let) + (srfi-let* . let*) + (srfi-letrec . letrec))) + +(define-syntax r5rs-let + (syntax-rules () + ((r5rs-let ((v x) ...) body1 body ...) + (let ((v x) ...) body1 body ...)) + ((r5rs-let tag ((v x) ...) body1 body ...) + (let tag ((v x) ...) body1 body ...)))) + +(define-syntax r5rs-let* + (syntax-rules () + ((r5rs-let* ((v x) ...) body1 body ...) + (let* ((v x) ...) body1 body ...)))) + +(define-syntax r5rs-letrec + (syntax-rules () + ((r5rs-letrec ((v x) ...) body1 body ...) + (letrec ((v x) ...) body1 body ...))))=20=20 + +; --- textual copy of 'letvalues.scm' starts here --- + +; Reference implementation of SRFI-71 (generic part) +; Sebastian.Egner@philips.com, 20-May-2005, PLT 208 +; +; In order to avoid conflicts with the existing let etc. +; the macros defined here are called srfi-let etc., +; and they are defined in terms of r5rs-let etc. +; It is up to the actual implementation to save let/*/rec +; in r5rs-let/*/rec first and redefine let/*/rec +; by srfi-let/*/rec then. +; +; There is also a srfi-letrec* being defined (in view of R6RS.) +; +; Macros used internally are named i:. +; +; Abbreviations for macro arguments: +; bs - +; b - component of a binding spec (values, , or ) +; v - +; vr - for rest list +; x - +; t - newly introduced temporary variable +; vx - ( ) +; rec - flag if letrec is produced (and not let) +; cwv - call-with-value skeleton of the form (x formals) +; (call-with-values (lambda () x) (lambda formals /payload/)) +; where /payload/ is of the form (let (vx ...) body1 body ...). +; +; Remark (*): +; We bind the variables of a letrec to i:undefined since there is +; no portable (R5RS) way of binding a variable to a values that +; raises an error when read uninitialized. + +(define i:undefined 'undefined) + +(define-syntax srfi-letrec* ; -> srfi-letrec + (syntax-rules () + ((srfi-letrec* () body1 body ...) + (srfi-letrec () body1 body ...)) + ((srfi-letrec* (bs) body1 body ...) + (srfi-letrec (bs) body1 body ...)) + ((srfi-letrec* (bs1 bs2 bs ...) body1 body ...) + (srfi-letrec (bs1) (srfi-letrec* (bs2 bs ...) body1 body ...))))) + +(define-syntax srfi-letrec ; -> i:let + (syntax-rules () + ((srfi-letrec ((b1 b2 b ...) ...) body1 body ...) + (i:let "bs" #t () () (body1 body ...) ((b1 b2 b ...) ...))))) + +(define-syntax srfi-let* ; -> srfi-let + (syntax-rules () + ((srfi-let* () body1 body ...) + (srfi-let () body1 body ...)) + ((srfi-let* (bs) body1 body ...) + (srfi-let (bs) body1 body ...)) + ((srfi-let* (bs1 bs2 bs ...) body1 body ...) + (srfi-let (bs1) (srfi-let* (bs2 bs ...) body1 body ...))))) + +(define-syntax srfi-let ; -> i:let or i:named-let + (syntax-rules () + ((srfi-let ((b1 b2 b ...) ...) body1 body ...) + (i:let "bs" #f () () (body1 body ...) ((b1 b2 b ...) ...))) + ((srfi-let tag ((b1 b2 b ...) ...) body1 body ...) + (i:named-let tag () (body1 body ...) ((b1 b2 b ...) ...))))) + +(define-syntax i:let + (syntax-rules (values) + +; (i:let "bs" rec (cwv ...) (vx ...) body (bs ...)) +; processes the binding specs bs ... by adding call-with-values +; skeletons to cwv ... and bindings to vx ..., and afterwards +; wrapping the skeletons around the payload (let (vx ...) . body). + + ; no more bs to process -> wrap call-with-values skeletons + ((i:let "bs" rec (cwv ...) vxs body ()) + (i:let "wrap" rec vxs body cwv ...)) + + ; recognize form1 without variable -> dummy binding for side-effects + ((i:let "bs" rec cwvs (vx ...) body (((values) x) bs ...)) + (i:let "bs" rec cwvs (vx ... (dummy (begin x #f))) body (bs ...))) + + ; recognize form1 with single variable -> just extend vx ... + ((i:let "bs" rec cwvs (vx ...) body (((values v) x) bs ...)) + (i:let "bs" rec cwvs (vx ... (v x)) body (bs ...))) + + ; recognize form1 without rest arg -> generate cwv + ((i:let "bs" rec cwvs vxs body (((values v ...) x) bs ...)) + (i:let "form1" rec cwvs vxs body (bs ...) (x ()) (values v ...))) + + ; recognize form1 with rest arg -> generate cwv + ((i:let "bs" rec cwvs vxs body (((values . vs) x) bs ...)) + (i:let "form1+" rec cwvs vxs body (bs ...) (x ()) (values . vs))) + + ; recognize form2 with single variable -> just extend vx ... + ((i:let "bs" rec cwvs (vx ...) body ((v x) bs ...)) + (i:let "bs" rec cwvs (vx ... (v x)) body (bs ...))) + + ; recognize form2 with >=3D2 variables -> transform to form1 + ((i:let "bs" rec cwvs vxs body ((b1 b2 b3 b ...) bs ...)) + (i:let "form2" rec cwvs vxs body (bs ...) (b1 b2) (b3 b ...))) + +; (i:let "form1" rec cwvs vxs body bss (x (t ...)) (values v1 v2 v ...)) +; processes the variables in v1 v2 v ... adding them to (t ...) +; and producing a cwv when finished. There is not rest argument. + + ((i:let "form1" rec (cwv ...) vxs body bss (x ts) (values)) + (i:let "bs" rec (cwv ... (x ts)) vxs body bss)) + ((i:let "form1" rec cwvs (vx ...) body bss (x (t ...)) (values v1 v ..= .)) + (i:let "form1" rec cwvs (vx ... (v1 t1)) body bss (x (t ... t1)) (val= ues v ...))) + +; (i:let "form1+" rec cwvs vxs body bss (x (t ...)) (values v ... . vr)) +; processes the variables in v ... . vr adding them to (t ...) +; and producing a cwv when finished. The rest arg is vr. + + ((i:let "form1+" rec cwvs (vx ...) body bss (x (t ...)) (values v1 v2 = . vs)) + (i:let "form1+" rec cwvs (vx ... (v1 t1)) body bss (x (t ... t1)) (va= lues v2 . vs))) + ((i:let "form1+" rec (cwv ...) (vx ...) body bss (x (t ...)) (values v= 1 . vr)) + (i:let "bs" rec (cwv ... (x (t ... t1 . tr))) (vx ... (v1 t1) (vr tr)= ) body bss)) + ((i:let "form1+" rec (cwv ...) (vx ...) body bss (x ()) (values . vr)) + (i:let "bs" rec (cwv ... (x tr)) (vx ... (vr tr)) body bss)) + +; (i:let "form2" rec cwvs vxs body bss (v ...) (b ... x)) +; processes the binding items (b ... x) from form2 as in +; (v ... b ... x) into ((values v ... b ...) x), i.e. form1. +; Then call "bs" recursively. + + ((i:let "form2" rec cwvs vxs body (bs ...) (v ...) (x)) + (i:let "bs" rec cwvs vxs body (((values v ...) x) bs ...))) + ((i:let "form2" rec cwvs vxs body bss (v ...) (b1 b2 b ...)) + (i:let "form2" rec cwvs vxs body bss (v ... b1) (b2 b ...))) + +; (i:let "wrap" rec ((v x) ...) (body ...) cwv ...) +; wraps cwv ... around the payload generating the actual code. +; For letrec this is of course different than for let. + + ((i:let "wrap" #f vxs body) + (r5rs-let vxs . body)) + ((i:let "wrap" #f vxs body (x formals) cwv ...) + (call-with-values + (lambda () x) + (lambda formals (i:let "wrap" #f vxs body cwv ...)))) + + ((i:let "wrap" #t vxs body) + (r5rs-letrec vxs . body)) + ((i:let "wrap" #t ((v t) ...) body cwv ...) + (r5rs-let ((v i:undefined) ...) ; (*) + (i:let "wraprec" ((v t) ...) body cwv ...))) +=20=20=20=20 +; (i:let "wraprec" ((v t) ...) body cwv ...) +; generate the inner code for a letrec. The variables v ... +; are the user-visible variables (bound outside), and t ...=20 +; are the temporary variables bound by the cwv consumers. + + ((i:let "wraprec" ((v t) ...) (body ...)) + (begin (set! v t) ... (r5rs-let () body ...))) + ((i:let "wraprec" vxs body (x formals) cwv ...) + (call-with-values + (lambda () x) + (lambda formals (i:let "wraprec" vxs body cwv ...)))) + + )) + +(define-syntax i:named-let + (syntax-rules (values) + +; (i:named-let tag (vx ...) body (bs ...)) +; processes the binding specs bs ... by extracting the variable +; and expression, adding them to vx and turning the result into +; an ordinary named let. + + ((i:named-let tag vxs body ()) + (r5rs-let tag vxs . body))=20=20=20=20 + ((i:named-let tag (vx ...) body (((values v) x) bs ...)) + (i:named-let tag (vx ... (v x)) body (bs ...))) + ((i:named-let tag (vx ...) body ((v x) bs ...)) + (i:named-let tag (vx ... (v x)) body (bs ...))))) + +; --- standard procedures --- + +(define (uncons pair) + (values (car pair) (cdr pair))) + +(define (uncons-2 list) + (values (car list) (cadr list) (cddr list))) + +(define (uncons-3 list) + (values (car list) (cadr list) (caddr list) (cdddr list))) + +(define (uncons-4 list) + (values (car list) (cadr list) (caddr list) (cadddr list) (cddddr list))) + +(define (uncons-cons alist) + (values (caar alist) (cdar alist) (cdr alist))) + +(define (unlist list) + (apply values list)) + +(define (unvector vector) + (apply values (vector->list vector))) + +; --- standard macros --- + +(define-syntax values->list + (syntax-rules () + ((values->list x) + (call-with-values (lambda () x) list)))) + +(define-syntax values->vector + (syntax-rules () + ((values->vector x) + (call-with-values (lambda () x) vector)))) + +; --- textual copy of 'letvalues.scm' ends here --- =2D-=20 2.13.1 --=-=-=-- --==-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEUQqGKOKndniPjHCcS8Alkl/49NMFAllVfb0ACgkQS8Alkl/4 9NP2OQ/+P2XidVuyoY94Ueh0e/C+1e+Nbf3zuAkschXWi2w8q5kzzDJnOUoKQ1RV y37irJGbR8NKd9bzvMJDl2fmwwWi4zhdYRsBebH9rpJoY2g1UI2DOrKRW5mpQbj/ AUTYsrw78zyzJWU1AQajiKJPxDez0nBp+HvvCveBy5wxkELGDtHvilSj6B9X0mBk YFY4X6QcT3J5AhqmYB7XtsuZHlhdVY562nqpVtvFWn8rOyEZabvVlpHDwZeogByC lkjs2Tl6+yPbxKwhIkN7poIWLLoutAbWVqi685/y/pVEBYnVo0M9QUNHTYMIu0/f 0TK93GdRF2/MqnmWqydv9XWOCUxqECTdVSuyztbCB2j/lE2LpDMf5fvOp0xbO7rB NMtlSeSU2jmg1RvJSq9tpbaNx6eugN5K6AK1U3+waDgzjJ8O3PjwDzrserJP2gnr Khu6NjlnY+JKN4OVGZaHLJqSNqDkIfWho42WIVaN3MxZIX9vgxdbbQ8WF/XEhdpB DA7bIdydbb/JqzRI8kcCHokqP1vy4UV1ExhHXcMRFsEbnCiywOr+/uXnrQK2a/b8 OV3groETK8vV6PPu0nVygtZhrD6guRwz0okEZqWEiZghrZyuuqM6sNXVibLDQCxT ZdJmsjxjIk81whlpa9gY9p7w/Zi80wlftSAfc3/Tlbt0c7tOUj0= =Sq1U -----END PGP SIGNATURE----- --==-=-=--