GNU bug report logs - #77762
[PATCH] web: Add JSON module.

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: guile; Reported by: "Thompson, David" <dthompson2@HIDDEN>; Keywords: patch; dated Sat, 12 Apr 2025 13:16:02 UTC; Maintainer for guile is bug-guile@HIDDEN.

Message received at 77762 <at> debbugs.gnu.org:


Received: (at 77762) by debbugs.gnu.org; 20 Apr 2025 13:48:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Apr 20 09:48:39 2025
Received: from localhost ([127.0.0.1]:47832 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1u6V2E-0001mk-6Q
	for submit <at> debbugs.gnu.org; Sun, 20 Apr 2025 09:48:39 -0400
Received: from mail-pg1-x536.google.com ([2607:f8b0:4864:20::536]:47481)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <maxim.cournoyer@HIDDEN>)
 id 1u6V25-0001mN-OA
 for 77762 <at> debbugs.gnu.org; Sun, 20 Apr 2025 09:48:34 -0400
Received: by mail-pg1-x536.google.com with SMTP id
 41be03b00d2f7-aee79a0f192so2026493a12.3
 for <77762 <at> debbugs.gnu.org>; Sun, 20 Apr 2025 06:48:29 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1745156902; x=1745761702; darn=debbugs.gnu.org;
 h=mime-version:user-agent:message-id:date:references:in-reply-to
 :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
 bh=hBee4q1jgt1B3GjDAGKHiv+nYbn+PzStWyHL/0ofh90=;
 b=flUUTTYz6SoDM/SfkWE8gJMHEREHMPdOI+1oR3zPwISiQq/49Mwj1DSUSR6HXzQ9Sw
 tEAJ+DwQnhH3CnF9AQI7oq4Ck+xhMjn8aE5KS0hl6e/UUkLzOdj6nz6YgQvF3DzLERZd
 XWO9ymybLt6OELCGvqc+dsX4WW/R9SgPafpoJ20GtyyWVAmScG/B6r8YsyF9DI5W7HEj
 iH+GKIEl/+Y2RKXC5PSeB33vGzWFvPccqkRtPgr9UuTCUi01pGna1NLFWT8TXcVaQ1Tm
 yYcutNt77Vf9rFZ2jFEulIB7NqDDKZWLWZf4b7dheEFb9xiMvxwwtcRsB9INR3ptyOIi
 IyxQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1745156902; x=1745761702;
 h=mime-version:user-agent:message-id:date:references:in-reply-to
 :subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
 :message-id:reply-to;
 bh=hBee4q1jgt1B3GjDAGKHiv+nYbn+PzStWyHL/0ofh90=;
 b=vdk+xXzKxExyKwvLhm8TA/Bt8pr6L6hlYUEv7S+TU/txeUBHTtm2MoB4c/TgqiDd5D
 xZ2chfj2QynID5TM64MHTkzU0EuO6HGVLrxh6DJToKB38tOhnZ4KTYcbwes8kBvrGbOX
 5RUQMuSD0VKrxI42x93XDgxdPU/UQJlr6qDkvUu7PN7j03msHKM9OrvkXzeMj2s3aVf1
 QX3aT/UbsRbCmAy3chgVwoRq/sKzpEi4jC2ASA0OukksbHMIvf7j0SFa7bC31Q96KjBI
 vXvrU+iNfwLH7OUc7tycAz+HiOr23GbBdVMX6OYgjAXll2SodvLfVQXAolJC6tVsPfBl
 N/nQ==
X-Gm-Message-State: AOJu0YxtbslCMkodFB4bOTlLcA6TgvfnOUdOBbsc9T1pPmJwRc5fXpIC
 P74dcBDdpFG52A1+EbbG7Ti2hH7ogf7N5vziuwd0KQewZ9Bh837QrpzKlA==
X-Gm-Gg: ASbGncvXNOrSg17oJKPBjXWNH34WWAoFZ763kfErVKSaqQzJHSQFRsiv62XYeqZ8G1X
 T1rboc/8V+7zfgjfvmXwQhV9X4N8WUzUm+iWp5LE2MqXHEHsJrrw93dBFVmva4CmPgUOgekE52R
 zZjqlmK9ou5g1XDIClaE7vCTGUX+NGZg0sfGYnyeasJzkZaF0eufAlXqLnwbMr6/7kmEv2ifohp
 r3A1OC6IzrxuFVmYieZpL4oY3xGelQdsum/7zrX8Cd9dYZLDMmh2ql4mTp8J3ns0raJ1oqMiFiH
 CIYVRpnj7jPvatduLNw1da/NFg8ICQTF7vnaG8A=
X-Google-Smtp-Source: AGHT+IEJ/18j3aOom5oVarn48XFm+PSHzKw5kvamcLEYqI857+Pcw/06Q+/KGQ0AjSWJ4tNQTbX2Pg==
X-Received: by 2002:a17:90b:3848:b0:305:2d27:7c9f with SMTP id
 98e67ed59e1d1-3087bb696bcmr14018739a91.16.1745156902067; 
 Sun, 20 Apr 2025 06:48:22 -0700 (PDT)
Received: from terra ([2405:6586:be0:0:83c8:d31d:2cec:f542])
 by smtp.gmail.com with ESMTPSA id
 98e67ed59e1d1-3087df4df83sm4665618a91.34.2025.04.20.06.48.20
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Sun, 20 Apr 2025 06:48:21 -0700 (PDT)
From: Maxim Cournoyer <maxim.cournoyer@HIDDEN>
To: "Thompson, David" <dthompson2@HIDDEN>
Subject: Re: bug#77762: [PATCH] web: Add JSON module.
In-Reply-To: <CAJ=Rwfayx9x9sV2nUa1hm87iZNMM9Z0vgs4A65Z0BiRBRsFCOw@HIDDEN>
 (David Thompson's message of "Mon, 14 Apr 2025 08:16:13 -0400")
References: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
 <87plhfuue8.fsf@HIDDEN>
 <CAJ=Rwfayx9x9sV2nUa1hm87iZNMM9Z0vgs4A65Z0BiRBRsFCOw@HIDDEN>
Date: Sun, 20 Apr 2025 22:48:00 +0900
Message-ID: <87tt6j9c6n.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 77762
Cc: 77762 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hi David,

"Thompson, David" <dthompson2@HIDDEN> writes:

> Hi Maxim,
>
> Thanks for the review!

My pleasure!  It's a small thing I can do to try to help nudge builtin
JSON support in Guile, which I agree has its place in 2025.  In general,
I'd like Guile to compete a bit more with Python in the out-of-the-box
library capabilities.  Especially since outside of Guix installing Guile
libraries is probably not that fun (I'd suspect many Guile libraries to
be missing or outdated on various distributions), so a more useful core
has even more value there.

[...]

>> Is there particular reason for using vectors instead of plain list to
>> represent JSON arrays?  The later would be more idiomatic unless there
>> are technical reasons (perhaps performance?).
>
> Back in 2015 I chose lists out of convenience because lists are such a
> fundamental data structure in Scheme. It is very tempting! However,
> there are a couple of issues: 1) O(n) access time for lists is not
> great when there's a perfectly suitable O(1) data structure with read
> syntax sitting right there and 2) It creates ambiguity when lists are
> also used to represent objects. My previous patch used the symbol '@
> as a sentinel to mark objects, but it was kinda gross and I grew to
> dislike it more and more over the years. SRFI-180 uses vectors,
> Racket's JSON library uses vectors, etc. and I think they made the
> right call.

I see.  It makes sense, thanks for explaining.

[...]

>> Hm, I wonder what (list port) looks like in the irritants when the
>> exception is reported; is it useful?  Shouldn't it show instead the
>> problematic value?
>
> By including the port in the irritants it allows the exception handler
> to use 'port-line' and 'port-column' to show where in the JSON
> document the error occurred (for ports with such information like file
> ports).

OK!

>> > +  (define (consume-whitespace)
>> > +    (case (peek-char port)
>> > +      ((#\space #\tab #\return #\newline)
>>
>> Should a match + ((? char-whitespace?)) predicate pattern be used here
>> instead, or similar?  Or perhaps the above is faster and more
>> self-contained, which can be a good thing.
>
> ECMA-404 states that these 4 characters are the only acceptable
> whitespace characters:
>
> "Whitespace is any sequence of one or more of the following code
> points: character tabulation (U+0009), line feed (U+000A), carriage
> return (U+000D), and space (U+0020)."

Makes sense.

[...]

>> > +  (define (read-fraction)
>> > +    (case (peek-char port)
>> > +      ((#\.)
>> > +       (read-char port)
>> > +       (let lp ((mag 10))
>> > +         (let ((n (read-digit-maybe)))
>> > +           (if n (+ (/ n mag) (lp (* mag 10))) 0))))
>> > +      (else 0)))
>>
>> Should the above be named 'read-decimal' ?  Does a decimal number in
>> JSON always start with '.' and not with 0. ?  I was a bit puzzled on
>> what 'mag' may mean here, I guess 'magnitude' although there doesn't
>> appear to have a clear terminology for it.
>
> It's called 'read-fraction' because it reads the fractional part of
> the number.  I considered 'read-decimal' but I think it's less
> descriptive. This procedure is called from two places, after the
> respective caller has already read the digits before the decimal
> point. 'mag' does indeed mean 'magnitude', as each digit read
> increases the order of magnitude of the resulting number. I borrowed
> this name from Hoot's 'read' implementation, which means it's probably
> in Guile's pure-Scheme 'read' implementation as well.

OK, thanks for explaining.  I realized later in my review that these are
very dependent on when they are called (they are very specific or
narrow, more than their name might suggest).  It's fine.

[...]

> The following clause checks for '.'. We need to distinguish between 3
> types of input here:
>
> - invalid extraneous zeroes like '09' (ECMA-404 says this is not allowed)
> - fractional notation like '0.123'
> - plain '0'
>
> If I leave out this clause, we can no longer distinguish errors from
> plain zeroes.  There's likely other ways to express it but this feels
> straightforward enough.
>
> However, it was a great idea to take another look at this code because
> there is a bug! '0e3' is a valid JSON number that this code rejects.
> It should parse to 0.  My updated patch fixes this and adds a test
> case.

Good catch!

[...]

>> > +  (define (write-object obj)
>> > +    (put-char port #\{)
>> > +    (match obj
>> > +      ((head . rest)
>> > +       (write-pair head)
>> > +       (let lp ((obj rest))
>> > +         (match obj
>> > +           (() (values))
>>
>> Any reason to return (values) instead of some dummy #t to denote 'no-op'
>> ?.
>
> The loop is evaluated for effect and thus there is nothing to return
> so returning 0 values makes sense. This is something I picked up from
> Andy Wingo.

Interesting.

>> > +           ((head . rest)
>> > +            (put-char port #\,)
>> > +            (write-pair head)
>> > +            (lp rest))
>> > +           (_ (fail "invalid object" obj))))))
>> > +    (put-char port #\}))
>> > +  (define (write-array v)
>> > +    (put-char port #\[)
>> > +    (match (vector-length v)
>> > +      (0 (values))
>> > +      (n
>> > +       (write-value (vector-ref v 0))
>> > +       (do ((i 1 (1+ i)))
>> > +           ((= i n))
>> > +         (put-char port #\,)
>> > +         (write-value (vector-ref v i)))))
>>
>> I suppose the above is more efficient than a for-each loop?  I'd be
>> curious to see it profiled, if you still have data.  At least now I see
>> than for > 100k, vector-ref is faster than list-ref, which probably
>> explains why you went with vectors (could still be an implementation
>> detail with the list->vector call left in the writer though, in my
>> opinion).
>
> Yes, it is more efficient because it avoids closure allocation. Also,
> I just don't see any reason to import (rnrs base) or (srfi srfi-43) to
> get vector-for-each when looping over a vector is trivial. I didn't
> profile anything.

Yeah, I was thinking in terms of plain lists, didn't know we didn't
iterators for vectors in the core (I've seldom used vectors).  Sounds
reasonable.

>> > +    (put-char port #\]))
>> > +  (define (write-number x)
>> > +    (if (or (exact-integer? x)
>> > +            (and (real? x)
>> > +                 (inexact? x)
>> > +                 ;; NaNs and infinities are not allowed.
>> > +                 (not (or (nan? x) (inf? x)))))
>> > +        ;; Scheme's string representations of exact integers and floats
>> > +        ;; are compatible with JSON.
>> > +        (put-string port (number->string x))
>> > +        (fail "invalid number" x)))
>> > +  (define (write-value x)
>> > +    (match x
>> > +      (#t (put-string port "true"))
>> > +      (#f (put-string port "false"))
>> > +      ('null (put-string port "null"))
>> > +      (() (put-string port "{}"))
>> > +      ((? pair?) (write-object x))
>> > +      ((? vector?) (write-array x))
>> > +      ((? string?) (write-string x))
>> > +      ((? number?) (write-number x))
>> > +      (_ (fail "invalid value" x))))
>> > +  (write-value exp))
>>
>> Phew.  That's a pretty low-level parser!  I hope it's fast, otherwise it
>> seems it'd be more concise/fun/maintainable to devise a PEG-based one,
>> which appears to be doable for JSON, from what I've read.  Perhaps
>> sprinkle with a few performance-related comments where such concerns
>> impacted the design choices, so that we can remember and retest/reverify
>> these in the future when Guile evolves.
>
> JSON is a pretty simple format and thus I think a hand-rolled parser
> is appropriate.  It's much simpler than 'read', anyway.  I suppose it
> would be more concise, but "PEG parser" and "fun" do not go together
> for me.  At ~300 lines of quite simple code (I did not go hog wild on
> macros or fancy abstractions nor did I sacrifice readable code for
> performance) I don't think there is much concern regarding
> maintenance.  If someone wants to experiment to see how a PEG parser
> compares, though, feel free.

Someone could always make that experiment in the future and suggest a
replacement, if the performance is as good or better and the code
simpler.  LGTM.

Reviewed-by: Maxim Cournoyer <maxim.cournoyer@gmail>

-- 
Thanks,
Maxim




Information forwarded to bug-guile@HIDDEN:
bug#77762; Package guile. Full text available.

Message received at 77762 <at> debbugs.gnu.org:


Received: (at 77762) by debbugs.gnu.org; 14 Apr 2025 12:16:45 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Apr 14 08:16:45 2025
Received: from localhost ([127.0.0.1]:46186 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1u4Ijy-0000RQ-LA
	for submit <at> debbugs.gnu.org; Mon, 14 Apr 2025 08:16:45 -0400
Received: from mail-ed1-x52a.google.com ([2a00:1450:4864:20::52a]:44450)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <dthompson2@HIDDEN>)
 id 1u4Ijq-0000Qw-LP
 for 77762 <at> debbugs.gnu.org; Mon, 14 Apr 2025 08:16:38 -0400
Received: by mail-ed1-x52a.google.com with SMTP id
 4fb4d7f45d1cf-5e6167d0536so7936657a12.1
 for <77762 <at> debbugs.gnu.org>; Mon, 14 Apr 2025 05:16:34 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=worcester.edu; s=google; t=1744632987; x=1745237787; darn=debbugs.gnu.org;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:from:to:cc:subject:date:message-id:reply-to;
 bh=7ZGtBbM9jSg+G4TSsA718zVnT7j974Z9vm5k0w6Vwy4=;
 b=kzhWv5+FeJMz9Cqd1CvbFo53vJF5FpRByL6czmS1hta/kOmxfV6ABrRuh+VIaz874O
 OKA/q+HAUxgPAMzYJ8pvdOMmsby8kZksbGUMI3sGXphUd4lo2TmaBcMoGZMc7UxOHUuY
 8Wj9JUQHM1h81gix6bdx6jCZ/BD0yEmC/JsYY=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1744632987; x=1745237787;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id
 :reply-to;
 bh=7ZGtBbM9jSg+G4TSsA718zVnT7j974Z9vm5k0w6Vwy4=;
 b=H4az7ombCNKktuKl5RPJqUBStyZlbfoJ3Py80G6PkgfweonWs3JzBKnvr7louEDFEQ
 6sUSBatJvbw3CUvF0oFlTBcuQ/sE0X20qsus+rv0yTyl8/DVyVu57M29UUvYBIIDMLHz
 4o98DTSereKz1unfffZqr3l8z/+9KWNkC8oxLwR0Ml9bXr5ZIJn9aUEX+6Tve4uot162
 5BVdzkOYaHqonbbAj8Riy40L9Rb0O04xAHnCaUrh96kvZQITSUGTcsZzcAknS7NuVDfl
 PgqmD0zSYAiIhWS07fBKBDNBt9fsqJwqFHI2gVXHterDFeig4zT20RC9snM8THEQsSyo
 C0dw==
X-Gm-Message-State: AOJu0YzI1DjK8PXtwkToaReGp9r8AGrm9WubnVNJCTGE1fSN3tZAIgej
 uIXVQjl+c+j/vZ7+eFXEdlgJY8xiE5UUIzDukMI/BtYHJXeNWztRnZBLGN26yKfPG0kjz4fcYw+
 KjmH6R5HuI7AtBhyzokDRpCZzgOxIptgsN/loXHUnS6U3po3v3x8=
X-Gm-Gg: ASbGncu89hK8XI5GLqvd4pchE/tUM3N7wB7Z+PKCxUWA1s/YkuGPSRPQk9qlCBBDuT3
 sUbknH9sOJNj323weSc2jpcIwcCvdbvVOYfgL9r0SwLUNF93UU9Yhm4sVETX2cnKn2mCbX/ZBB/
 tQT4Rm/xVG8ySTSR2zlnCOfq0pYRzKkTURjr/f
X-Google-Smtp-Source: AGHT+IEwNi6sAic0GGEaa5wsNc01gz7or0xNZxXf+5Fas/RJ91ESHm4nJFJICQv3jRCljgUZoPPzr9Y0OATPOxBwrBw=
X-Received: by 2002:a05:6402:3591:b0:5e7:c773:ae35 with SMTP id
 4fb4d7f45d1cf-5f36f78064fmr9890762a12.5.1744632986460; Mon, 14 Apr 2025
 05:16:26 -0700 (PDT)
MIME-Version: 1.0
References: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
 <87plhfuue8.fsf@HIDDEN>
In-Reply-To: <87plhfuue8.fsf@HIDDEN>
From: "Thompson, David" <dthompson2@HIDDEN>
Date: Mon, 14 Apr 2025 08:16:13 -0400
X-Gm-Features: ATxdqUEuXeeBJqEbMTJyBnNnAYdCddnDIwCjAATe1jjOnmEHOmFfgk6rTFF0ewM
Message-ID: <CAJ=Rwfayx9x9sV2nUa1hm87iZNMM9Z0vgs4A65Z0BiRBRsFCOw@HIDDEN>
Subject: Re: bug#77762: [PATCH] web: Add JSON module.
To: Maxim Cournoyer <maxim.cournoyer@HIDDEN>
Content-Type: multipart/mixed; boundary="0000000000006c2d480632bc057b"
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 77762
Cc: 77762 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

--0000000000006c2d480632bc057b
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hi Maxim,

Thanks for the review!

On Mon, Apr 14, 2025 at 2:31=E2=80=AFAM Maxim Cournoyer
<maxim.cournoyer@HIDDEN> wrote:
>
> > +@example
> > +@verbatim
> > +{
> > +  "name": "Eva Luator",
> > +  "age": 24,
> > +  "schemer": true,
> > +  "hobbies": [
> > +    "hacking",
> > +    "cycling",
> > +    "surfing"
> > +  ]
> > +}
> > +@end verbatim
> > +@end example
> > +
> > +can be represented with the following Scheme expression:
> > +
> > +@example
> > +@verbatim
> > +'(("name" . "Eva Luator")
> > +  ("age" . 24)
> > +  ("schemer" . #t)
> > +  ("hobbies" . #("hacking" "cycling" "surfing")))
> > +@end verbatim
> > +@end example
>
> Is there particular reason for using vectors instead of plain list to
> represent JSON arrays?  The later would be more idiomatic unless there
> are technical reasons (perhaps performance?).

Back in 2015 I chose lists out of convenience because lists are such a
fundamental data structure in Scheme. It is very tempting! However,
there are a couple of issues: 1) O(n) access time for lists is not
great when there's a perfectly suitable O(1) data structure with read
syntax sitting right there and 2) It creates ambiguity when lists are
also used to represent objects. My previous patch used the symbol '@
as a sentinel to mark objects, but it was kinda gross and I grew to
dislike it more and more over the years. SRFI-180 uses vectors,
Racket's JSON library uses vectors, etc. and I think they made the
right call.

> > +Strings, exact integers, inexact reals (excluding NaNs and infinities)=
,
> > +@code{#t}, @code{#f}, the symbol @code{null}, vectors, and association
> > +lists may be serialized as JSON.  Association lists serialize as JSON
> > +objects and vectors serialize as JSON arrays.  The keys of association
> > +lists @emph{must} be strings.
> > +
> > +@deffn {Scheme Procedure} read-json [port]
> > +
> > +Parse a JSON-encoded value from @var{port} and return its Scheme
> > +representation.  If @var{port} is unspecified, the current input port =
is
> > +used.
> > +
> > +@example
> > +@verbatim
> > +(call-with-input-string "[true,false,null,42,\"foo\"]" read-json)
> > +;; =3D> #(#t #f null 42 "foo")
> > +
> > +(call-with-input-string "{\"foo\":1,\"bar\":2}" read-json)
> > +;; =3D> (("foo" . 1) ("bar" . 2))
> > +@end verbatim
> > +@end example
> > +
> > +@end deffn
> > +
> > +@deftp {Exception Type} &json-read-error
> > +An exception type denoting JSON read errors.
> > +@end deftp
> >
> > +@deffn {Scheme Procedure} write-json exp [port]
> > +
> > +Serialize the expression @var{exp} as JSON-encoded text to @var{port}.
> > +If @var{port} is unspecified, the current output port is used.
> > +
> > +@example
> > +@verbatim
> > +(with-output-to-string (lambda () (write-json #(#t #f null 42 "foo")))=
)
> > +;; =3D> "[true,false,null,42,\"foo\"]"
> > +
> > +(with-output-to-string (lambda () (write-json '(("foo" . 1) ("bar" . 2=
)))))
> > +;; =3D> "{\"foo\":1,\"bar\":2}"
> > +@end verbatim
> > +@end example
> > +
> > +@end deffn
> > +
> > +@deftp {Exception Type} &json-write-error
> > +An exception type denoting JSON write errors.
> > +@end deftp
>
> I think it could be a bit nicer if the deffn of read-json and write-json
> explicitly mentioned that upon error an exception of type X is raised.

Sure, makes sense to mention that.

> > +
> >  @node Web Client
> >  @subsection Web Client
> >
> > diff --git a/module/web/json.scm b/module/web/json.scm
> > new file mode 100644
> > index 000000000..41aac0e90
> > --- /dev/null
> > +++ b/module/web/json.scm
> > @@ -0,0 +1,308 @@
> > +;;;; json.scm --- JSON reader/writer (ECMA-404)
> > +;;;; Copyright (C) 2025 Free Software Foundation, Inc.
> > +;;;;
> > +;;;; This library is free software; you can redistribute it and/or
> > +;;;; modify it under the terms of the GNU Lesser General Public
> > +;;;; License as published by the Free Software Foundation; either
> > +;;;; version 3 of the License, or (at your option) any later version.
> > +;;;;
> > +;;;; This library is distributed in the hope that it will be useful,
> > +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > +;;;; Lesser General Public License for more details.
> > +;;;;
> > +;;;; You should have received a copy of the GNU Lesser General Public
> > +;;;; License along with this library; if not, write to the Free Softwa=
re
> > +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 021=
10-1301 USA
>
> The FSF has gone office-less, so the above address is now incorrect [0].
> The up-to-date template for the copyright notice (header) reads [1]:
>
> --8<---------------cut here---------------start------------->8---
>     This program is free software: you can redistribute it and/or modify
>     it under the terms of the GNU General Public License as published by
>     the Free Software Foundation, either version 3 of the License, or
>     (at your option) any later version.
>
>     This program is distributed in the hope that it will be useful, but
>     WITHOUT ANY WARRANTY; without even the implied warranty of
>     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>     General Public License for more details.
>
>     You should have received a copy of the GNU General Public License
>     along with this program. If not, see
>     <https://www.gnu.org/licenses/>.
> --8<---------------cut here---------------end--------------->8---
>
> [0]  https://www.fsf.org/blogs/community/fsf-office-closing-party
> [1]  https://www.gnu.org/licenses/gpl-howto.html

Ah, right. Good catch.  I knew about this change but wasn't thinking
about the copyright header at the time. I even walked through Franklin
St. recently and thought about the FSF no longer having an office.  I
always thought it was a bit silly to include a mailing address in a
license header because offices are not forever.

> > +
> > +(define-module (web json)
> > +  #:use-module (ice-9 exceptions)
> > +  #:use-module (ice-9 match)
> > +  #:use-module (ice-9 textual-ports)
> > +  #:export (&json-read-error
> > +            read-json
> > +
> > +            &json-write-error
> > +            write-json))
> > +
> > +(define-exception-type &json-read-error &error
> > +  make-json-read-error
> > +  json-read-error?)
> > +
> > +(define* (read-json #:optional (port (current-input-port)))
> > +  "Parse a JSON-encoded value from @var{port} and return its Scheme
> > +representation.  If @var{port} is unspecified, the current input port =
is
> > +used."
> > +  (define (fail message)
> > +    (raise-exception
> > +     (make-exception (make-json-read-error)
> > +                     (make-exception-with-origin 'read-json)
> > +                     (make-exception-with-message message)
> > +                     (make-exception-with-irritants (list port)))))
>
> Hm, I wonder what (list port) looks like in the irritants when the
> exception is reported; is it useful?  Shouldn't it show instead the
> problematic value?

By including the port in the irritants it allows the exception handler
to use 'port-line' and 'port-column' to show where in the JSON
document the error occurred (for ports with such information like file
ports).

> > +  (define (consume-whitespace)
> > +    (case (peek-char port)
> > +      ((#\space #\tab #\return #\newline)
>
> Should a match + ((? char-whitespace?)) predicate pattern be used here
> instead, or similar?  Or perhaps the above is faster and more
> self-contained, which can be a good thing.

ECMA-404 states that these 4 characters are the only acceptable
whitespace characters:

"Whitespace is any sequence of one or more of the following code
points: character tabulation (U+0009), line feed (U+000A), carriage
return (U+000D), and space (U+0020)."

> > +       (read-char port)
> > +       (consume-whitespace))
> > +      (else (values))))
> > +  (define-syntax-rule (define-keyword-reader name str val)
> > +    (define (name)
> > +      (if (string=3D? (get-string-n port (string-length str)) str)
> > +          val
> > +          (fail "invalid keyword"))))
> > +  (define-keyword-reader read-true "true" #t)
> > +  (define-keyword-reader read-false "false" #f)
> > +  (define-keyword-reader read-null "null" 'null)
> > +  (define (read-hex-digit)
> > +    (case (peek-char port)
> > +      ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
> > +       (- (char->integer (read-char port)) (char->integer #\0)))
> > +      ((#\a #\b #\c #\d #\e #\f)
> > +       (+ 10 (- (char->integer (read-char port)) (char->integer #\a)))=
)
> > +      ((#\A #\B #\C #\D #\E #\F)
> > +       (+ 10 (- (char->integer (read-char port)) (char->integer #\A)))=
)
> > +      (else (fail "invalid hex digit"))))
> > +  (define (read-utf16-character)
> > +    (let* ((a (read-hex-digit))
> > +           (b (read-hex-digit))
> > +           (c (read-hex-digit))
> > +           (d (read-hex-digit)))
> > +      (integer->char (+ (* a (expt 16 3)) (* b (expt 16 2)) (* c 16) d=
))))
> > +  (define (read-escape-character)
> > +    (case (read-char port)
> > +      ((#\") #\")
> > +      ((#\\) #\\)
> > +      ((#\/) #\/)
> > +      ((#\b) #\backspace)
> > +      ((#\f) #\page)
> > +      ((#\n) #\newline)
> > +      ((#\r) #\return)
> > +      ((#\t) #\tab)
> > +      ((#\u) (read-utf16-character))
> > +      (else (fail "invalid escape character"))))
> > +  (define (read-string)
> > +    (read-char port)
> > +    (list->string
> > +     (let lp ()
> > +       (match (read-char port)
> > +         ((? eof-object?) (fail "EOF while reading string"))
> > +         (#\" '())
> > +         (#\\ (cons (read-escape-character) (lp)))
> > +         (char (cons char (lp)))))))
> > +  (define (read-digit-maybe)
> > +    (case (peek-char port)
> > +      ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
> > +       (- (char->integer (read-char port))
> > +          (char->integer #\0)))
> > +      (else #f)))
> > +  (define (read-integer)
> > +    (let ((x (read-digit-maybe)))
> > +      (and x
> > +           (let lp ((x x))
> > +             (match (read-digit-maybe)
> > +               (#f x)
> > +               (y (lp (+ (* x 10) y))))))))
>
> Perhaps the above should be named read-integer-maybe, since it may
> return #f?

Yeah, good idea.

> > +  (define (read-fraction)
> > +    (case (peek-char port)
> > +      ((#\.)
> > +       (read-char port)
> > +       (let lp ((mag 10))
> > +         (let ((n (read-digit-maybe)))
> > +           (if n (+ (/ n mag) (lp (* mag 10))) 0))))
> > +      (else 0)))
>
> Should the above be named 'read-decimal' ?  Does a decimal number in
> JSON always start with '.' and not with 0. ?  I was a bit puzzled on
> what 'mag' may mean here, I guess 'magnitude' although there doesn't
> appear to have a clear terminology for it.

It's called 'read-fraction' because it reads the fractional part of
the number.  I considered 'read-decimal' but I think it's less
descriptive. This procedure is called from two places, after the
respective caller has already read the digits before the decimal
point. 'mag' does indeed mean 'magnitude', as each digit read
increases the order of magnitude of the resulting number. I borrowed
this name from Hoot's 'read' implementation, which means it's probably
in Guile's pure-Scheme 'read' implementation as well.

> > +  (define (read-exponent)
> > +    (case (peek-char port)
> > +      ((#\e #\E)
> > +       (read-char port)
> > +       (case (peek-char port)
> > +         ((#\-)
> > +          (read-char port)
> > +          (expt 10 (- (read-integer))))
> > +         ((#\+)
> > +          (read-char port)
> > +          (expt 10 (read-integer)))
> > +         (else
> > +          (expt 10 (read-integer)))))
> > +      (else 1)))
> > +  (define (read-positive-number)
> > +    (let ((n (read-integer)))
> > +      (and n
> > +           (let* ((f (read-fraction))
> > +                  (e (read-exponent))
> > +                  (x (* (+ n f) e)))
> > +             (if (exact-integer? x) x (exact->inexact x))))))
>
> This may return #f.  Should it fail instead, or be named
> read-positive-number-maybe ?

Adding 'maybe' to the name is good. It's called from two places. One
caller knows that it's not going to return #f because it has peeked a
valid digit from the port beforehand, the other does a check and fails
upon #f.

> > +  (define (read-negative-number)
> > +    (read-char port)
> > +    (let ((x (read-positive-number)))
> > +      (if x (- x) (fail "invalid number"))))
>
> Not symmetrical with the above: this one would fail if an integer
> couldn't be read in read-positive-number.

This is the intended behavior to ensure that '-' is not parsed as a
valid number.  There needs to be at least one digit.

> > +  (define (read-leading-zero-number)
> > +    (read-char port)
> > +    (case (peek-char port)
> > +      ;; Extraneous zeroes are not allowed.  A single leading zero
> > +      ;; can only be followed by a decimal point.
> > +      ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\e #\E)
> > +       (fail "extraneous leading zero"))
>
> Why not check for (not #\.) explicitly?  That'd be clearer and would
> cover all cases (even crazy unexpected ones).

The following clause checks for '.'. We need to distinguish between 3
types of input here:

- invalid extraneous zeroes like '09' (ECMA-404 says this is not allowed)
- fractional notation like '0.123'
- plain '0'

If I leave out this clause, we can no longer distinguish errors from
plain zeroes.  There's likely other ways to express it but this feels
straightforward enough.

However, it was a great idea to take another look at this code because
there is a bug! '0e3' is a valid JSON number that this code rejects.
It should parse to 0.  My updated patch fixes this and adds a test
case.

> > +      ;; Fractional number.
> > +      ((#\.)
> > +       (let* ((d (read-fraction))
> > +              (e (read-exponent)))
> > +         (exact->inexact (* d e))))
> > +      ;; Just plain zero.
> > +      (else 0)))
> > +  (define (read-key+value-pair)
> > +    (let ((key (read-string)))
> > +      (consume-whitespace)
> > +      (case (read-char port)
> > +        ((#\:)
> > +         (consume-whitespace)
> > +         (cons key (read-value)))
> > +        (else (fail "invalid key/value pair delimiter")))))
> > +  (define (read-object)
> > +    (read-char port)
> > +    (consume-whitespace)
> > +    (case (peek-char port)
> > +      ;; Empty object.
> > +      ((#\})
> > +       (read-char port)
> > +       '())
> > +      (else
> > +       ;; Read first key/value pair, then all subsequent pairs delimit=
ed
> > +       ;; by commas.
> > +       (cons (read-key+value-pair)
> > +             (let lp ()
> > +               (consume-whitespace)
> > +               (case (peek-char port)
> > +                 ((#\,)
> > +                  (read-char port)
> > +                  (consume-whitespace)
> > +                  (cons (read-key+value-pair) (lp)))
> > +                 ;; End of object.
> > +                 ((#\})
> > +                  (read-char port)
> > +                  '())
> > +                 (else (fail "invalid object delimiter"))))))))
> > +  (define (read-array)
> > +    (read-char port)
> > +    (consume-whitespace)
> > +    (case (peek-char port)
> > +      ;; Empty array.
> > +      ((#\])
> > +       (read-char port)
> > +       #())
> > +      (else
> > +       (list->vector
>
> As mentioned above, just a plain list would be more Schemey, no?  What
> does the vector type buys us?  A user wanting a vector could always call
> list->vector themselves, and otherwise we save some computation.

As stated above, vectors are the more natural analog to JSON arrays
and being distinct from pairs they resolve some ambiguity in the
Scheme representation that would exist otherwise.

> > +        ;; Read the first element, then all subsequent elements
> > +        ;; delimited by commas.
> > +        (cons (read-value)
> > +              (let lp ()
> > +                (consume-whitespace)
> > +                (case (peek-char port)
> > +                  ;; Elements are comma delimited.
> > +                  ((#\,)
> > +                   (read-char port)
> > +                   (consume-whitespace)
> > +                   (cons (read-value) (lp)))
> > +                  ;; End of array.
> > +                  ((#\])
> > +                   (read-char port)
> > +                   '())
> > +                  (else (fail "invalid array delimiter")))))))))
> > +  (define (read-value)
> > +    (consume-whitespace)
> > +    (case (peek-char port)
> > +      ((#\") (read-string))
> > +      ((#\{) (read-object))
> > +      ((#\[) (read-array))
> > +      ((#\t) (read-true))
> > +      ((#\f) (read-false))
> > +      ((#\n) (read-null))
> > +      ((#\-) (read-negative-number))
> > +      ((#\0) (read-leading-zero-number))
> > +      ((#\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) (read-positive-number))
> > +      (else (fail "invalid value"))))
> > +  (read-value))
> > +
> > +(define-exception-type &json-write-error &error
> > +  make-json-write-error
> > +  json-write-error?)
> > +
> > +(define* (write-json exp #:optional (port (current-output-port)))
> > +  "Serialize the expression @var{exp} as JSON-encoded text to @var{por=
t}.
> > +If @var{port} is unspecified, the current output port is used."
> > +  (define (fail message x)
> > +    (raise-exception
> > +     (make-exception (make-json-write-error)
> > +                     (make-exception-with-origin 'write-json)
> > +                     (make-exception-with-message message)
> > +                     (make-exception-with-irritants (list x)))))
> > +  (define (write-char/escape char)
> > +    (match char
> > +      (#\" (put-string port "\\\""))
> > +      (#\\ (put-string port "\\\\"))
> > +      (#\/ (put-string port "\\/"))
> > +      (#\backspace (put-string port "\\b"))
> > +      (#\page (put-string port "\\f"))
> > +      (#\newline (put-string port "\\n"))
> > +      (#\return (put-string port "\\r"))
> > +      (#\tab (put-string port "\\t"))
> > +      (_ (put-char port char))))
> > +  (define (write-string str)
> > +    (let ((in (open-input-string str)))
>
> Looks like the above 'in' binding is not used.

Vestigial code, my favorite. Good eye! Removed.

> > +      (put-char port #\")
> > +      (string-for-each write-char/escape str)
> > +      (put-char port #\")))
> > +  (define (write-pair x)
> > +    (match x
> > +      (((? string? key) . value)
> > +       (write-string key)
> > +       (put-char port #\:)
> > +       (write-value value))
> > +      (_ (fail "invalid key/value pair" x))))
> > +  (define (write-object obj)
> > +    (put-char port #\{)
> > +    (match obj
> > +      ((head . rest)
> > +       (write-pair head)
> > +       (let lp ((obj rest))
> > +         (match obj
> > +           (() (values))
>
> Any reason to return (values) instead of some dummy #t to denote 'no-op'
> ?.

The loop is evaluated for effect and thus there is nothing to return
so returning 0 values makes sense. This is something I picked up from
Andy Wingo.

> > +           ((head . rest)
> > +            (put-char port #\,)
> > +            (write-pair head)
> > +            (lp rest))
> > +           (_ (fail "invalid object" obj))))))
> > +    (put-char port #\}))
> > +  (define (write-array v)
> > +    (put-char port #\[)
> > +    (match (vector-length v)
> > +      (0 (values))
> > +      (n
> > +       (write-value (vector-ref v 0))
> > +       (do ((i 1 (1+ i)))
> > +           ((=3D i n))
> > +         (put-char port #\,)
> > +         (write-value (vector-ref v i)))))
>
> I suppose the above is more efficient than a for-each loop?  I'd be
> curious to see it profiled, if you still have data.  At least now I see
> than for > 100k, vector-ref is faster than list-ref, which probably
> explains why you went with vectors (could still be an implementation
> detail with the list->vector call left in the writer though, in my
> opinion).

Yes, it is more efficient because it avoids closure allocation. Also,
I just don't see any reason to import (rnrs base) or (srfi srfi-43) to
get vector-for-each when looping over a vector is trivial. I didn't
profile anything.

> > +    (put-char port #\]))
> > +  (define (write-number x)
> > +    (if (or (exact-integer? x)
> > +            (and (real? x)
> > +                 (inexact? x)
> > +                 ;; NaNs and infinities are not allowed.
> > +                 (not (or (nan? x) (inf? x)))))
> > +        ;; Scheme's string representations of exact integers and float=
s
> > +        ;; are compatible with JSON.
> > +        (put-string port (number->string x))
> > +        (fail "invalid number" x)))
> > +  (define (write-value x)
> > +    (match x
> > +      (#t (put-string port "true"))
> > +      (#f (put-string port "false"))
> > +      ('null (put-string port "null"))
> > +      (() (put-string port "{}"))
> > +      ((? pair?) (write-object x))
> > +      ((? vector?) (write-array x))
> > +      ((? string?) (write-string x))
> > +      ((? number?) (write-number x))
> > +      (_ (fail "invalid value" x))))
> > +  (write-value exp))
>
> Phew.  That's a pretty low-level parser!  I hope it's fast, otherwise it
> seems it'd be more concise/fun/maintainable to devise a PEG-based one,
> which appears to be doable for JSON, from what I've read.  Perhaps
> sprinkle with a few performance-related comments where such concerns
> impacted the design choices, so that we can remember and retest/reverify
> these in the future when Guile evolves.

JSON is a pretty simple format and thus I think a hand-rolled parser
is appropriate.  It's much simpler than 'read', anyway.  I suppose it
would be more concise, but "PEG parser" and "fun" do not go together
for me.  At ~300 lines of quite simple code (I did not go hog wild on
macros or fancy abstractions nor did I sacrifice readable code for
performance) I don't think there is much concern regarding
maintenance.  If someone wants to experiment to see how a PEG parser
compares, though, feel free.

> > diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
> > index 6014b1f1f..00afea142 100644
> > --- a/test-suite/Makefile.am
> > +++ b/test-suite/Makefile.am
> > @@ -73,6 +73,7 @@ SCM_TESTS =3D tests/00-initial-env.test              =
 \
> >           tests/iconv.test                    \
> >           tests/import.test                   \
> >           tests/interp.test                   \
> > +         tests/json.test                     \
> >           tests/keywords.test                 \
> >           tests/list.test                     \
> >           tests/load.test                     \
> > diff --git a/test-suite/tests/json.test b/test-suite/tests/json.test
> > new file mode 100644
> > index 000000000..f92eeccec
> > --- /dev/null
> > +++ b/test-suite/tests/json.test
> > @@ -0,0 +1,154 @@
> > +;;;; json.test --- test JSON reader/writer     -*- scheme -*-
> > +;;;;
> > +;;;; Copyright (C) 2015 Free Software Foundation, Inc.
> > +;;;;
> > +;;;; This library is free software; you can redistribute it and/or
> > +;;;; modify it under the terms of the GNU Lesser General Public
> > +;;;; License as published by the Free Software Foundation; either
> > +;;;; version 3 of the License, or (at your option) any later version.
> > +;;;;
> > +;;;; This library is distributed in the hope that it will be useful,
> > +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > +;;;; Lesser General Public License for more details.
> > +;;;;
> > +;;;; You should have received a copy of the GNU Lesser General Public
> > +;;;; License along with this library; if not, write to the Free Softwa=
re
> > +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 021=
10-1301 USA
> > +
> > +(define-module (test-suite test-json)
> > +  #:use-module (test-suite lib)
> > +  #:use-module (web json))
> > +
> > +;;;
> > +;;; Reader
> > +;;;
> > +
> > +(define (read-json-string str)
> > +  (call-with-input-string str read-json))
> > +
> > +(define (json-read=3D? str x)
> > +  (=3D x (read-json-string str)))
> > +
> > +(define (json-read-eq? str x)
> > +  (eq? x (read-json-string str)))
> > +
> > +(define (json-read-equal? str x)
> > +  (equal? x (read-json-string str)))
> > +
> > +(define (json-read-string=3D? str x)
> > +  (string=3D? x (read-json-string str)))
> > +
> > +(with-test-prefix "read-json"
> > +  ;; Keywords
> > +  (pass-if (json-read-eq? "true" #t))
> > +  (pass-if (json-read-eq? "false" #f))
> > +  (pass-if (json-read-eq? "null" 'null))
> > +  ;; Numbers
> > +  (pass-if (json-read=3D? "0" 0))
> > +  (pass-if (json-read=3D? "-0" 0))
> > +  (pass-if (json-read=3D? "0.0" 0.0))
> > +  (pass-if (json-read=3D? "-0.0" -0.0))
> > +  (pass-if (json-read=3D? "0.1" 0.1))
> > +  (pass-if (json-read=3D? "1.234" 1.234))
> > +  (pass-if (json-read=3D? "1" 1))
> > +  (pass-if (json-read=3D? "-1" -1))
> > +  (pass-if (json-read=3D? "1.1" 1.1))
> > +  (pass-if (json-read=3D? "1e2" 1e2))
> > +  (pass-if (json-read=3D? "1.1e2" 1.1e2))
> > +  (pass-if (json-read=3D? "1.1e-2" 1.1e-2))
> > +  (pass-if (json-read=3D? "1.1e+2" 1.1e2))
> > +  ;; Extraneous zeroes in fraction
> > +  (pass-if (json-read=3D? "1.000" 1))
> > +  (pass-if (json-read=3D? "1.5000" 1.5))
> > +  ;; Extraneous zeroes in exponent
> > +  (pass-if (json-read=3D? "1.1e000" 1.1))
> > +  (pass-if (json-read=3D? "1.1e-02" 1.1e-2))
> > +  (pass-if (json-read=3D? "1.1e+02" 1.1e2))
> > +  ;; Strings
> > +  (pass-if (json-read-string=3D? "\"foo\"" "foo"))
> > +  ;; Escape codes
> > +  (pass-if (json-read-string=3D? "\"\\\"\"" "\""))
> > +  (pass-if (json-read-string=3D? "\"\\\\\"" "\\"))
> > +  (pass-if (json-read-string=3D? "\"\\/\"" "/"))
> > +  (pass-if (json-read-string=3D? "\"\\b\"" "\b"))
> > +  (pass-if (json-read-string=3D? "\"\\f\"" "\f"))
> > +  (pass-if (json-read-string=3D? "\"\\n\"" "\n"))
> > +  (pass-if (json-read-string=3D? "\"\\r\"" "\r"))
> > +  (pass-if (json-read-string=3D? "\"\\t\"" "\t"))
> > +  ;; Unicode in hexadecimal format
> > +  (pass-if (json-read-string=3D? "\"\\u12ab\"" "\u12ab"))
> > +  ;; Objects
> > +  (pass-if (json-read-equal? "{}" '()))
> > +  (pass-if (json-read-equal? "{ \"foo\": \"bar\", \"baz\": \"frob\"}"
> > +                             '(("foo" . "bar") ("baz" . "frob"))))
> > +  ;; Nested objects
> > +  (pass-if (json-read-equal? "{\"foo\":{\"bar\":\"baz\"}}"
> > +                             '(("foo" . (("bar" . "baz"))))))
> > +  ;; Arrays
> > +  (pass-if (json-read-equal? "[]" #()))
> > +  (pass-if (json-read-equal? "[1, 2, \"foo\"]"
> > +                             #(1 2 "foo")))
> > +  ;; Nested arrays
> > +  (pass-if (json-read-equal? "[1, 2, [\"foo\", \"bar\"]]"
> > +                             #(1 2 #("foo" "bar"))))
> > +  ;; Arrays and objects nested within each other
> > +  (pass-if (json-read-equal? "{\"foo\":[{\"bar\":true},{\"baz\":[1,2,3=
]}]}"
> > +                             '(("foo" . #((("bar" . #t))
> > +                                          (("baz" . #(1 2 3))))))))
> > +  ;; Leading whitespace
> > +  (pass-if (json-read-eq? "\t\r\n true" #t)))
>
> > +;;;
> > +;;; Writer
> > +;;;
> > +
> > +(define (write-json-string exp)
> > +  (call-with-output-string
> > +   (lambda (port)
> > +     (write-json exp port))))
> > +
> > +(define (json-write-string=3D? exp str)
> > +  (string=3D? str (write-json-string exp)))
> > +
> > +(with-test-prefix "write-json"
> > +  ;; Keywords
> > +  (pass-if (json-write-string=3D? #t "true"))
> > +  (pass-if (json-write-string=3D? #f "false"))
> > +  (pass-if (json-write-string=3D? 'null "null"))
> > +  ;; Numbers
> > +  (pass-if (json-write-string=3D? 0 "0"))
> > +  (pass-if (json-write-string=3D? 0.0 "0.0"))
> > +  (pass-if (json-write-string=3D? 0.1 "0.1"))
> > +  (pass-if (json-write-string=3D? 1 "1"))
> > +  (pass-if (json-write-string=3D? -1 "-1"))
> > +  (pass-if (json-write-string=3D? 1.1 "1.1"))
> > +  ;; Strings
> > +  (pass-if (json-write-string=3D? "foo" "\"foo\""))
> > +  ;; Escape codes
> > +  (pass-if (json-write-string=3D? "\"" "\"\\\"\""))
> > +  (pass-if (json-write-string=3D? "\\" "\"\\\\\""))
> > +  (pass-if (json-write-string=3D? "/" "\"\\/\""))
> > +  (pass-if (json-write-string=3D? "\b" "\"\\b\""))
> > +  (pass-if (json-write-string=3D? "\f" "\"\\f\""))
> > +  (pass-if (json-write-string=3D? "\n" "\"\\n\""))
> > +  (pass-if (json-write-string=3D? "\r" "\"\\r\""))
> > +  (pass-if (json-write-string=3D? "\t" "\"\\t\""))
> > +  ;; Objects
> > +  (pass-if (json-write-string=3D? '() "{}"))
> > +  (pass-if (json-write-string=3D? '(("foo" . "bar") ("baz" . "frob"))
> > +                                "{\"foo\":\"bar\",\"baz\":\"frob\"}"))
> > +  ;; Nested objects
> > +  (pass-if (json-write-string=3D? '(("foo" . (("bar" . "baz"))))
> > +                                "{\"foo\":{\"bar\":\"baz\"}}"))
> > +  ;; Arrays
> > +  (pass-if (json-write-string=3D? #() "[]"))
> > +  (pass-if (json-write-string=3D? #(1 2 "foo")
> > +                                "[1,2,\"foo\"]"))
> > +  ;; Nested arrays
> > +  (pass-if (json-write-string=3D? #(1 2 #("foo" "bar"))
> > +                                "[1,2,[\"foo\",\"bar\"]]"))
> > +  ;; Arrays and objects nested in each other
> > +  (pass-if (json-write-string=3D? '(("foo" . #((("bar" . #t))
> > +                                             (("baz" . #(1 2))))))
> > +                                "{\"foo\":[{\"bar\":true},{\"baz\":[1,=
2]}]}")))
>
> Neat.  Nitpick: perhaps add a trailing '.' after each stand-alone
> comments, to follow existing conventions.

Sure thing.

> I hope my armchair commentary is of some use :-).

It was! Always nice to have another pair of eyes on some code you've
stared at for too long to notice all the little issues that remain.
Thank you!

> Thanks again for working on a JSON parser/writer for Guile.

:)

Updated patch attached.

- Dave

--0000000000006c2d480632bc057b
Content-Type: text/x-patch; charset="US-ASCII"; name="0001-web-Add-JSON-module.patch"
Content-Disposition: attachment; filename="0001-web-Add-JSON-module.patch"
Content-Transfer-Encoding: base64
Content-ID: <f_m9h14j210>
X-Attachment-Id: f_m9h14j210

RnJvbSBiMDU1MWVhMGY3NWVlYTIxZDQ0ZmQxZmIzYjhiZjYzYTM2ZGZjYmE0IE1vbiBTZXAgMTcg
MDA6MDA6MDAgMjAwMQpGcm9tOiBEYXZpZCBUaG9tcHNvbiA8ZHRob21wc29uMkB3b3JjZXN0ZXIu
ZWR1PgpEYXRlOiBTYXQsIDEyIEFwciAyMDI1IDA4OjI3OjM1IC0wNDAwClN1YmplY3Q6IFtQQVRD
SF0gd2ViOiBBZGQgSlNPTiBtb2R1bGUuCgoqIG1vZHVsZS93ZWIvanNvbi5zY206IE5ldyBmaWxl
LgoqIGFtL2Jvb3RzdHJhcC5hbSAoU09VUkNFUyk6IEFkZCBpdC4KKiB0ZXN0LXN1aXRlL3Rlc3Rz
L2pzb24udGVzdDogTmV3IGZpbGUuCiogdGVzdC1zdWl0ZS9NYWtlZmlsZS5hbSAoU0NNX1RFU1RT
KTogQWRkIGl0LgoqIGRvYy9yZWYvd2ViLnRleGkgKCJKU09OIik6IE5ldyBzdWJzZWN0aW9uLgot
LS0KIGFtL2Jvb3RzdHJhcC5hbSAgICAgICAgICAgIHwgICAzICstCiBkb2MvcmVmL3dlYi50ZXhp
ICAgICAgICAgICB8ICA5NSArKysrKysrKysrKysKIG1vZHVsZS93ZWIvanNvbi5zY20gICAgICAg
IHwgMzA5ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIHRlc3Qtc3VpdGUv
TWFrZWZpbGUuYW0gICAgIHwgICAxICsKIHRlc3Qtc3VpdGUvdGVzdHMvanNvbi50ZXN0IHwgMTU1
ICsrKysrKysrKysrKysrKysrKysKIDUgZmlsZXMgY2hhbmdlZCwgNTYyIGluc2VydGlvbnMoKyks
IDEgZGVsZXRpb24oLSkKIGNyZWF0ZSBtb2RlIDEwMDY0NCBtb2R1bGUvd2ViL2pzb24uc2NtCiBj
cmVhdGUgbW9kZSAxMDA2NDQgdGVzdC1zdWl0ZS90ZXN0cy9qc29uLnRlc3QKCmRpZmYgLS1naXQg
YS9hbS9ib290c3RyYXAuYW0gYi9hbS9ib290c3RyYXAuYW0KaW5kZXggOTYwMjNkODNkLi42ODA2
ZmRhNWQgMTAwNjQ0Ci0tLSBhL2FtL2Jvb3RzdHJhcC5hbQorKysgYi9hbS9ib290c3RyYXAuYW0K
QEAgLTQyNSw3ICs0MjUsOCBAQCBTT1VSQ0VTID0JCQkJCVwKICAgd2ViL3Jlc3BvbnNlLnNjbQkJ
CQlcCiAgIHdlYi9zZXJ2ZXIuc2NtCQkJCVwKICAgd2ViL3NlcnZlci9odHRwLnNjbQkJCQlcCi0g
IHdlYi91cmkuc2NtCisgIHdlYi91cmkuc2NtCQkJCQlcCisgIHdlYi9qc29uLnNjbQogCiBFTElT
UF9TT1VSQ0VTID0JCQkJCVwKICAgbGFuZ3VhZ2UvZWxpc3AvYm9vdC5lbApkaWZmIC0tZ2l0IGEv
ZG9jL3JlZi93ZWIudGV4aSBiL2RvYy9yZWYvd2ViLnRleGkKaW5kZXggNjA3Yzg1NWI2Li4wNWY2
MWRmY2IgMTAwNjQ0Ci0tLSBhL2RvYy9yZWYvd2ViLnRleGkKKysrIGIvZG9jL3JlZi93ZWIudGV4
aQpAQCAtNDAsNiArNDAsNyBAQCBiYWNrLgogKiBUcmFuc2ZlciBDb2RpbmdzOjogICAgICAgICAg
ICBIVFRQIFRyYW5zZmVyIENvZGluZ3MuCiAqIFJlcXVlc3RzOjogICAgICAgICAgICAgICAgICAg
IEhUVFAgcmVxdWVzdHMuCiAqIFJlc3BvbnNlczo6ICAgICAgICAgICAgICAgICAgIEhUVFAgcmVz
cG9uc2VzLgorKiBKU09OOjogICAgICAgICAgICAgICAgICAgICAgICBUaGUgSmF2YVNjcmlwdCBP
YmplY3QgTm90YXRpb24uCiAqIFdlYiBDbGllbnQ6OiAgICAgICAgICAgICAgICAgIEFjY2Vzc2lu
ZyB3ZWIgcmVzb3VyY2VzIG92ZXIgSFRUUC4KICogV2ViIFNlcnZlcjo6ICAgICAgICAgICAgICAg
ICAgU2VydmluZyBIVFRQIHRvIHRoZSBpbnRlcm5ldC4KICogV2ViIEV4YW1wbGVzOjogICAgICAg
ICAgICAgICAgSG93IHRvIHVzZSB0aGlzIHRoaW5nLgpAQCAtMTQ0OCw2ICsxNDQ5LDEwMCBAQCBS
ZXR1cm4gQGNvZGV7I3R9IGlmIEB2YXJ7dHlwZX0sIGEgc3ltYm9sIGFzIHJldHVybmVkIGJ5CiBA
ZW5kIGRlZmZuCiAKIAorQG5vZGUgSlNPTgorQHN1YnNlY3Rpb24gSlNPTgorCitAY2luZGV4IGpz
b24KK0BjaW5kZXggKHdlYiBqc29uKQorCitAZXhhbXBsZQorKHVzZS1tb2R1bGVzICh3ZWIganNv
bikpCitAZW5kIGV4YW1wbGUKKworSmF2YVNjcmlwdCBPYmplY3QgTm90YXRpb24gKEpTT04pIGlz
IHRoZSBtb3N0IGNvbW1vbiBkYXRhIGludGVyY2hhbmdlCitmb3JtYXQgb24gdGhlIHdlYi4gIEl0
IGlzIHViaXF1aXRvdXMgaW4gSFRUUCBBUElzIGFuZCBoYXMgZm91bmQgaXRzIHdheQoraW50byBt
YW55IG90aGVyIGRvbWFpbnMgYmV5b25kIHRoZSB3ZWIsIGFzIHdlbGwuICBUaGUgQGNvZGV7KHdl
YiBqc29uKX0KK21vZHVsZSBtYWtlcyBpdCBwb3NzaWJsZSB0byBjb252ZXJ0IGEgc3Vic2V0IG9m
IFNjaGVtZSBkYXRhIHR5cGVzIHRvCitKU09OIHRleHQgYW5kIHZpY2UgdmVyc2EuICBGb3IgZXhh
bXBsZSwgdGhlIEpTT04gZG9jdW1lbnQ6CisKK0BleGFtcGxlCitAdmVyYmF0aW0KK3sKKyAgIm5h
bWUiOiAiRXZhIEx1YXRvciIsCisgICJhZ2UiOiAzNCwKKyAgInNjaGVtZXIiOiB0cnVlLAorICAi
aG9iYmllcyI6IFsKKyAgICAiaGFja2luZyIsCisgICAgImN5Y2xpbmciLAorICAgICJzdXJmaW5n
IgorICBdCit9CitAZW5kIHZlcmJhdGltCitAZW5kIGV4YW1wbGUKKworY2FuIGJlIHJlcHJlc2Vu
dGVkIHdpdGggdGhlIGZvbGxvd2luZyBTY2hlbWUgZXhwcmVzc2lvbjoKKworQGV4YW1wbGUKK0B2
ZXJiYXRpbQorJygoIm5hbWUiIC4gIkV2YSBMdWF0b3IiKQorICAoImFnZSIgLiAzNCkKKyAgKCJz
Y2hlbWVyIiAuICN0KQorICAoImhvYmJpZXMiIC4gIygiaGFja2luZyIgImN5Y2xpbmciICJzdXJm
aW5nIikpKQorQGVuZCB2ZXJiYXRpbQorQGVuZCBleGFtcGxlCisKK1N0cmluZ3MsIGV4YWN0IGlu
dGVnZXJzLCBpbmV4YWN0IHJlYWxzIChleGNsdWRpbmcgTmFOcyBhbmQgaW5maW5pdGllcyksCitA
Y29kZXsjdH0sIEBjb2RleyNmfSwgdGhlIHN5bWJvbCBAY29kZXtudWxsfSwgdmVjdG9ycywgYW5k
IGFzc29jaWF0aW9uCitsaXN0cyBtYXkgYmUgc2VyaWFsaXplZCBhcyBKU09OLiAgQXNzb2NpYXRp
b24gbGlzdHMgc2VyaWFsaXplIGFzIEpTT04KK29iamVjdHMgYW5kIHZlY3RvcnMgc2VyaWFsaXpl
IGFzIEpTT04gYXJyYXlzLiAgVGhlIGtleXMgb2YgYXNzb2NpYXRpb24KK2xpc3RzIEBlbXBoe211
c3R9IGJlIHN0cmluZ3MuCisKK0BkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gcmVhZC1qc29uIFtw
b3J0XQorCitQYXJzZSBhIEpTT04tZW5jb2RlZCB2YWx1ZSBmcm9tIEB2YXJ7cG9ydH0gYW5kIHJl
dHVybiBpdHMgU2NoZW1lCityZXByZXNlbnRhdGlvbi4gIElmIEB2YXJ7cG9ydH0gaXMgdW5zcGVj
aWZpZWQsIHRoZSBjdXJyZW50IGlucHV0IHBvcnQgaXMKK3VzZWQuICBVcG9uIGVycm9yLCBhbiBl
eGNlcHRpb24gb2YgdHlwZSBAY29kZXsmanNvbi1yZWFkLWVycm9yfSBpcworcmFpc2VkLgorCitA
ZXhhbXBsZQorQHZlcmJhdGltCisoY2FsbC13aXRoLWlucHV0LXN0cmluZyAiW3RydWUsZmFsc2Us
bnVsbCw0MixcImZvb1wiXSIgcmVhZC1qc29uKQorOzsgPT4gIygjdCAjZiBudWxsIDQyICJmb28i
KQorCisoY2FsbC13aXRoLWlucHV0LXN0cmluZyAie1wiZm9vXCI6MSxcImJhclwiOjJ9IiByZWFk
LWpzb24pCis7OyA9PiAoKCJmb28iIC4gMSkgKCJiYXIiIC4gMikpCitAZW5kIHZlcmJhdGltCitA
ZW5kIGV4YW1wbGUKKworQGVuZCBkZWZmbgorCitAZGVmdHAge0V4Y2VwdGlvbiBUeXBlfSAmanNv
bi1yZWFkLWVycm9yCitBbiBleGNlcHRpb24gdHlwZSBkZW5vdGluZyBKU09OIHJlYWQgZXJyb3Jz
LgorQGVuZCBkZWZ0cAorCitAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHdyaXRlLWpzb24gZXhw
IFtwb3J0XQorCitTZXJpYWxpemUgdGhlIGV4cHJlc3Npb24gQHZhcntleHB9IGFzIEpTT04tZW5j
b2RlZCB0ZXh0IHRvIEB2YXJ7cG9ydH0uCitJZiBAdmFye3BvcnR9IGlzIHVuc3BlY2lmaWVkLCB0
aGUgY3VycmVudCBvdXRwdXQgcG9ydCBpcyB1c2VkLiAgVXBvbgorZXJyb3IsIGFuIGV4Y2VwdGlv
biBvZiB0eXBlIEBjb2RleyZqc29uLXdyaXRlLWVycm9yfSBpcyByYWlzZWQuCisKK0BleGFtcGxl
CitAdmVyYmF0aW0KKyh3aXRoLW91dHB1dC10by1zdHJpbmcgKGxhbWJkYSAoKSAod3JpdGUtanNv
biAjKCN0ICNmIG51bGwgNDIgImZvbyIpKSkpCis7OyA9PiAiW3RydWUsZmFsc2UsbnVsbCw0Mixc
ImZvb1wiXSIKKworKHdpdGgtb3V0cHV0LXRvLXN0cmluZyAobGFtYmRhICgpICh3cml0ZS1qc29u
ICcoKCJmb28iIC4gMSkgKCJiYXIiIC4gMikpKSkpCis7OyA9PiAie1wiZm9vXCI6MSxcImJhclwi
OjJ9IgorQGVuZCB2ZXJiYXRpbQorQGVuZCBleGFtcGxlCisKK0BlbmQgZGVmZm4KKworQGRlZnRw
IHtFeGNlcHRpb24gVHlwZX0gJmpzb24td3JpdGUtZXJyb3IKK0FuIGV4Y2VwdGlvbiB0eXBlIGRl
bm90aW5nIEpTT04gd3JpdGUgZXJyb3JzLgorQGVuZCBkZWZ0cAorCisKIEBub2RlIFdlYiBDbGll
bnQKIEBzdWJzZWN0aW9uIFdlYiBDbGllbnQKIApkaWZmIC0tZ2l0IGEvbW9kdWxlL3dlYi9qc29u
LnNjbSBiL21vZHVsZS93ZWIvanNvbi5zY20KbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAw
MDAwMDAwLi5hMmI1MDE5NzEKLS0tIC9kZXYvbnVsbAorKysgYi9tb2R1bGUvd2ViL2pzb24uc2Nt
CkBAIC0wLDAgKzEsMzA5IEBACis7Ozs7IGpzb24uc2NtIC0tLSBKU09OIHJlYWRlci93cml0ZXIg
KEVDTUEtNDA0KQorOzs7OyBDb3B5cmlnaHQgKEMpIDIwMjUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0
aW9uLCBJbmMuCis7Ozs7Cis7Ozs7IFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3Ug
Y2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IKKzs7OzsgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJt
cyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYworOzs7OyBMaWNlbnNlIGFzIHB1Ymxp
c2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXIKKzs7OzsgdmVyc2lv
biAzIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9u
LgorOzs7OworOzs7OyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhh
dCBpdCB3aWxsIGJlIHVzZWZ1bCwKKzs7OzsgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRo
b3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKKzs7OzsgTUVSQ0hBTlRBQklMSVRZIG9y
IEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUKKzs7OzsgTGVz
c2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KKzs7OzsKKzs7Ozsg
WW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFs
IFB1YmxpYworOzs7OyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIElm
IG5vdCwgc2VlCis7Ozs7IDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uCisKKyhkZWZp
bmUtbW9kdWxlICh3ZWIganNvbikKKyAgIzp1c2UtbW9kdWxlIChpY2UtOSBleGNlcHRpb25zKQor
ICAjOnVzZS1tb2R1bGUgKGljZS05IG1hdGNoKQorICAjOnVzZS1tb2R1bGUgKGljZS05IHRleHR1
YWwtcG9ydHMpCisgICM6ZXhwb3J0ICgmanNvbi1yZWFkLWVycm9yCisgICAgICAgICAgICByZWFk
LWpzb24KKworICAgICAgICAgICAgJmpzb24td3JpdGUtZXJyb3IKKyAgICAgICAgICAgIHdyaXRl
LWpzb24pKQorCisoZGVmaW5lLWV4Y2VwdGlvbi10eXBlICZqc29uLXJlYWQtZXJyb3IgJmVycm9y
CisgIG1ha2UtanNvbi1yZWFkLWVycm9yCisgIGpzb24tcmVhZC1lcnJvcj8pCisKKyhkZWZpbmUq
IChyZWFkLWpzb24gIzpvcHRpb25hbCAocG9ydCAoY3VycmVudC1pbnB1dC1wb3J0KSkpCisgICJQ
YXJzZSBhIEpTT04tZW5jb2RlZCB2YWx1ZSBmcm9tIEB2YXJ7cG9ydH0gYW5kIHJldHVybiBpdHMg
U2NoZW1lCityZXByZXNlbnRhdGlvbi4gIElmIEB2YXJ7cG9ydH0gaXMgdW5zcGVjaWZpZWQsIHRo
ZSBjdXJyZW50IGlucHV0IHBvcnQgaXMKK3VzZWQuIgorICAoZGVmaW5lIChmYWlsIG1lc3NhZ2Up
CisgICAgKHJhaXNlLWV4Y2VwdGlvbgorICAgICAobWFrZS1leGNlcHRpb24gKG1ha2UtanNvbi1y
ZWFkLWVycm9yKQorICAgICAgICAgICAgICAgICAgICAgKG1ha2UtZXhjZXB0aW9uLXdpdGgtb3Jp
Z2luICdyZWFkLWpzb24pCisgICAgICAgICAgICAgICAgICAgICAobWFrZS1leGNlcHRpb24td2l0
aC1tZXNzYWdlIG1lc3NhZ2UpCisgICAgICAgICAgICAgICAgICAgICAobWFrZS1leGNlcHRpb24t
d2l0aC1pcnJpdGFudHMgKGxpc3QgcG9ydCkpKSkpCisgIChkZWZpbmUgKGNvbnN1bWUtd2hpdGVz
cGFjZSkKKyAgICAoY2FzZSAocGVlay1jaGFyIHBvcnQpCisgICAgICAoKCNcc3BhY2UgI1x0YWIg
I1xyZXR1cm4gI1xuZXdsaW5lKQorICAgICAgIChyZWFkLWNoYXIgcG9ydCkKKyAgICAgICAoY29u
c3VtZS13aGl0ZXNwYWNlKSkKKyAgICAgIChlbHNlICh2YWx1ZXMpKSkpCisgIChkZWZpbmUtc3lu
dGF4LXJ1bGUgKGRlZmluZS1rZXl3b3JkLXJlYWRlciBuYW1lIHN0ciB2YWwpCisgICAgKGRlZmlu
ZSAobmFtZSkKKyAgICAgIChpZiAoc3RyaW5nPT8gKGdldC1zdHJpbmctbiBwb3J0IChzdHJpbmct
bGVuZ3RoIHN0cikpIHN0cikKKyAgICAgICAgICB2YWwKKyAgICAgICAgICAoZmFpbCAiaW52YWxp
ZCBrZXl3b3JkIikpKSkKKyAgKGRlZmluZS1rZXl3b3JkLXJlYWRlciByZWFkLXRydWUgInRydWUi
ICN0KQorICAoZGVmaW5lLWtleXdvcmQtcmVhZGVyIHJlYWQtZmFsc2UgImZhbHNlIiAjZikKKyAg
KGRlZmluZS1rZXl3b3JkLXJlYWRlciByZWFkLW51bGwgIm51bGwiICdudWxsKQorICAoZGVmaW5l
IChyZWFkLWhleC1kaWdpdCkKKyAgICAoY2FzZSAocGVlay1jaGFyIHBvcnQpCisgICAgICAoKCNc
MCAjXDEgI1wyICNcMyAjXDQgI1w1ICNcNiAjXDcgI1w4ICNcOSkKKyAgICAgICAoLSAoY2hhci0+
aW50ZWdlciAocmVhZC1jaGFyIHBvcnQpKSAoY2hhci0+aW50ZWdlciAjXDApKSkKKyAgICAgICgo
I1xhICNcYiAjXGMgI1xkICNcZSAjXGYpCisgICAgICAgKCsgMTAgKC0gKGNoYXItPmludGVnZXIg
KHJlYWQtY2hhciBwb3J0KSkgKGNoYXItPmludGVnZXIgI1xhKSkpKQorICAgICAgKCgjXEEgI1xC
ICNcQyAjXEQgI1xFICNcRikKKyAgICAgICAoKyAxMCAoLSAoY2hhci0+aW50ZWdlciAocmVhZC1j
aGFyIHBvcnQpKSAoY2hhci0+aW50ZWdlciAjXEEpKSkpCisgICAgICAoZWxzZSAoZmFpbCAiaW52
YWxpZCBoZXggZGlnaXQiKSkpKQorICAoZGVmaW5lIChyZWFkLXV0ZjE2LWNoYXJhY3RlcikKKyAg
ICAobGV0KiAoKGEgKHJlYWQtaGV4LWRpZ2l0KSkKKyAgICAgICAgICAgKGIgKHJlYWQtaGV4LWRp
Z2l0KSkKKyAgICAgICAgICAgKGMgKHJlYWQtaGV4LWRpZ2l0KSkKKyAgICAgICAgICAgKGQgKHJl
YWQtaGV4LWRpZ2l0KSkpCisgICAgICAoaW50ZWdlci0+Y2hhciAoKyAoKiBhIChleHB0IDE2IDMp
KSAoKiBiIChleHB0IDE2IDIpKSAoKiBjIDE2KSBkKSkpKQorICAoZGVmaW5lIChyZWFkLWVzY2Fw
ZS1jaGFyYWN0ZXIpCisgICAgKGNhc2UgKHJlYWQtY2hhciBwb3J0KQorICAgICAgKCgjXCIpICNc
IikKKyAgICAgICgoI1xcKSAjXFwpCisgICAgICAoKCNcLykgI1wvKQorICAgICAgKCgjXGIpICNc
YmFja3NwYWNlKQorICAgICAgKCgjXGYpICNccGFnZSkKKyAgICAgICgoI1xuKSAjXG5ld2xpbmUp
CisgICAgICAoKCNccikgI1xyZXR1cm4pCisgICAgICAoKCNcdCkgI1x0YWIpCisgICAgICAoKCNc
dSkgKHJlYWQtdXRmMTYtY2hhcmFjdGVyKSkKKyAgICAgIChlbHNlIChmYWlsICJpbnZhbGlkIGVz
Y2FwZSBjaGFyYWN0ZXIiKSkpKQorICAoZGVmaW5lIChyZWFkLXN0cmluZykKKyAgICAocmVhZC1j
aGFyIHBvcnQpCisgICAgKGxpc3QtPnN0cmluZworICAgICAobGV0IGxwICgpCisgICAgICAgKG1h
dGNoIChyZWFkLWNoYXIgcG9ydCkKKyAgICAgICAgICgoPyBlb2Ytb2JqZWN0PykgKGZhaWwgIkVP
RiB3aGlsZSByZWFkaW5nIHN0cmluZyIpKQorICAgICAgICAgKCNcIiAnKCkpCisgICAgICAgICAo
I1xcIChjb25zIChyZWFkLWVzY2FwZS1jaGFyYWN0ZXIpIChscCkpKQorICAgICAgICAgKGNoYXIg
KGNvbnMgY2hhciAobHApKSkpKSkpCisgIChkZWZpbmUgKHJlYWQtZGlnaXQtbWF5YmUpCisgICAg
KGNhc2UgKHBlZWstY2hhciBwb3J0KQorICAgICAgKCgjXDAgI1wxICNcMiAjXDMgI1w0ICNcNSAj
XDYgI1w3ICNcOCAjXDkpCisgICAgICAgKC0gKGNoYXItPmludGVnZXIgKHJlYWQtY2hhciBwb3J0
KSkKKyAgICAgICAgICAoY2hhci0+aW50ZWdlciAjXDApKSkKKyAgICAgIChlbHNlICNmKSkpCisg
IChkZWZpbmUgKHJlYWQtaW50ZWdlci1tYXliZSkKKyAgICAobGV0ICgoeCAocmVhZC1kaWdpdC1t
YXliZSkpKQorICAgICAgKGFuZCB4CisgICAgICAgICAgIChsZXQgbHAgKCh4IHgpKQorICAgICAg
ICAgICAgIChtYXRjaCAocmVhZC1kaWdpdC1tYXliZSkKKyAgICAgICAgICAgICAgICgjZiB4KQor
ICAgICAgICAgICAgICAgKHkgKGxwICgrICgqIHggMTApIHkpKSkpKSkpKQorICAoZGVmaW5lIChy
ZWFkLWZyYWN0aW9uKQorICAgIChjYXNlIChwZWVrLWNoYXIgcG9ydCkKKyAgICAgICgoI1wuKQor
ICAgICAgIChyZWFkLWNoYXIgcG9ydCkKKyAgICAgICAobGV0IGxwICgobWFnIDEwKSkKKyAgICAg
ICAgIChsZXQgKChuIChyZWFkLWRpZ2l0LW1heWJlKSkpCisgICAgICAgICAgIChpZiBuICgrICgv
IG4gbWFnKSAobHAgKCogbWFnIDEwKSkpIDApKSkpCisgICAgICAoZWxzZSAwKSkpCisgIChkZWZp
bmUgKHJlYWQtZXhwb25lbnQpCisgICAgKGNhc2UgKHBlZWstY2hhciBwb3J0KQorICAgICAgKCgj
XGUgI1xFKQorICAgICAgIChyZWFkLWNoYXIgcG9ydCkKKyAgICAgICAoY2FzZSAocGVlay1jaGFy
IHBvcnQpCisgICAgICAgICAoKCNcLSkKKyAgICAgICAgICAocmVhZC1jaGFyIHBvcnQpCisgICAg
ICAgICAgKGV4cHQgMTAgKC0gKHJlYWQtaW50ZWdlci1tYXliZSkpKSkKKyAgICAgICAgICgoI1wr
KQorICAgICAgICAgIChyZWFkLWNoYXIgcG9ydCkKKyAgICAgICAgICAoZXhwdCAxMCAocmVhZC1p
bnRlZ2VyLW1heWJlKSkpCisgICAgICAgICAoZWxzZQorICAgICAgICAgIChleHB0IDEwIChyZWFk
LWludGVnZXItbWF5YmUpKSkpKQorICAgICAgKGVsc2UgMSkpKQorICAoZGVmaW5lIChyZWFkLXBv
c2l0aXZlLW51bWJlci1tYXliZSkKKyAgICAobGV0ICgobiAocmVhZC1pbnRlZ2VyLW1heWJlKSkp
CisgICAgICAoYW5kIG4KKyAgICAgICAgICAgKGxldCogKChmIChyZWFkLWZyYWN0aW9uKSkKKyAg
ICAgICAgICAgICAgICAgIChlIChyZWFkLWV4cG9uZW50KSkKKyAgICAgICAgICAgICAgICAgICh4
ICgqICgrIG4gZikgZSkpKQorICAgICAgICAgICAgIChpZiAoZXhhY3QtaW50ZWdlcj8geCkgeCAo
ZXhhY3QtPmluZXhhY3QgeCkpKSkpKQorICAoZGVmaW5lIChyZWFkLW5lZ2F0aXZlLW51bWJlcikK
KyAgICAocmVhZC1jaGFyIHBvcnQpCisgICAgKGxldCAoKHggKHJlYWQtcG9zaXRpdmUtbnVtYmVy
LW1heWJlKSkpCisgICAgICAoaWYgeCAoLSB4KSAoZmFpbCAiaW52YWxpZCBudW1iZXIiKSkpKQor
ICAoZGVmaW5lIChyZWFkLWxlYWRpbmctemVyby1udW1iZXIpCisgICAgKHJlYWQtY2hhciBwb3J0
KQorICAgIChjYXNlIChwZWVrLWNoYXIgcG9ydCkKKyAgICAgIDs7IEV4dHJhbmVvdXMgemVyb2Vz
IGFyZSBub3QgYWxsb3dlZC4KKyAgICAgICgoI1wwICNcMSAjXDIgI1wzICNcNCAjXDUgI1w2ICNc
NyAjXDggI1w5KQorICAgICAgIChmYWlsICJleHRyYW5lb3VzIGxlYWRpbmcgemVybyIpKQorICAg
ICAgKCgjXGUgI1xFKQorICAgICAgIChyZWFkLWV4cG9uZW50KSA7IDAgKiAxMF5uIGlzIHN0aWxs
IDAKKyAgICAgICAwKQorICAgICAgOzsgRnJhY3Rpb25hbCBudW1iZXIuCisgICAgICAoKCNcLikK
KyAgICAgICAobGV0KiAoKGQgKHJlYWQtZnJhY3Rpb24pKQorICAgICAgICAgICAgICAoZSAocmVh
ZC1leHBvbmVudCkpKQorICAgICAgICAgKGV4YWN0LT5pbmV4YWN0ICgqIGQgZSkpKSkKKyAgICAg
IDs7IEp1c3QgcGxhaW4gemVyby4KKyAgICAgIChlbHNlIDApKSkKKyAgKGRlZmluZSAocmVhZC1r
ZXkrdmFsdWUtcGFpcikKKyAgICAobGV0ICgoa2V5IChyZWFkLXN0cmluZykpKQorICAgICAgKGNv
bnN1bWUtd2hpdGVzcGFjZSkKKyAgICAgIChjYXNlIChyZWFkLWNoYXIgcG9ydCkKKyAgICAgICAg
KCgjXDopCisgICAgICAgICAoY29uc3VtZS13aGl0ZXNwYWNlKQorICAgICAgICAgKGNvbnMga2V5
IChyZWFkLXZhbHVlKSkpCisgICAgICAgIChlbHNlIChmYWlsICJpbnZhbGlkIGtleS92YWx1ZSBw
YWlyIGRlbGltaXRlciIpKSkpKQorICAoZGVmaW5lIChyZWFkLW9iamVjdCkKKyAgICAocmVhZC1j
aGFyIHBvcnQpCisgICAgKGNvbnN1bWUtd2hpdGVzcGFjZSkKKyAgICAoY2FzZSAocGVlay1jaGFy
IHBvcnQpCisgICAgICA7OyBFbXB0eSBvYmplY3QuCisgICAgICAoKCNcfSkKKyAgICAgICAocmVh
ZC1jaGFyIHBvcnQpCisgICAgICAgJygpKQorICAgICAgKGVsc2UKKyAgICAgICA7OyBSZWFkIGZp
cnN0IGtleS92YWx1ZSBwYWlyLCB0aGVuIGFsbCBzdWJzZXF1ZW50IHBhaXJzIGRlbGltaXRlZAor
ICAgICAgIDs7IGJ5IGNvbW1hcy4KKyAgICAgICAoY29ucyAocmVhZC1rZXkrdmFsdWUtcGFpcikK
KyAgICAgICAgICAgICAobGV0IGxwICgpCisgICAgICAgICAgICAgICAoY29uc3VtZS13aGl0ZXNw
YWNlKQorICAgICAgICAgICAgICAgKGNhc2UgKHBlZWstY2hhciBwb3J0KQorICAgICAgICAgICAg
ICAgICAoKCNcLCkKKyAgICAgICAgICAgICAgICAgIChyZWFkLWNoYXIgcG9ydCkKKyAgICAgICAg
ICAgICAgICAgIChjb25zdW1lLXdoaXRlc3BhY2UpCisgICAgICAgICAgICAgICAgICAoY29ucyAo
cmVhZC1rZXkrdmFsdWUtcGFpcikgKGxwKSkpCisgICAgICAgICAgICAgICAgIDs7IEVuZCBvZiBv
YmplY3QuCisgICAgICAgICAgICAgICAgICgoI1x9KQorICAgICAgICAgICAgICAgICAgKHJlYWQt
Y2hhciBwb3J0KQorICAgICAgICAgICAgICAgICAgJygpKQorICAgICAgICAgICAgICAgICAoZWxz
ZSAoZmFpbCAiaW52YWxpZCBvYmplY3QgZGVsaW1pdGVyIikpKSkpKSkpCisgIChkZWZpbmUgKHJl
YWQtYXJyYXkpCisgICAgKHJlYWQtY2hhciBwb3J0KQorICAgIChjb25zdW1lLXdoaXRlc3BhY2Up
CisgICAgKGNhc2UgKHBlZWstY2hhciBwb3J0KQorICAgICAgOzsgRW1wdHkgYXJyYXkuCisgICAg
ICAoKCNcXSkKKyAgICAgICAocmVhZC1jaGFyIHBvcnQpCisgICAgICAgIygpKQorICAgICAgKGVs
c2UKKyAgICAgICAobGlzdC0+dmVjdG9yCisgICAgICAgIDs7IFJlYWQgdGhlIGZpcnN0IGVsZW1l
bnQsIHRoZW4gYWxsIHN1YnNlcXVlbnQgZWxlbWVudHMKKyAgICAgICAgOzsgZGVsaW1pdGVkIGJ5
IGNvbW1hcy4KKyAgICAgICAgKGNvbnMgKHJlYWQtdmFsdWUpCisgICAgICAgICAgICAgIChsZXQg
bHAgKCkKKyAgICAgICAgICAgICAgICAoY29uc3VtZS13aGl0ZXNwYWNlKQorICAgICAgICAgICAg
ICAgIChjYXNlIChwZWVrLWNoYXIgcG9ydCkKKyAgICAgICAgICAgICAgICAgIDs7IEVsZW1lbnRz
IGFyZSBjb21tYSBkZWxpbWl0ZWQuCisgICAgICAgICAgICAgICAgICAoKCNcLCkKKyAgICAgICAg
ICAgICAgICAgICAocmVhZC1jaGFyIHBvcnQpCisgICAgICAgICAgICAgICAgICAgKGNvbnN1bWUt
d2hpdGVzcGFjZSkKKyAgICAgICAgICAgICAgICAgICAoY29ucyAocmVhZC12YWx1ZSkgKGxwKSkp
CisgICAgICAgICAgICAgICAgICA7OyBFbmQgb2YgYXJyYXkuCisgICAgICAgICAgICAgICAgICAo
KCNcXSkKKyAgICAgICAgICAgICAgICAgICAocmVhZC1jaGFyIHBvcnQpCisgICAgICAgICAgICAg
ICAgICAgJygpKQorICAgICAgICAgICAgICAgICAgKGVsc2UgKGZhaWwgImludmFsaWQgYXJyYXkg
ZGVsaW1pdGVyIikpKSkpKSkpKQorICAoZGVmaW5lIChyZWFkLXZhbHVlKQorICAgIChjb25zdW1l
LXdoaXRlc3BhY2UpCisgICAgKGNhc2UgKHBlZWstY2hhciBwb3J0KQorICAgICAgKCgjXCIpIChy
ZWFkLXN0cmluZykpCisgICAgICAoKCNceykgKHJlYWQtb2JqZWN0KSkKKyAgICAgICgoI1xbKSAo
cmVhZC1hcnJheSkpCisgICAgICAoKCNcdCkgKHJlYWQtdHJ1ZSkpCisgICAgICAoKCNcZikgKHJl
YWQtZmFsc2UpKQorICAgICAgKCgjXG4pIChyZWFkLW51bGwpKQorICAgICAgKCgjXC0pIChyZWFk
LW5lZ2F0aXZlLW51bWJlcikpCisgICAgICAoKCNcMCkgKHJlYWQtbGVhZGluZy16ZXJvLW51bWJl
cikpCisgICAgICAoKCNcMSAjXDIgI1wzICNcNCAjXDUgI1w2ICNcNyAjXDggI1w5KQorICAgICAg
IChyZWFkLXBvc2l0aXZlLW51bWJlci1tYXliZSkpCisgICAgICAoZWxzZSAoZmFpbCAiaW52YWxp
ZCB2YWx1ZSIpKSkpCisgIChyZWFkLXZhbHVlKSkKKworKGRlZmluZS1leGNlcHRpb24tdHlwZSAm
anNvbi13cml0ZS1lcnJvciAmZXJyb3IKKyAgbWFrZS1qc29uLXdyaXRlLWVycm9yCisgIGpzb24t
d3JpdGUtZXJyb3I/KQorCisoZGVmaW5lKiAod3JpdGUtanNvbiBleHAgIzpvcHRpb25hbCAocG9y
dCAoY3VycmVudC1vdXRwdXQtcG9ydCkpKQorICAiU2VyaWFsaXplIHRoZSBleHByZXNzaW9uIEB2
YXJ7ZXhwfSBhcyBKU09OLWVuY29kZWQgdGV4dCB0byBAdmFye3BvcnR9LgorSWYgQHZhcntwb3J0
fSBpcyB1bnNwZWNpZmllZCwgdGhlIGN1cnJlbnQgb3V0cHV0IHBvcnQgaXMgdXNlZC4iCisgIChk
ZWZpbmUgKGZhaWwgbWVzc2FnZSB4KQorICAgIChyYWlzZS1leGNlcHRpb24KKyAgICAgKG1ha2Ut
ZXhjZXB0aW9uIChtYWtlLWpzb24td3JpdGUtZXJyb3IpCisgICAgICAgICAgICAgICAgICAgICAo
bWFrZS1leGNlcHRpb24td2l0aC1vcmlnaW4gJ3dyaXRlLWpzb24pCisgICAgICAgICAgICAgICAg
ICAgICAobWFrZS1leGNlcHRpb24td2l0aC1tZXNzYWdlIG1lc3NhZ2UpCisgICAgICAgICAgICAg
ICAgICAgICAobWFrZS1leGNlcHRpb24td2l0aC1pcnJpdGFudHMgKGxpc3QgeCkpKSkpCisgIChk
ZWZpbmUgKHdyaXRlLWNoYXIvZXNjYXBlIGNoYXIpCisgICAgKG1hdGNoIGNoYXIKKyAgICAgICgj
XCIgKHB1dC1zdHJpbmcgcG9ydCAiXFxcIiIpKQorICAgICAgKCNcXCAocHV0LXN0cmluZyBwb3J0
ICJcXFxcIikpCisgICAgICAoI1wvIChwdXQtc3RyaW5nIHBvcnQgIlxcLyIpKQorICAgICAgKCNc
YmFja3NwYWNlIChwdXQtc3RyaW5nIHBvcnQgIlxcYiIpKQorICAgICAgKCNccGFnZSAocHV0LXN0
cmluZyBwb3J0ICJcXGYiKSkKKyAgICAgICgjXG5ld2xpbmUgKHB1dC1zdHJpbmcgcG9ydCAiXFxu
IikpCisgICAgICAoI1xyZXR1cm4gKHB1dC1zdHJpbmcgcG9ydCAiXFxyIikpCisgICAgICAoI1x0
YWIgKHB1dC1zdHJpbmcgcG9ydCAiXFx0IikpCisgICAgICAoXyAocHV0LWNoYXIgcG9ydCBjaGFy
KSkpKQorICAoZGVmaW5lICh3cml0ZS1zdHJpbmcgc3RyKQorICAgIChwdXQtY2hhciBwb3J0ICNc
IikKKyAgICAoc3RyaW5nLWZvci1lYWNoIHdyaXRlLWNoYXIvZXNjYXBlIHN0cikKKyAgICAocHV0
LWNoYXIgcG9ydCAjXCIpKQorICAoZGVmaW5lICh3cml0ZS1wYWlyIHgpCisgICAgKG1hdGNoIHgK
KyAgICAgICgoKD8gc3RyaW5nPyBrZXkpIC4gdmFsdWUpCisgICAgICAgKHdyaXRlLXN0cmluZyBr
ZXkpCisgICAgICAgKHB1dC1jaGFyIHBvcnQgI1w6KQorICAgICAgICh3cml0ZS12YWx1ZSB2YWx1
ZSkpCisgICAgICAoXyAoZmFpbCAiaW52YWxpZCBrZXkvdmFsdWUgcGFpciIgeCkpKSkKKyAgKGRl
ZmluZSAod3JpdGUtb2JqZWN0IG9iaikKKyAgICAocHV0LWNoYXIgcG9ydCAjXHspCisgICAgKG1h
dGNoIG9iagorICAgICAgKChoZWFkIC4gcmVzdCkKKyAgICAgICAod3JpdGUtcGFpciBoZWFkKQor
ICAgICAgIChsZXQgbHAgKChvYmogcmVzdCkpCisgICAgICAgICAobWF0Y2ggb2JqCisgICAgICAg
ICAgICgoKSAodmFsdWVzKSkKKyAgICAgICAgICAgKChoZWFkIC4gcmVzdCkKKyAgICAgICAgICAg
IChwdXQtY2hhciBwb3J0ICNcLCkKKyAgICAgICAgICAgICh3cml0ZS1wYWlyIGhlYWQpCisgICAg
ICAgICAgICAobHAgcmVzdCkpCisgICAgICAgICAgIChfIChmYWlsICJpbnZhbGlkIG9iamVjdCIg
b2JqKSkpKSkpCisgICAgKHB1dC1jaGFyIHBvcnQgI1x9KSkKKyAgKGRlZmluZSAod3JpdGUtYXJy
YXkgdikKKyAgICAocHV0LWNoYXIgcG9ydCAjXFspCisgICAgKG1hdGNoICh2ZWN0b3ItbGVuZ3Ro
IHYpCisgICAgICAoMCAodmFsdWVzKSkKKyAgICAgIChuCisgICAgICAgKHdyaXRlLXZhbHVlICh2
ZWN0b3ItcmVmIHYgMCkpCisgICAgICAgKGRvICgoaSAxICgxKyBpKSkpCisgICAgICAgICAgICgo
PSBpIG4pKQorICAgICAgICAgKHB1dC1jaGFyIHBvcnQgI1wsKQorICAgICAgICAgKHdyaXRlLXZh
bHVlICh2ZWN0b3ItcmVmIHYgaSkpKSkpCisgICAgKHB1dC1jaGFyIHBvcnQgI1xdKSkKKyAgKGRl
ZmluZSAod3JpdGUtbnVtYmVyIHgpCisgICAgKGlmIChvciAoZXhhY3QtaW50ZWdlcj8geCkKKyAg
ICAgICAgICAgIChhbmQgKHJlYWw/IHgpCisgICAgICAgICAgICAgICAgIChpbmV4YWN0PyB4KQor
ICAgICAgICAgICAgICAgICA7OyBOYU5zIGFuZCBpbmZpbml0aWVzIGFyZSBub3QgYWxsb3dlZC4K
KyAgICAgICAgICAgICAgICAgKG5vdCAob3IgKG5hbj8geCkgKGluZj8geCkpKSkpCisgICAgICAg
IDs7IFNjaGVtZSdzIHN0cmluZyByZXByZXNlbnRhdGlvbnMgb2YgZXhhY3QgaW50ZWdlcnMgYW5k
IGZsb2F0cworICAgICAgICA7OyBhcmUgY29tcGF0aWJsZSB3aXRoIEpTT04uCisgICAgICAgIChw
dXQtc3RyaW5nIHBvcnQgKG51bWJlci0+c3RyaW5nIHgpKQorICAgICAgICAoZmFpbCAiaW52YWxp
ZCBudW1iZXIiIHgpKSkKKyAgKGRlZmluZSAod3JpdGUtdmFsdWUgeCkKKyAgICAobWF0Y2ggeAor
ICAgICAgKCN0IChwdXQtc3RyaW5nIHBvcnQgInRydWUiKSkKKyAgICAgICgjZiAocHV0LXN0cmlu
ZyBwb3J0ICJmYWxzZSIpKQorICAgICAgKCdudWxsIChwdXQtc3RyaW5nIHBvcnQgIm51bGwiKSkK
KyAgICAgICgoKSAocHV0LXN0cmluZyBwb3J0ICJ7fSIpKQorICAgICAgKCg/IHBhaXI/KSAod3Jp
dGUtb2JqZWN0IHgpKQorICAgICAgKCg/IHZlY3Rvcj8pICh3cml0ZS1hcnJheSB4KSkKKyAgICAg
ICgoPyBzdHJpbmc/KSAod3JpdGUtc3RyaW5nIHgpKQorICAgICAgKCg/IG51bWJlcj8pICh3cml0
ZS1udW1iZXIgeCkpCisgICAgICAoXyAoZmFpbCAiaW52YWxpZCB2YWx1ZSIgeCkpKSkKKyAgKHdy
aXRlLXZhbHVlIGV4cCkpCmRpZmYgLS1naXQgYS90ZXN0LXN1aXRlL01ha2VmaWxlLmFtIGIvdGVz
dC1zdWl0ZS9NYWtlZmlsZS5hbQppbmRleCA2MDE0YjFmMWYuLjAwYWZlYTE0MiAxMDA2NDQKLS0t
IGEvdGVzdC1zdWl0ZS9NYWtlZmlsZS5hbQorKysgYi90ZXN0LXN1aXRlL01ha2VmaWxlLmFtCkBA
IC03Myw2ICs3Myw3IEBAIFNDTV9URVNUUyA9IHRlc3RzLzAwLWluaXRpYWwtZW52LnRlc3QJCVwK
IAkgICAgdGVzdHMvaWNvbnYudGVzdAkJCVwKIAkgICAgdGVzdHMvaW1wb3J0LnRlc3QJCQlcCiAJ
ICAgIHRlc3RzL2ludGVycC50ZXN0CQkJXAorCSAgICB0ZXN0cy9qc29uLnRlc3QJCQlcCiAJICAg
IHRlc3RzL2tleXdvcmRzLnRlc3QJCQlcCiAJICAgIHRlc3RzL2xpc3QudGVzdAkJCVwKIAkgICAg
dGVzdHMvbG9hZC50ZXN0CQkJXApkaWZmIC0tZ2l0IGEvdGVzdC1zdWl0ZS90ZXN0cy9qc29uLnRl
c3QgYi90ZXN0LXN1aXRlL3Rlc3RzL2pzb24udGVzdApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRl
eCAwMDAwMDAwMDAuLjM5NWQxZWExNwotLS0gL2Rldi9udWxsCisrKyBiL3Rlc3Qtc3VpdGUvdGVz
dHMvanNvbi50ZXN0CkBAIC0wLDAgKzEsMTU1IEBACis7Ozs7IGpzb24udGVzdCAtLS0gdGVzdCBK
U09OIHJlYWRlci93cml0ZXIgICAgIC0qLSBzY2hlbWUgLSotCis7Ozs7Cis7Ozs7IENvcHlyaWdo
dCAoQykgMjAyNSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4KKzs7OzsKKzs7OzsgVGhp
cyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9v
cgorOzs7OyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVy
YWwgUHVibGljCis7Ozs7IExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJl
IEZvdW5kYXRpb247IGVpdGhlcgorOzs7OyB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChh
dCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uCis7Ozs7Cis7Ozs7IFRoaXMgbGlicmFy
eSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLAorOzs7
OyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJy
YW50eSBvZgorOzs7OyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFS
IFBVUlBPU0UuICBTZWUgdGhlIEdOVQorOzs7OyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5z
ZSBmb3IgbW9yZSBkZXRhaWxzLgorOzs7OworOzs7OyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQg
YSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljCis7Ozs7IExpY2Vuc2UgYWxv
bmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgSWYgbm90LCBzZWUKKzs7OzsgPGh0dHBzOi8v
d3d3LmdudS5vcmcvbGljZW5zZXMvPi4KKworKGRlZmluZS1tb2R1bGUgKHRlc3Qtc3VpdGUgdGVz
dC1qc29uKQorICAjOnVzZS1tb2R1bGUgKHRlc3Qtc3VpdGUgbGliKQorICAjOnVzZS1tb2R1bGUg
KHdlYiBqc29uKSkKKworOzs7Cis7OzsgUmVhZGVyCis7OzsKKworKGRlZmluZSAocmVhZC1qc29u
LXN0cmluZyBzdHIpCisgIChjYWxsLXdpdGgtaW5wdXQtc3RyaW5nIHN0ciByZWFkLWpzb24pKQor
CisoZGVmaW5lIChqc29uLXJlYWQ9PyBzdHIgeCkKKyAgKD0geCAocmVhZC1qc29uLXN0cmluZyBz
dHIpKSkKKworKGRlZmluZSAoanNvbi1yZWFkLWVxPyBzdHIgeCkKKyAgKGVxPyB4IChyZWFkLWpz
b24tc3RyaW5nIHN0cikpKQorCisoZGVmaW5lIChqc29uLXJlYWQtZXF1YWw/IHN0ciB4KQorICAo
ZXF1YWw/IHggKHJlYWQtanNvbi1zdHJpbmcgc3RyKSkpCisKKyhkZWZpbmUgKGpzb24tcmVhZC1z
dHJpbmc9PyBzdHIgeCkKKyAgKHN0cmluZz0/IHggKHJlYWQtanNvbi1zdHJpbmcgc3RyKSkpCisK
Kyh3aXRoLXRlc3QtcHJlZml4ICJyZWFkLWpzb24iCisgIDs7IEtleXdvcmRzLgorICAocGFzcy1p
ZiAoanNvbi1yZWFkLWVxPyAidHJ1ZSIgI3QpKQorICAocGFzcy1pZiAoanNvbi1yZWFkLWVxPyAi
ZmFsc2UiICNmKSkKKyAgKHBhc3MtaWYgKGpzb24tcmVhZC1lcT8gIm51bGwiICdudWxsKSkKKyAg
OzsgTnVtYmVycy4KKyAgKHBhc3MtaWYgKGpzb24tcmVhZD0/ICIwIiAwKSkKKyAgKHBhc3MtaWYg
KGpzb24tcmVhZD0/ICItMCIgMCkpCisgIChwYXNzLWlmIChqc29uLXJlYWQ9PyAiMC4wIiAwLjAp
KQorICAocGFzcy1pZiAoanNvbi1yZWFkPT8gIi0wLjAiIC0wLjApKQorICAocGFzcy1pZiAoanNv
bi1yZWFkPT8gIjAuMSIgMC4xKSkKKyAgKHBhc3MtaWYgKGpzb24tcmVhZD0/ICIxLjIzNCIgMS4y
MzQpKQorICAocGFzcy1pZiAoanNvbi1yZWFkPT8gIjEiIDEpKQorICAocGFzcy1pZiAoanNvbi1y
ZWFkPT8gIi0xIiAtMSkpCisgIChwYXNzLWlmIChqc29uLXJlYWQ9PyAiMS4xIiAxLjEpKQorICAo
cGFzcy1pZiAoanNvbi1yZWFkPT8gIjFlMiIgMWUyKSkKKyAgKHBhc3MtaWYgKGpzb24tcmVhZD0/
ICIwZTMiIDApKQorICAocGFzcy1pZiAoanNvbi1yZWFkPT8gIjEuMWUyIiAxLjFlMikpCisgIChw
YXNzLWlmIChqc29uLXJlYWQ9PyAiMS4xZS0yIiAxLjFlLTIpKQorICAocGFzcy1pZiAoanNvbi1y
ZWFkPT8gIjEuMWUrMiIgMS4xZTIpKQorICA7OyBFeHRyYW5lb3VzIHplcm9lcyBpbiBmcmFjdGlv
bi4KKyAgKHBhc3MtaWYgKGpzb24tcmVhZD0/ICIxLjAwMCIgMSkpCisgIChwYXNzLWlmIChqc29u
LXJlYWQ9PyAiMS41MDAwIiAxLjUpKQorICA7OyBFeHRyYW5lb3VzIHplcm9lcyBpbiBleHBvbmVu
dC4KKyAgKHBhc3MtaWYgKGpzb24tcmVhZD0/ICIxLjFlMDAwIiAxLjEpKQorICAocGFzcy1pZiAo
anNvbi1yZWFkPT8gIjEuMWUtMDIiIDEuMWUtMikpCisgIChwYXNzLWlmIChqc29uLXJlYWQ9PyAi
MS4xZSswMiIgMS4xZTIpKQorICA7OyBTdHJpbmdzLgorICAocGFzcy1pZiAoanNvbi1yZWFkLXN0
cmluZz0/ICJcImZvb1wiIiAiZm9vIikpCisgIDs7IEVzY2FwZSBjb2Rlcy4KKyAgKHBhc3MtaWYg
KGpzb24tcmVhZC1zdHJpbmc9PyAiXCJcXFwiXCIiICJcIiIpKQorICAocGFzcy1pZiAoanNvbi1y
ZWFkLXN0cmluZz0/ICJcIlxcXFxcIiIgIlxcIikpCisgIChwYXNzLWlmIChqc29uLXJlYWQtc3Ry
aW5nPT8gIlwiXFwvXCIiICIvIikpCisgIChwYXNzLWlmIChqc29uLXJlYWQtc3RyaW5nPT8gIlwi
XFxiXCIiICJcYiIpKQorICAocGFzcy1pZiAoanNvbi1yZWFkLXN0cmluZz0/ICJcIlxcZlwiIiAi
XGYiKSkKKyAgKHBhc3MtaWYgKGpzb24tcmVhZC1zdHJpbmc9PyAiXCJcXG5cIiIgIlxuIikpCisg
IChwYXNzLWlmIChqc29uLXJlYWQtc3RyaW5nPT8gIlwiXFxyXCIiICJcciIpKQorICAocGFzcy1p
ZiAoanNvbi1yZWFkLXN0cmluZz0/ICJcIlxcdFwiIiAiXHQiKSkKKyAgOzsgVW5pY29kZSBpbiBo
ZXhhZGVjaW1hbCBmb3JtYXQuCisgIChwYXNzLWlmIChqc29uLXJlYWQtc3RyaW5nPT8gIlwiXFx1
MTJhYlwiIiAiXHUxMmFiIikpCisgIDs7IE9iamVjdHMuCisgIChwYXNzLWlmIChqc29uLXJlYWQt
ZXF1YWw/ICJ7fSIgJygpKSkKKyAgKHBhc3MtaWYgKGpzb24tcmVhZC1lcXVhbD8gInsgXCJmb29c
IjogXCJiYXJcIiwgXCJiYXpcIjogXCJmcm9iXCJ9IgorICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAnKCgiZm9vIiAuICJiYXIiKSAoImJheiIgLiAiZnJvYiIpKSkpCisgIDs7IE5lc3RlZCBv
YmplY3RzLgorICAocGFzcy1pZiAoanNvbi1yZWFkLWVxdWFsPyAie1wiZm9vXCI6e1wiYmFyXCI6
XCJiYXpcIn19IgorICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnKCgiZm9vIiAuICgoImJh
ciIgLiAiYmF6IikpKSkpKQorICA7OyBBcnJheXMuCisgIChwYXNzLWlmIChqc29uLXJlYWQtZXF1
YWw/ICJbXSIgIygpKSkKKyAgKHBhc3MtaWYgKGpzb24tcmVhZC1lcXVhbD8gIlsxLCAyLCBcImZv
b1wiXSIKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIygxIDIgImZvbyIpKSkKKyAgOzsg
TmVzdGVkIGFycmF5cy4KKyAgKHBhc3MtaWYgKGpzb24tcmVhZC1lcXVhbD8gIlsxLCAyLCBbXCJm
b29cIiwgXCJiYXJcIl1dIgorICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjKDEgMiAjKCJm
b28iICJiYXIiKSkpKQorICA7OyBBcnJheXMgYW5kIG9iamVjdHMgbmVzdGVkIHdpdGhpbiBlYWNo
IG90aGVyLgorICAocGFzcy1pZiAoanNvbi1yZWFkLWVxdWFsPyAie1wiZm9vXCI6W3tcImJhclwi
OnRydWV9LHtcImJhelwiOlsxLDIsM119XX0iCisgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICcoKCJmb28iIC4gIygoKCJiYXIiIC4gI3QpKQorICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgKCgiYmF6IiAuICMoMSAyIDMpKSkpKSkpKQorICA7OyBMZWFkaW5nIHdo
aXRlc3BhY2UuCisgIChwYXNzLWlmIChqc29uLXJlYWQtZXE/ICJcdFxyXG4gdHJ1ZSIgI3QpKSkK
KworOzs7Cis7OzsgV3JpdGVyCis7OzsKKworKGRlZmluZSAod3JpdGUtanNvbi1zdHJpbmcgZXhw
KQorICAoY2FsbC13aXRoLW91dHB1dC1zdHJpbmcKKyAgIChsYW1iZGEgKHBvcnQpCisgICAgICh3
cml0ZS1qc29uIGV4cCBwb3J0KSkpKQorCisoZGVmaW5lIChqc29uLXdyaXRlLXN0cmluZz0/IGV4
cCBzdHIpCisgIChzdHJpbmc9PyBzdHIgKHdyaXRlLWpzb24tc3RyaW5nIGV4cCkpKQorCisod2l0
aC10ZXN0LXByZWZpeCAid3JpdGUtanNvbiIKKyAgOzsgS2V5d29yZHMuCisgIChwYXNzLWlmIChq
c29uLXdyaXRlLXN0cmluZz0/ICN0ICJ0cnVlIikpCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0
cmluZz0/ICNmICJmYWxzZSIpKQorICAocGFzcy1pZiAoanNvbi13cml0ZS1zdHJpbmc9PyAnbnVs
bCAibnVsbCIpKQorICA7OyBOdW1iZXJzLgorICAocGFzcy1pZiAoanNvbi13cml0ZS1zdHJpbmc9
PyAwICIwIikpCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0cmluZz0/IDAuMCAiMC4wIikpCisg
IChwYXNzLWlmIChqc29uLXdyaXRlLXN0cmluZz0/IDAuMSAiMC4xIikpCisgIChwYXNzLWlmIChq
c29uLXdyaXRlLXN0cmluZz0/IDEgIjEiKSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5n
PT8gLTEgIi0xIikpCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0cmluZz0/IDEuMSAiMS4xIikp
CisgIDs7IFN0cmluZ3MuCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0cmluZz0/ICJmb28iICJc
ImZvb1wiIikpCisgIDs7IEVzY2FwZSBjb2Rlcy4KKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3Ry
aW5nPT8gIlwiIiAiXCJcXFwiXCIiKSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8g
IlxcIiAiXCJcXFxcXCIiKSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gIi8iICJc
IlxcL1wiIikpCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0cmluZz0/ICJcYiIgIlwiXFxiXCIi
KSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gIlxmIiAiXCJcXGZcIiIpKQorICAo
cGFzcy1pZiAoanNvbi13cml0ZS1zdHJpbmc9PyAiXG4iICJcIlxcblwiIikpCisgIChwYXNzLWlm
IChqc29uLXdyaXRlLXN0cmluZz0/ICJcciIgIlwiXFxyXCIiKSkKKyAgKHBhc3MtaWYgKGpzb24t
d3JpdGUtc3RyaW5nPT8gIlx0IiAiXCJcXHRcIiIpKQorICA7OyBPYmplY3RzLgorICAocGFzcy1p
ZiAoanNvbi13cml0ZS1zdHJpbmc9PyAnKCkgInt9IikpCisgIChwYXNzLWlmIChqc29uLXdyaXRl
LXN0cmluZz0/ICcoKCJmb28iIC4gImJhciIpICgiYmF6IiAuICJmcm9iIikpCisgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICJ7XCJmb29cIjpcImJhclwiLFwiYmF6XCI6XCJmcm9iXCJ9
IikpCisgIDs7IE5lc3RlZCBvYmplY3RzLgorICAocGFzcy1pZiAoanNvbi13cml0ZS1zdHJpbmc9
PyAnKCgiZm9vIiAuICgoImJhciIgLiAiYmF6IikpKSkKKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIntcImZvb1wiOntcImJhclwiOlwiYmF6XCJ9fSIpKQorICA7OyBBcnJheXMuCisg
IChwYXNzLWlmIChqc29uLXdyaXRlLXN0cmluZz0/ICMoKSAiW10iKSkKKyAgKHBhc3MtaWYgKGpz
b24td3JpdGUtc3RyaW5nPT8gIygxIDIgImZvbyIpCisgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICJbMSwyLFwiZm9vXCJdIikpCisgIDs7IE5lc3RlZCBhcnJheXMuCisgIChwYXNzLWlm
IChqc29uLXdyaXRlLXN0cmluZz0/ICMoMSAyICMoImZvbyIgImJhciIpKQorICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAiWzEsMixbXCJmb29cIixcImJhclwiXV0iKSkKKyAgOzsgQXJy
YXlzIGFuZCBvYmplY3RzIG5lc3RlZCBpbiBlYWNoIG90aGVyLgorICAocGFzcy1pZiAoanNvbi13
cml0ZS1zdHJpbmc9PyAnKCgiZm9vIiAuICMoKCgiYmFyIiAuICN0KSkKKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoImJheiIgLiAjKDEgMikpKSkpKQorICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAie1wiZm9vXCI6W3tcImJhclwiOnRydWV9LHtc
ImJhelwiOlsxLDJdfV19IikpKQotLSAKMi40Ny4xCgo=
--0000000000006c2d480632bc057b--




Information forwarded to bug-guile@HIDDEN:
bug#77762; Package guile. Full text available.

Message received at 77762 <at> debbugs.gnu.org:


Received: (at 77762) by debbugs.gnu.org; 14 Apr 2025 06:31:30 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Apr 14 02:31:30 2025
Received: from localhost ([127.0.0.1]:45423 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1u4DLs-0002gp-Lt
	for submit <at> debbugs.gnu.org; Mon, 14 Apr 2025 02:31:30 -0400
Received: from mail-pl1-x634.google.com ([2607:f8b0:4864:20::634]:48237)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <maxim.cournoyer@HIDDEN>)
 id 1u4DLo-0002gX-2N
 for 77762 <at> debbugs.gnu.org; Mon, 14 Apr 2025 02:31:25 -0400
Received: by mail-pl1-x634.google.com with SMTP id
 d9443c01a7336-2243803b776so56581525ad.0
 for <77762 <at> debbugs.gnu.org>; Sun, 13 Apr 2025 23:31:24 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1744612277; x=1745217077; darn=debbugs.gnu.org;
 h=mime-version:user-agent:message-id:date:references:in-reply-to
 :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to;
 bh=rEGL0guU40SWGc5zf8BuZCzri3aBxgdryDh+O1PRpW8=;
 b=LhhN1iGTLvHU24b6UNNqF0/LUwLZ4LuDc5s+qvKyxIygXn6zipz80i3038e/8q6mYO
 pM0+EUn+YnJ+IUpXuvjppZcYdNzY8hAjJprs0Ut9yyhBMCO3qAElOFveNsqY3hC5krtj
 PJyO8jhhU7vqdctW+3H9c5sMn3s2O7HXKeZEgH1Tphv0fAIEaB7RXwuVP257OG+xvqJe
 7a/T3gZTNZ9hrTGk1mUebQo+qEGwnTd5nWdhKvbfwuHWzC0Bt0hOU/SOa3HUDciugJYF
 r6903sMrHEdwM8KKG9v5f7I81J98iGrbWlw7H9pLt6+phnFHZBKzMBvu5ghMbzAxcp6Y
 is7g==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1744612277; x=1745217077;
 h=mime-version:user-agent:message-id:date:references:in-reply-to
 :subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date
 :message-id:reply-to;
 bh=rEGL0guU40SWGc5zf8BuZCzri3aBxgdryDh+O1PRpW8=;
 b=K01IC3ThV5YKKSYhX2QMmd88i5WVvq01xZUvoKtCywWaUqqiJr5P1ptig+eDnCJIVL
 +MQAX9kCVZlqSYvGnZE6KVPPGv7TBw8J0ey7nfRCtBp/WLu/BpgqGxtejFTO8zYov5B9
 LlBlcTbkmayeUu7w/l2fWtpHZvYUS9ttq8bw/Nq7KyZnzmQLdNp/Hvpu1kQKfPTgKJY/
 ucyk6itgOXTotuglgqRo68g+cATvR6GvvRnVi1+Rgnbbr1i3YLTy59uYRbobtCvvF03Z
 xT4f+N0DWN64GAhXxKVyQDavEWtN8jIEG0F8W4/p4Wb1m435LdGpqlcyvFFEWWRW2A5d
 lDMg==
X-Gm-Message-State: AOJu0YxypLA+wP/FeCHxa6rV68lm5zqHcL7AruAeqc2r5J4vgnYOrzLS
 VVMVv9jvh4LCsG4L0rF0X/hCWm7mAREpqeXceZStmvR2ReXm1u/8v6RbWw==
X-Gm-Gg: ASbGncvPqQ5ah8NWtlIJZYfkwQbwBxXZh7LEPZKvn/ovrBjQ4mJTWIN+6pvOrDqEC7I
 9UkzYeZGJu+0o/WSSyst19JIEgjlgUNhyD6EJciaXGktQXwR8I/dK4jgEarOW2rhe8E9AsslHwG
 lReTavkM2mQYPtx+9JnYno0gbvwOZaEZlNRefBLYJl12sHXzyVWQ0Y8mUV+1nMXYrHeMWBvVM1T
 YpuiTE1j4TWj9c6wxFkIBKmmSh6X3s9V8HbRyBlTcr859vNA4ZuieqKSEC0+SJQ2QCbRDljCnk5
 XkjTaRxJDosw91/7bwyZb60u7SeOl8LHyZHwfsXCEvtDZ3sXgQ==
X-Google-Smtp-Source: AGHT+IF/QTFni7wQRH+tC/BIPk7bEL+Q+ZMGWMyRq5xgPZpFrVKMh9ttZ9uezro13jBzvshz4pClkA==
X-Received: by 2002:a17:902:d2ca:b0:220:faa2:c911 with SMTP id
 d9443c01a7336-22bea4ab6f9mr150111275ad.14.1744612276196; 
 Sun, 13 Apr 2025 23:31:16 -0700 (PDT)
Received: from terra ([2405:6586:be0:0:83c8:d31d:2cec:f542])
 by smtp.gmail.com with ESMTPSA id
 d9443c01a7336-22ac7cb59b1sm92416395ad.196.2025.04.13.23.31.14
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Sun, 13 Apr 2025 23:31:15 -0700 (PDT)
From: Maxim Cournoyer <maxim.cournoyer@HIDDEN>
To: "Thompson, David" <dthompson2@HIDDEN>
Subject: Re: bug#77762: [PATCH] web: Add JSON module.
In-Reply-To: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
 (David Thompson's message of "Sat, 12 Apr 2025 09:14:31 -0400")
References: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
Date: Mon, 14 Apr 2025 15:30:55 +0900
Message-ID: <87plhfuue8.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 77762
Cc: 77762 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hi David,

"Thompson, David" <dthompson2@HIDDEN> writes:

> Attached is a patch that adds a new (web json) module. Some may
> remember that I submitted a patch back in 2015 (time flies, eh?) for
> an (ice-9 json) module that never made it in. Well, 10 years is a long
> time and Guile still doesn't have a built-in JSON module. Third party
> libraries like guile-json and guile-sjson are available, the latter
> being an adaptation of my original patch and the former remaining the
> go-to library used by larger Guile projects like Guix. There's also
> SRFI-180 (which sounds like a cool surfing trick!) which was published
> in 2020 but the API is, in my opinion, overly complicated due to
> generators and other things.  Anyway, JSON continues to be *the* data
> interchange format of the web and Guile really ought to have a simple
> API that can read/write JSON to/from a port using only Scheme data
> types that have read syntax (i.e. no hash tables like guile-json).
> This minimal, practical API is what my patch provides.  I've tried my
> best to make it as efficient as possible.
>
> I've settled on the following JSON<->Scheme data type mapping which is
> nearly identical to SRFI-180 with the exception of object keys:
>
> - true and false are #t and #f
> - null is the symbol 'null
> - numbers are either exact integers (fixnums and bignums) or inexact
> reals (flonums, NaNs and infinities excluded)
> - strings are strings
> - arrays are vectors
> - objects are association lists with string keys (SRFI-180 chose
> symbols but JSON uses strings so strings feel the most honest)
>
> Thanks in advance for the review,

First of all, let me say thank you for working on that!  I agree that
this would be most welcome in core Guile, for the reasons you mention.

[...]

> +@example
> +@verbatim
> +{
> +  "name": "Eva Luator",
> +  "age": 24,
> +  "schemer": true,
> +  "hobbies": [
> +    "hacking",
> +    "cycling",
> +    "surfing"
> +  ]
> +}
> +@end verbatim
> +@end example
> +
> +can be represented with the following Scheme expression:
> +
> +@example
> +@verbatim
> +'(("name" . "Eva Luator")
> +  ("age" . 24)
> +  ("schemer" . #t)
> +  ("hobbies" . #("hacking" "cycling" "surfing")))
> +@end verbatim
> +@end example

Is there particular reason for using vectors instead of plain list to
represent JSON arrays?  The later would be more idiomatic unless there
are technical reasons (perhaps performance?).

> +Strings, exact integers, inexact reals (excluding NaNs and infinities),
> +@code{#t}, @code{#f}, the symbol @code{null}, vectors, and association
> +lists may be serialized as JSON.  Association lists serialize as JSON
> +objects and vectors serialize as JSON arrays.  The keys of association
> +lists @emph{must} be strings.
> +
> +@deffn {Scheme Procedure} read-json [port]
> +
> +Parse a JSON-encoded value from @var{port} and return its Scheme
> +representation.  If @var{port} is unspecified, the current input port is
> +used.
> +
> +@example
> +@verbatim
> +(call-with-input-string "[true,false,null,42,\"foo\"]" read-json)
> +;; => #(#t #f null 42 "foo")
> +
> +(call-with-input-string "{\"foo\":1,\"bar\":2}" read-json)
> +;; => (("foo" . 1) ("bar" . 2))
> +@end verbatim
> +@end example
> +
> +@end deffn
> +
> +@deftp {Exception Type} &json-read-error
> +An exception type denoting JSON read errors.
> +@end deftp
>
> +@deffn {Scheme Procedure} write-json exp [port]
> +
> +Serialize the expression @var{exp} as JSON-encoded text to @var{port}.
> +If @var{port} is unspecified, the current output port is used.
> +
> +@example
> +@verbatim
> +(with-output-to-string (lambda () (write-json #(#t #f null 42 "foo"))))
> +;; => "[true,false,null,42,\"foo\"]"
> +
> +(with-output-to-string (lambda () (write-json '(("foo" . 1) ("bar" . 2)))))
> +;; => "{\"foo\":1,\"bar\":2}"
> +@end verbatim
> +@end example
> +
> +@end deffn
> +
> +@deftp {Exception Type} &json-write-error
> +An exception type denoting JSON write errors.
> +@end deftp

I think it could be a bit nicer if the deffn of read-json and write-json
explicitly mentioned that upon error an exception of type X is raised.

> +
>  @node Web Client
>  @subsection Web Client
>  
> diff --git a/module/web/json.scm b/module/web/json.scm
> new file mode 100644
> index 000000000..41aac0e90
> --- /dev/null
> +++ b/module/web/json.scm
> @@ -0,0 +1,308 @@
> +;;;; json.scm --- JSON reader/writer (ECMA-404)
> +;;;; Copyright (C) 2025 Free Software Foundation, Inc.
> +;;;;
> +;;;; This library is free software; you can redistribute it and/or
> +;;;; modify it under the terms of the GNU Lesser General Public
> +;;;; License as published by the Free Software Foundation; either
> +;;;; version 3 of the License, or (at your option) any later version.
> +;;;;
> +;;;; This library is distributed in the hope that it will be useful,
> +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +;;;; Lesser General Public License for more details.
> +;;;;
> +;;;; You should have received a copy of the GNU Lesser General Public
> +;;;; License along with this library; if not, write to the Free Software
> +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

The FSF has gone office-less, so the above address is now incorrect [0].
The up-to-date template for the copyright notice (header) reads [1]:

--8<---------------cut here---------------start------------->8---
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program. If not, see
    <https://www.gnu.org/licenses/>.
--8<---------------cut here---------------end--------------->8---

[0]  https://www.fsf.org/blogs/community/fsf-office-closing-party
[1]  https://www.gnu.org/licenses/gpl-howto.html

> +
> +(define-module (web json)
> +  #:use-module (ice-9 exceptions)
> +  #:use-module (ice-9 match)
> +  #:use-module (ice-9 textual-ports)
> +  #:export (&json-read-error
> +            read-json
> +
> +            &json-write-error
> +            write-json))
> +
> +(define-exception-type &json-read-error &error
> +  make-json-read-error
> +  json-read-error?)
> +
> +(define* (read-json #:optional (port (current-input-port)))
> +  "Parse a JSON-encoded value from @var{port} and return its Scheme
> +representation.  If @var{port} is unspecified, the current input port is
> +used."
> +  (define (fail message)
> +    (raise-exception
> +     (make-exception (make-json-read-error)
> +                     (make-exception-with-origin 'read-json)
> +                     (make-exception-with-message message)
> +                     (make-exception-with-irritants (list port)))))

Hm, I wonder what (list port) looks like in the irritants when the
exception is reported; is it useful?  Shouldn't it show instead the
problematic value?

> +  (define (consume-whitespace)
> +    (case (peek-char port)
> +      ((#\space #\tab #\return #\newline)

Should a match + ((? char-whitespace?)) predicate pattern be used here
instead, or similar?  Or perhaps the above is faster and more
self-contained, which can be a good thing.

> +       (read-char port)
> +       (consume-whitespace))
> +      (else (values))))
> +  (define-syntax-rule (define-keyword-reader name str val)
> +    (define (name)
> +      (if (string=? (get-string-n port (string-length str)) str)
> +          val
> +          (fail "invalid keyword"))))
> +  (define-keyword-reader read-true "true" #t)
> +  (define-keyword-reader read-false "false" #f)
> +  (define-keyword-reader read-null "null" 'null)
> +  (define (read-hex-digit)
> +    (case (peek-char port)
> +      ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
> +       (- (char->integer (read-char port)) (char->integer #\0)))
> +      ((#\a #\b #\c #\d #\e #\f)
> +       (+ 10 (- (char->integer (read-char port)) (char->integer #\a))))
> +      ((#\A #\B #\C #\D #\E #\F)
> +       (+ 10 (- (char->integer (read-char port)) (char->integer #\A))))
> +      (else (fail "invalid hex digit"))))
> +  (define (read-utf16-character)
> +    (let* ((a (read-hex-digit))
> +           (b (read-hex-digit))
> +           (c (read-hex-digit))
> +           (d (read-hex-digit)))
> +      (integer->char (+ (* a (expt 16 3)) (* b (expt 16 2)) (* c 16) d))))
> +  (define (read-escape-character)
> +    (case (read-char port)
> +      ((#\") #\")
> +      ((#\\) #\\)
> +      ((#\/) #\/)
> +      ((#\b) #\backspace)
> +      ((#\f) #\page)
> +      ((#\n) #\newline)
> +      ((#\r) #\return)
> +      ((#\t) #\tab)
> +      ((#\u) (read-utf16-character))
> +      (else (fail "invalid escape character"))))
> +  (define (read-string)
> +    (read-char port)
> +    (list->string
> +     (let lp ()
> +       (match (read-char port)
> +         ((? eof-object?) (fail "EOF while reading string"))
> +         (#\" '())
> +         (#\\ (cons (read-escape-character) (lp)))
> +         (char (cons char (lp)))))))
> +  (define (read-digit-maybe)
> +    (case (peek-char port)
> +      ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
> +       (- (char->integer (read-char port))
> +          (char->integer #\0)))
> +      (else #f)))
> +  (define (read-integer)
> +    (let ((x (read-digit-maybe)))
> +      (and x
> +           (let lp ((x x))
> +             (match (read-digit-maybe)
> +               (#f x)
> +               (y (lp (+ (* x 10) y))))))))

Perhaps the above should be named read-integer-maybe, since it may
return #f?

> +  (define (read-fraction)
> +    (case (peek-char port)
> +      ((#\.)
> +       (read-char port)
> +       (let lp ((mag 10))
> +         (let ((n (read-digit-maybe)))
> +           (if n (+ (/ n mag) (lp (* mag 10))) 0))))
> +      (else 0)))

Should the above be named 'read-decimal' ?  Does a decimal number in
JSON always start with '.' and not with 0. ?  I was a bit puzzled on
what 'mag' may mean here, I guess 'magnitude' although there doesn't
appear to have a clear terminology for it.

> +  (define (read-exponent)
> +    (case (peek-char port)
> +      ((#\e #\E)
> +       (read-char port)
> +       (case (peek-char port)
> +         ((#\-)
> +          (read-char port)
> +          (expt 10 (- (read-integer))))
> +         ((#\+)
> +          (read-char port)
> +          (expt 10 (read-integer)))
> +         (else
> +          (expt 10 (read-integer)))))
> +      (else 1)))
> +  (define (read-positive-number)
> +    (let ((n (read-integer)))
> +      (and n
> +           (let* ((f (read-fraction))
> +                  (e (read-exponent))
> +                  (x (* (+ n f) e)))
> +             (if (exact-integer? x) x (exact->inexact x))))))

This may return #f.  Should it fail instead, or be named
read-positive-number-maybe ?

> +  (define (read-negative-number)
> +    (read-char port)
> +    (let ((x (read-positive-number)))
> +      (if x (- x) (fail "invalid number"))))

Not symmetrical with the above: this one would fail if an integer
couldn't be read in read-positive-number.

> +  (define (read-leading-zero-number)
> +    (read-char port)
> +    (case (peek-char port)
> +      ;; Extraneous zeroes are not allowed.  A single leading zero
> +      ;; can only be followed by a decimal point.
> +      ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\e #\E)
> +       (fail "extraneous leading zero"))

Why not check for (not #\.) explicitly?  That'd be clearer and would
cover all cases (even crazy unexpected ones).

> +      ;; Fractional number.
> +      ((#\.)
> +       (let* ((d (read-fraction))
> +              (e (read-exponent)))
> +         (exact->inexact (* d e))))
> +      ;; Just plain zero.
> +      (else 0)))
> +  (define (read-key+value-pair)
> +    (let ((key (read-string)))
> +      (consume-whitespace)
> +      (case (read-char port)
> +        ((#\:)
> +         (consume-whitespace)
> +         (cons key (read-value)))
> +        (else (fail "invalid key/value pair delimiter")))))
> +  (define (read-object)
> +    (read-char port)
> +    (consume-whitespace)
> +    (case (peek-char port)
> +      ;; Empty object.
> +      ((#\})
> +       (read-char port)
> +       '())
> +      (else
> +       ;; Read first key/value pair, then all subsequent pairs delimited
> +       ;; by commas.
> +       (cons (read-key+value-pair)
> +             (let lp ()
> +               (consume-whitespace)
> +               (case (peek-char port)
> +                 ((#\,)
> +                  (read-char port)
> +                  (consume-whitespace)
> +                  (cons (read-key+value-pair) (lp)))
> +                 ;; End of object.
> +                 ((#\})
> +                  (read-char port)
> +                  '())
> +                 (else (fail "invalid object delimiter"))))))))
> +  (define (read-array)
> +    (read-char port)
> +    (consume-whitespace)
> +    (case (peek-char port)
> +      ;; Empty array.
> +      ((#\])
> +       (read-char port)
> +       #())
> +      (else
> +       (list->vector

As mentioned above, just a plain list would be more Schemey, no?  What
does the vector type buys us?  A user wanting a vector could always call
list->vector themselves, and otherwise we save some computation.

> +        ;; Read the first element, then all subsequent elements
> +        ;; delimited by commas.
> +        (cons (read-value)
> +              (let lp ()
> +                (consume-whitespace)
> +                (case (peek-char port)
> +                  ;; Elements are comma delimited.
> +                  ((#\,)
> +                   (read-char port)
> +                   (consume-whitespace)
> +                   (cons (read-value) (lp)))
> +                  ;; End of array.
> +                  ((#\])
> +                   (read-char port)
> +                   '())
> +                  (else (fail "invalid array delimiter")))))))))
> +  (define (read-value)
> +    (consume-whitespace)
> +    (case (peek-char port)
> +      ((#\") (read-string))
> +      ((#\{) (read-object))
> +      ((#\[) (read-array))
> +      ((#\t) (read-true))
> +      ((#\f) (read-false))
> +      ((#\n) (read-null))
> +      ((#\-) (read-negative-number))
> +      ((#\0) (read-leading-zero-number))
> +      ((#\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) (read-positive-number))
> +      (else (fail "invalid value"))))
> +  (read-value))
> +
> +(define-exception-type &json-write-error &error
> +  make-json-write-error
> +  json-write-error?)
> +
> +(define* (write-json exp #:optional (port (current-output-port)))
> +  "Serialize the expression @var{exp} as JSON-encoded text to @var{port}.
> +If @var{port} is unspecified, the current output port is used."
> +  (define (fail message x)
> +    (raise-exception
> +     (make-exception (make-json-write-error)
> +                     (make-exception-with-origin 'write-json)
> +                     (make-exception-with-message message)
> +                     (make-exception-with-irritants (list x)))))
> +  (define (write-char/escape char)
> +    (match char
> +      (#\" (put-string port "\\\""))
> +      (#\\ (put-string port "\\\\"))
> +      (#\/ (put-string port "\\/"))
> +      (#\backspace (put-string port "\\b"))
> +      (#\page (put-string port "\\f"))
> +      (#\newline (put-string port "\\n"))
> +      (#\return (put-string port "\\r"))
> +      (#\tab (put-string port "\\t"))
> +      (_ (put-char port char))))
> +  (define (write-string str)
> +    (let ((in (open-input-string str)))

Looks like the above 'in' binding is not used.

> +      (put-char port #\")
> +      (string-for-each write-char/escape str)
> +      (put-char port #\")))
> +  (define (write-pair x)
> +    (match x
> +      (((? string? key) . value)
> +       (write-string key)
> +       (put-char port #\:)
> +       (write-value value))
> +      (_ (fail "invalid key/value pair" x))))
> +  (define (write-object obj)
> +    (put-char port #\{)
> +    (match obj
> +      ((head . rest)
> +       (write-pair head)
> +       (let lp ((obj rest))
> +         (match obj
> +           (() (values))

Any reason to return (values) instead of some dummy #t to denote 'no-op'
?.

> +           ((head . rest)
> +            (put-char port #\,)
> +            (write-pair head)
> +            (lp rest))
> +           (_ (fail "invalid object" obj))))))
> +    (put-char port #\}))
> +  (define (write-array v)
> +    (put-char port #\[)
> +    (match (vector-length v)
> +      (0 (values))
> +      (n
> +       (write-value (vector-ref v 0))
> +       (do ((i 1 (1+ i)))
> +           ((= i n))
> +         (put-char port #\,)
> +         (write-value (vector-ref v i)))))

I suppose the above is more efficient than a for-each loop?  I'd be
curious to see it profiled, if you still have data.  At least now I see
than for > 100k, vector-ref is faster than list-ref, which probably
explains why you went with vectors (could still be an implementation
detail with the list->vector call left in the writer though, in my
opinion).

> +    (put-char port #\]))
> +  (define (write-number x)
> +    (if (or (exact-integer? x)
> +            (and (real? x)
> +                 (inexact? x)
> +                 ;; NaNs and infinities are not allowed.
> +                 (not (or (nan? x) (inf? x)))))
> +        ;; Scheme's string representations of exact integers and floats
> +        ;; are compatible with JSON.
> +        (put-string port (number->string x))
> +        (fail "invalid number" x)))
> +  (define (write-value x)
> +    (match x
> +      (#t (put-string port "true"))
> +      (#f (put-string port "false"))
> +      ('null (put-string port "null"))
> +      (() (put-string port "{}"))
> +      ((? pair?) (write-object x))
> +      ((? vector?) (write-array x))
> +      ((? string?) (write-string x))
> +      ((? number?) (write-number x))
> +      (_ (fail "invalid value" x))))
> +  (write-value exp))

Phew.  That's a pretty low-level parser!  I hope it's fast, otherwise it
seems it'd be more concise/fun/maintainable to devise a PEG-based one,
which appears to be doable for JSON, from what I've read.  Perhaps
sprinkle with a few performance-related comments where such concerns
impacted the design choices, so that we can remember and retest/reverify
these in the future when Guile evolves.

> diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
> index 6014b1f1f..00afea142 100644
> --- a/test-suite/Makefile.am
> +++ b/test-suite/Makefile.am
> @@ -73,6 +73,7 @@ SCM_TESTS = tests/00-initial-env.test		\
>  	    tests/iconv.test			\
>  	    tests/import.test			\
>  	    tests/interp.test			\
> +	    tests/json.test			\
>  	    tests/keywords.test			\
>  	    tests/list.test			\
>  	    tests/load.test			\
> diff --git a/test-suite/tests/json.test b/test-suite/tests/json.test
> new file mode 100644
> index 000000000..f92eeccec
> --- /dev/null
> +++ b/test-suite/tests/json.test
> @@ -0,0 +1,154 @@
> +;;;; json.test --- test JSON reader/writer     -*- scheme -*-
> +;;;;
> +;;;; Copyright (C) 2015 Free Software Foundation, Inc.
> +;;;;
> +;;;; This library is free software; you can redistribute it and/or
> +;;;; modify it under the terms of the GNU Lesser General Public
> +;;;; License as published by the Free Software Foundation; either
> +;;;; version 3 of the License, or (at your option) any later version.
> +;;;;
> +;;;; This library is distributed in the hope that it will be useful,
> +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +;;;; Lesser General Public License for more details.
> +;;;;
> +;;;; You should have received a copy of the GNU Lesser General Public
> +;;;; License along with this library; if not, write to the Free Software
> +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> +
> +(define-module (test-suite test-json)
> +  #:use-module (test-suite lib)
> +  #:use-module (web json))
> +
> +;;;
> +;;; Reader
> +;;;
> +
> +(define (read-json-string str)
> +  (call-with-input-string str read-json))
> +
> +(define (json-read=? str x)
> +  (= x (read-json-string str)))
> +
> +(define (json-read-eq? str x)
> +  (eq? x (read-json-string str)))
> +
> +(define (json-read-equal? str x)
> +  (equal? x (read-json-string str)))
> +
> +(define (json-read-string=? str x)
> +  (string=? x (read-json-string str)))
> +
> +(with-test-prefix "read-json"
> +  ;; Keywords
> +  (pass-if (json-read-eq? "true" #t))
> +  (pass-if (json-read-eq? "false" #f))
> +  (pass-if (json-read-eq? "null" 'null))
> +  ;; Numbers
> +  (pass-if (json-read=? "0" 0))
> +  (pass-if (json-read=? "-0" 0))
> +  (pass-if (json-read=? "0.0" 0.0))
> +  (pass-if (json-read=? "-0.0" -0.0))
> +  (pass-if (json-read=? "0.1" 0.1))
> +  (pass-if (json-read=? "1.234" 1.234))
> +  (pass-if (json-read=? "1" 1))
> +  (pass-if (json-read=? "-1" -1))
> +  (pass-if (json-read=? "1.1" 1.1))
> +  (pass-if (json-read=? "1e2" 1e2))
> +  (pass-if (json-read=? "1.1e2" 1.1e2))
> +  (pass-if (json-read=? "1.1e-2" 1.1e-2))
> +  (pass-if (json-read=? "1.1e+2" 1.1e2))
> +  ;; Extraneous zeroes in fraction
> +  (pass-if (json-read=? "1.000" 1))
> +  (pass-if (json-read=? "1.5000" 1.5))
> +  ;; Extraneous zeroes in exponent
> +  (pass-if (json-read=? "1.1e000" 1.1))
> +  (pass-if (json-read=? "1.1e-02" 1.1e-2))
> +  (pass-if (json-read=? "1.1e+02" 1.1e2))
> +  ;; Strings
> +  (pass-if (json-read-string=? "\"foo\"" "foo"))
> +  ;; Escape codes
> +  (pass-if (json-read-string=? "\"\\\"\"" "\""))
> +  (pass-if (json-read-string=? "\"\\\\\"" "\\"))
> +  (pass-if (json-read-string=? "\"\\/\"" "/"))
> +  (pass-if (json-read-string=? "\"\\b\"" "\b"))
> +  (pass-if (json-read-string=? "\"\\f\"" "\f"))
> +  (pass-if (json-read-string=? "\"\\n\"" "\n"))
> +  (pass-if (json-read-string=? "\"\\r\"" "\r"))
> +  (pass-if (json-read-string=? "\"\\t\"" "\t"))
> +  ;; Unicode in hexadecimal format
> +  (pass-if (json-read-string=? "\"\\u12ab\"" "\u12ab"))
> +  ;; Objects
> +  (pass-if (json-read-equal? "{}" '()))
> +  (pass-if (json-read-equal? "{ \"foo\": \"bar\", \"baz\": \"frob\"}"
> +                             '(("foo" . "bar") ("baz" . "frob"))))
> +  ;; Nested objects
> +  (pass-if (json-read-equal? "{\"foo\":{\"bar\":\"baz\"}}"
> +                             '(("foo" . (("bar" . "baz"))))))
> +  ;; Arrays
> +  (pass-if (json-read-equal? "[]" #()))
> +  (pass-if (json-read-equal? "[1, 2, \"foo\"]"
> +                             #(1 2 "foo")))
> +  ;; Nested arrays
> +  (pass-if (json-read-equal? "[1, 2, [\"foo\", \"bar\"]]"
> +                             #(1 2 #("foo" "bar"))))
> +  ;; Arrays and objects nested within each other
> +  (pass-if (json-read-equal? "{\"foo\":[{\"bar\":true},{\"baz\":[1,2,3]}]}"
> +                             '(("foo" . #((("bar" . #t))
> +                                          (("baz" . #(1 2 3))))))))
> +  ;; Leading whitespace
> +  (pass-if (json-read-eq? "\t\r\n true" #t)))

> +;;;
> +;;; Writer
> +;;;
> +
> +(define (write-json-string exp)
> +  (call-with-output-string
> +   (lambda (port)
> +     (write-json exp port))))
> +
> +(define (json-write-string=? exp str)
> +  (string=? str (write-json-string exp)))
> +
> +(with-test-prefix "write-json"
> +  ;; Keywords
> +  (pass-if (json-write-string=? #t "true"))
> +  (pass-if (json-write-string=? #f "false"))
> +  (pass-if (json-write-string=? 'null "null"))
> +  ;; Numbers
> +  (pass-if (json-write-string=? 0 "0"))
> +  (pass-if (json-write-string=? 0.0 "0.0"))
> +  (pass-if (json-write-string=? 0.1 "0.1"))
> +  (pass-if (json-write-string=? 1 "1"))
> +  (pass-if (json-write-string=? -1 "-1"))
> +  (pass-if (json-write-string=? 1.1 "1.1"))
> +  ;; Strings
> +  (pass-if (json-write-string=? "foo" "\"foo\""))
> +  ;; Escape codes
> +  (pass-if (json-write-string=? "\"" "\"\\\"\""))
> +  (pass-if (json-write-string=? "\\" "\"\\\\\""))
> +  (pass-if (json-write-string=? "/" "\"\\/\""))
> +  (pass-if (json-write-string=? "\b" "\"\\b\""))
> +  (pass-if (json-write-string=? "\f" "\"\\f\""))
> +  (pass-if (json-write-string=? "\n" "\"\\n\""))
> +  (pass-if (json-write-string=? "\r" "\"\\r\""))
> +  (pass-if (json-write-string=? "\t" "\"\\t\""))
> +  ;; Objects
> +  (pass-if (json-write-string=? '() "{}"))
> +  (pass-if (json-write-string=? '(("foo" . "bar") ("baz" . "frob"))
> +                                "{\"foo\":\"bar\",\"baz\":\"frob\"}"))
> +  ;; Nested objects
> +  (pass-if (json-write-string=? '(("foo" . (("bar" . "baz"))))
> +                                "{\"foo\":{\"bar\":\"baz\"}}"))
> +  ;; Arrays
> +  (pass-if (json-write-string=? #() "[]"))
> +  (pass-if (json-write-string=? #(1 2 "foo")
> +                                "[1,2,\"foo\"]"))
> +  ;; Nested arrays
> +  (pass-if (json-write-string=? #(1 2 #("foo" "bar"))
> +                                "[1,2,[\"foo\",\"bar\"]]"))
> +  ;; Arrays and objects nested in each other
> +  (pass-if (json-write-string=? '(("foo" . #((("bar" . #t))
> +                                             (("baz" . #(1 2))))))
> +                                "{\"foo\":[{\"bar\":true},{\"baz\":[1,2]}]}")))

Neat.  Nitpick: perhaps add a trailing '.' after each stand-alone
comments, to follow existing conventions.

I hope my armchair commentary is of some use :-).

Thanks again for working on a JSON parser/writer for Guile.

-- 
Thanks,
Maxim




Information forwarded to bug-guile@HIDDEN:
bug#77762; Package guile. Full text available.

Message received at 77762 <at> debbugs.gnu.org:


Received: (at 77762) by debbugs.gnu.org; 14 Apr 2025 04:21:43 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Apr 14 00:21:43 2025
Received: from localhost ([127.0.0.1]:45164 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1u4BKI-000109-Sj
	for submit <at> debbugs.gnu.org; Mon, 14 Apr 2025 00:21:43 -0400
Received: from mugam.systemreboot.net ([139.59.75.54]:47266)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <arunisaac@HIDDEN>)
 id 1u4BKE-0000zk-1B
 for 77762 <at> debbugs.gnu.org; Mon, 14 Apr 2025 00:21:40 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=systemreboot.net;
 s=default; t=1744604482;
 h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
 to:to:cc:cc:mime-version:mime-version:content-type:content-type:
 in-reply-to:in-reply-to:references:references;
 bh=Lnmr8KtWckrjhizRcmU594WrPF8Z3n1dGgqgnt73NBY=;
 b=eXtUJ+9dc3Ci6qacAb/RQuH1VGv/JlipXPcDoBCRvxxbZFIduScNIjQGLbUfI9v9GPnZKC
 XBCX5ZaH65vEtaka9DOs2yK1+zSdkVa92gT6DhS6aboEEX7TmeT6HVoLjwbgHftgYjzejM
 Zz5T/nTwONW+Smh6agD6bkyGwxWPR4svHO8kj41nijuym+hRI6K015sL+MjfYfCrTOvNhy
 7brxhZYmjAqybZ9KT+MxixnlHcnGnsCq8SIWVpc47+knSRugKT4Sh5lTMYYUHA0mawU3F1
 t8xe8kgOu1eQBX9iKIicDDbg4HCY9mMyVBNaiFmvMVVNVl/lnC6vYdhahbgr7Q==
Received: from localhost (<unknown> [192.168.2.1])
 by mugam.systemreboot.net (OpenSMTPD) with ESMTPSA id c3b7bd80
 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); 
 Mon, 14 Apr 2025 04:21:21 +0000 (UTC)
From: Arun Isaac <arunisaac@HIDDEN>
To: "Thompson, David" <dthompson2@HIDDEN>
Subject: Re: bug#77762: [PATCH] web: Add JSON module.
In-Reply-To: <CAJ=Rwfbzg9nD1hJw5NP_EEurCQBBYi8DJg6cFO-DT5GNdGz6Kw@HIDDEN>
References: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
 <87ikn8et6a.fsf@HIDDEN>
 <CAJ=Rwfbzg9nD1hJw5NP_EEurCQBBYi8DJg6cFO-DT5GNdGz6Kw@HIDDEN>
Date: Mon, 14 Apr 2025 05:21:16 +0100
Message-ID: <87zfgjcr0j.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 77762
Cc: 77762 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)


Hi David,

> I mean, Guile doesn't *need* to include anything, but JSON is one of
> the most common serialization formats around. Most language
> implementations ship with a JSON library.  Guile already has a suite
> of web modules and so this fits right in with those.  Over the years
> I've noticed many users, especially new users, asking why Guile
> doesn't ship with JSON support. I don't think you should have to
> install an external library for something so common. In my own
> projects I prefer to just check a JSON module into the source tree so
> I don't have to add an additional dependency. guile-json is a good
> library with a bunch of bells and whistles, but I think most people
> just want basic read/write procedures and would be happy to take them
> for granted with their Guile installation.

Thanks for the explanation. That sounds reasonable to me. But, I am a
bit biased in favour of keeping guile small and portable. :-) Anyway,
I'll let the guile maintainers make a call here.

>> > API that can read/write JSON to/from a port using only Scheme data
>> > types that have read syntax (i.e. no hash tables like guile-json).
>>
>> guile-json does not use hash tables. guile-json uses association lists.
>> I believe the decision to use hash tables was reversed many years ago.
>
> Heh, shows how long it's been since I last used guile-json. Glad
> that's changed. :)

And, the reversal of that decision was thanks to your objection, as a
matter of fact! :-)

https://yhetil.org/guile-user/CAJ=RwfZgUg6-bCoYJR-v48ywCROEMu94NrSGrNKjzJB0foCfTQ@HIDDEN/
https://yhetil.org/guile-user/CA+XASoVmEy1Rt7w=pM21JkYL6dYJeGtW0_HjpnUa_eV5pGcvkQ@HIDDEN/

Cheers!
Arun




Information forwarded to bug-guile@HIDDEN:
bug#77762; Package guile. Full text available.

Message received at 77762 <at> debbugs.gnu.org:


Received: (at 77762) by debbugs.gnu.org; 13 Apr 2025 02:14:15 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Apr 12 22:14:15 2025
Received: from localhost ([127.0.0.1]:35393 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1u3mrM-0001P9-KY
	for submit <at> debbugs.gnu.org; Sat, 12 Apr 2025 22:14:14 -0400
Received: from mail-ed1-x529.google.com ([2a00:1450:4864:20::529]:43095)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <dthompson2@HIDDEN>)
 id 1u3mr8-0001M0-69
 for 77762 <at> debbugs.gnu.org; Sat, 12 Apr 2025 22:14:07 -0400
Received: by mail-ed1-x529.google.com with SMTP id
 4fb4d7f45d1cf-5ec9d24acfbso7609536a12.0
 for <77762 <at> debbugs.gnu.org>; Sat, 12 Apr 2025 19:13:58 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=worcester.edu; s=google; t=1744510432; x=1745115232; darn=debbugs.gnu.org;
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:from:to:cc:subject:date
 :message-id:reply-to;
 bh=FANGbrfG7LYnqzOL/CRvMorjNLx8OOlvZ8B80WdEQPE=;
 b=Dg8zb5QWPIc8FwTy70UoLMhdj2oCWewEV6IhP+EMqsL6iClQzV3BTXmqGbn7YD/Z0e
 L3hZAwPgNk9Wkl8cO91R3p8bcfmngIJQv3b1c+nFYNsulqMAU/HPs1k5Mq+UcI2LHT5h
 t1GzalA2z34xeqmAfJfXNSeLG78SZvgfqIiTY=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1744510432; x=1745115232;
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=FANGbrfG7LYnqzOL/CRvMorjNLx8OOlvZ8B80WdEQPE=;
 b=PbRo349X943/yUKttTevQDAluzCawzRV6Ov+cvac4SgRn3fhpS8FfdGB5EiS7rx8u5
 9eJ0AS3pzZQn4IuxpTT1gWx/W/t/IQPPS5ndQhYbFMyA+2zPypfvfZqLhDGuxP7YP7cy
 HWsuIc+hmT6et9uW6Ux/1aVVovuEcp/EYB3CB1HS2dPj0iU6mOe4q23yoeFq8Y/EApLz
 cxJqr4QoIJQ++oIuyGs+JQ8NBO5ZUm+g+W3xVZ4h1Wo9ytQfx89UxE1Lqbi1prFuh5pg
 gUjcEoiNhU9/GjYiY0Uau+dhYTlzp8ARgAa5ZhE1TNNmEhCqIwn7bTXnIu9zEPCkYA0M
 M5/g==
X-Gm-Message-State: AOJu0YzqAnb7fBxTMDnP43+tZMvKJRCHoUzbbGkzTuh1tSUv9SB+jZ0+
 PIdP2ocmLPFM5hJH6smR2evqETTPUGNUmSo9mDPNOuyo3pU1QGNtEjhQZ+8l6OePaPXfXpzt5dv
 5mxpMM190snhXlhnUNJBcHjls2W5hZBnLHUnbjyUYGdcm63KU
X-Gm-Gg: ASbGncu7qyiL4X5nGtTYKJmJ+rig1BuCf3WB0UbbybdhHIYCjx+a2NoY11ix8jO9u7y
 dqnDom8zpwqOAlW+FmGgpEjRzK82YoltQMmS1J4WV8wjtpjqoIgtV5p7D0d9PstKHnu34gQ7kEs
 1Eh5jr4XJ8epwcPt85o2wgswMorD8/NGXUFGmb
X-Google-Smtp-Source: AGHT+IFg6dWYspulihOVM59mMZraPsUM7W/fr5qVd90kqcLhX0nObA5S0bK6UkSPChMEz98JYw6KzZviPFAIw1ex6qs=
X-Received: by 2002:a05:6402:3588:b0:5e0:6e6c:e2b5 with SMTP id
 4fb4d7f45d1cf-5f329fcaa01mr9762374a12.9.1744510431605; Sat, 12 Apr 2025
 19:13:51 -0700 (PDT)
MIME-Version: 1.0
References: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
 <87ikn8et6a.fsf@HIDDEN>
In-Reply-To: <87ikn8et6a.fsf@HIDDEN>
From: "Thompson, David" <dthompson2@HIDDEN>
Date: Sat, 12 Apr 2025 22:13:40 -0400
X-Gm-Features: ATxdqUGgTYOCxkBSv0Eb2JWChuJ4x0Bkv693Z0PWTd3eyWZxHTt9106xlBu0e9c
Message-ID: <CAJ=Rwfbzg9nD1hJw5NP_EEurCQBBYi8DJg6cFO-DT5GNdGz6Kw@HIDDEN>
Subject: Re: bug#77762: [PATCH] web: Add JSON module.
To: Arun Isaac <arunisaac@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 77762
Cc: 77762 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hi Arun,

On Sat, Apr 12, 2025 at 9:39=E2=80=AFPM Arun Isaac <arunisaac@systemreboot.=
net> wrote:
>
> Thanks for the patch. I'm just trying to understand: Why do we need a
> JSON module in guile itself? Isn't guile-json, the way it is as an
> external library, good enough?

I mean, Guile doesn't *need* to include anything, but JSON is one of
the most common serialization formats around. Most language
implementations ship with a JSON library.  Guile already has a suite
of web modules and so this fits right in with those.  Over the years
I've noticed many users, especially new users, asking why Guile
doesn't ship with JSON support. I don't think you should have to
install an external library for something so common. In my own
projects I prefer to just check a JSON module into the source tree so
I don't have to add an additional dependency. guile-json is a good
library with a bunch of bells and whistles, but I think most people
just want basic read/write procedures and would be happy to take them
for granted with their Guile installation.

> > API that can read/write JSON to/from a port using only Scheme data
> > types that have read syntax (i.e. no hash tables like guile-json).
>
> guile-json does not use hash tables. guile-json uses association lists.
> I believe the decision to use hash tables was reversed many years ago.

Heh, shows how long it's been since I last used guile-json. Glad
that's changed. :)

- Dave




Information forwarded to bug-guile@HIDDEN:
bug#77762; Package guile. Full text available.

Message received at 77762 <at> debbugs.gnu.org:


Received: (at 77762) by debbugs.gnu.org; 13 Apr 2025 01:39:43 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Apr 12 21:39:43 2025
Received: from localhost ([127.0.0.1]:35053 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1u3mJy-0004c3-Vd
	for submit <at> debbugs.gnu.org; Sat, 12 Apr 2025 21:39:43 -0400
Received: from mugam.systemreboot.net ([139.59.75.54]:60204)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <arunisaac@HIDDEN>)
 id 1u3mJv-0004b3-2M
 for 77762 <at> debbugs.gnu.org; Sat, 12 Apr 2025 21:39:40 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=systemreboot.net;
 s=default; t=1744508371;
 h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
 to:to:cc:mime-version:mime-version:content-type:content-type:
 in-reply-to:in-reply-to:references:references;
 bh=qCzhvYJSr38nh5VLyOAgsg3EhjSdncJxnGaJ220qSsA=;
 b=i78pFtr0T3PBut/Gon4L+/MY69duv144MWOUxXADg5Egk/IdM4Opl8Gb9hlBUPPHbJVJxC
 qGDTeqCHjz77dRGK88NQ/65suMWKdu+GFwsl2sxgQ/Ipt9DoVVCloYV8w6P+ctesGY/wC1
 Kp7nlsutwWrNlH+wMZx+KXrNZJgw+e8cqY+JGZ+kPGRieWlTMYtgh+eT7xjYRyX+rzbv65
 oCdOp0yf9l1xx0bal0Sfp9AjGFh4+O04lpARNRg2ScETsf5J0g3FWSQS0FHWLTD+TXYxgc
 tL9erv65r6YayYWvO3OIx93uFKqgqLXKJAPfAnsE+Nls6x3nz+5uRYRJIj/kow==
Received: from localhost (<unknown> [192.168.2.1])
 by mugam.systemreboot.net (OpenSMTPD) with ESMTPSA id 34303bb5
 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); 
 Sun, 13 Apr 2025 01:39:30 +0000 (UTC)
From: Arun Isaac <arunisaac@HIDDEN>
To: "Thompson, David" <dthompson2@HIDDEN>, 77762 <at> debbugs.gnu.org
Subject: Re: bug#77762: [PATCH] web: Add JSON module.
In-Reply-To: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
References: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
Date: Sun, 13 Apr 2025 02:39:25 +0100
Message-ID: <87ikn8et6a.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 77762
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)


Hi David,

Thanks for the patch. I'm just trying to understand: Why do we need a
JSON module in guile itself? Isn't guile-json, the way it is as an
external library, good enough?

> API that can read/write JSON to/from a port using only Scheme data
> types that have read syntax (i.e. no hash tables like guile-json).

guile-json does not use hash tables. guile-json uses association lists.
I believe the decision to use hash tables was reversed many years ago.

Cheers!
Arun




Information forwarded to bug-guile@HIDDEN:
bug#77762; Package guile. Full text available.

Message received at 77762 <at> debbugs.gnu.org:


Received: (at 77762) by debbugs.gnu.org; 12 Apr 2025 16:04:36 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Apr 12 12:04:35 2025
Received: from localhost ([127.0.0.1]:57930 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1u3dLO-0002sp-Nn
	for submit <at> debbugs.gnu.org; Sat, 12 Apr 2025 12:04:35 -0400
Received: from mail-ed1-x52c.google.com ([2a00:1450:4864:20::52c]:51518)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <dthompson2@HIDDEN>)
 id 1u3dLM-0002r2-3L
 for 77762 <at> debbugs.gnu.org; Sat, 12 Apr 2025 12:04:33 -0400
Received: by mail-ed1-x52c.google.com with SMTP id
 4fb4d7f45d1cf-5efe8d9ebdfso5397714a12.3
 for <77762 <at> debbugs.gnu.org>; Sat, 12 Apr 2025 09:04:32 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=worcester.edu; s=google; t=1744473865; x=1745078665; darn=debbugs.gnu.org;
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:from:to:cc:subject:date
 :message-id:reply-to;
 bh=0h2SSUCFwvb9mLzPkVcR1iVd/WZ7NzERZL6u7UjO8Hw=;
 b=Fp6lBGnS5HKGTp3KMxdbcjZsLgedoISgWY9JCdbaaRcgvXiMVqAH21SNoGDZ/mEgzP
 U4cvGbXPtje/THJUFuRv0UUrrle0sVbr90T0sAzanir+PiWsJQ91GsTux4dPPFwQBR8R
 gdfMWqjVpVLsGnlomnSqrX3fzNs98SQUoJsKg=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1744473865; x=1745078665;
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=0h2SSUCFwvb9mLzPkVcR1iVd/WZ7NzERZL6u7UjO8Hw=;
 b=DUgDB4jwyFid2TBkuZfWwE1Pkp4DgCyx42Ix2ND68QmzUZmPLUUSgW+68K+dpgUsEG
 T43uSQbb5gAnyS+x5NDXN5FBGbyuqLAXk/Zf4orou91PtvIlTsAd/YDFTxebwOGfssRh
 w/69EFBlDvF/t4yySxlHKGXakwga5NmUyBuL9g19w8QxHp3QsPhq7B4HAzJSgPyWXb3i
 30i+ey417D7SU4Gk0Th7dvGHXlKYNLA79DpzdPWwbe4VZxEy8plFP4ANogbWlHG4gGxS
 N27cCagCYqF7dJQE6nhK8/J2ZTAE7zjvIyAcvTYwjmTgP+hAfHfjLbc7bY8PjRePQ50q
 KWzw==
X-Gm-Message-State: AOJu0YyE3jSWrr7RvR8FrRewlCWAcuB1QFF+aZSMSvfOfNRGFD/Bb/CV
 ITWt4EHWfqgh616bSr8IrzqMEtyM1yuCiliwUFVmb4tFd+PTEnZXTuU9SRyt5Pbr0QGVk3ZeCyR
 W4pgyRhbkwZwzRXbW+moXDThcTOTyGoNTQqVWkw==
X-Gm-Gg: ASbGncvvqldphTHz2eC7G4UbLpotrzBeRobYYOd5AStx4Fb6DZ0Pc3QSNXsQ/PGe7px
 XvDpUAFkpm9QoAuIPxt7D0KASH7HvlKoulALm7dK6iZqzSDzkDZa/sS7d80mx9AojPwNHLER6+7
 iQCxPelKpBfFUqWHyLLLWEfDQUKkUMo6Jozyp8
X-Google-Smtp-Source: AGHT+IEgyk8bVlgxJz1uze4yJPhQfY1Hxm0rUd97or2iXXg02RenYAUh9Mv6VAOS67JUbR+mYPak0mdJSu45dTL93w4=
X-Received: by 2002:a05:6402:84d:b0:5ee:497:d4f3 with SMTP id
 4fb4d7f45d1cf-5f370115287mr5147317a12.33.1744473865475; Sat, 12 Apr 2025
 09:04:25 -0700 (PDT)
MIME-Version: 1.0
References: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
 <87v7r92wtu.fsf@HIDDEN>
In-Reply-To: <87v7r92wtu.fsf@HIDDEN>
From: "Thompson, David" <dthompson2@HIDDEN>
Date: Sat, 12 Apr 2025 12:04:14 -0400
X-Gm-Features: ATxdqUHiSvR8JSZaMW8uyrO-JHt5bHgYmVVQ5lixwMlb1vwBQZJ2ZrJC0WpkwyA
Message-ID: <CAJ=RwfZGCCq5FpkcFWasKMY2ip_cCT4pTAb1qZjDAVhvVvDTuQ@HIDDEN>
Subject: Re: bug#77762: [PATCH] web: Add JSON module.
To: Tomas Volf <~@wolfsden.cz>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 77762
Cc: 77762 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On Sat, Apr 12, 2025 at 12:01=E2=80=AFPM Tomas Volf <~@wolfsden.cz> wrote:
>
> > - null is the symbol 'null
>
> Out of curiosity, what are your thoughts about using #nil instead?

My original patch from 10 years ago did this. Mark Weaver then
explained to me that #nil was added specifically for the purpose of
supporting Emacs Lisp on the Guile VM and shouldn't be used in Scheme
code. The symbol 'null works well because there is no symbol type in
JSON so there's no ambiguity.

- Dave




Information forwarded to bug-guile@HIDDEN:
bug#77762; Package guile. Full text available.

Message received at 77762 <at> debbugs.gnu.org:


Received: (at 77762) by debbugs.gnu.org; 12 Apr 2025 16:01:26 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Apr 12 12:01:25 2025
Received: from localhost ([127.0.0.1]:57926 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1u3dIJ-0002K4-ND
	for submit <at> debbugs.gnu.org; Sat, 12 Apr 2025 12:01:25 -0400
Received: from wolfsden.cz ([37.205.8.62]:57318)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <~@wolfsden.cz>) id 1u3dIG-0002J6-08
 for 77762 <at> debbugs.gnu.org; Sat, 12 Apr 2025 12:01:21 -0400
Received: by wolfsden.cz (Postfix, from userid 104)
 id 3B0FD37E842; Sat, 12 Apr 2025 16:01:18 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail;
 t=1744473678; bh=N/qr0zkJk00026f5NQs4w8EpgXwymr9ilXpfGL+5xiA=;
 h=From:To:Cc:Subject:In-Reply-To:References:Date;
 b=CJNUKEQP1x6q10xhbszDS5jSMWOmYKiDoprBYvF+/zfYOYC7cwIdVSswF59N010AP
 5J7dloROIckFzx2TGncx475MbMr1CFohWc1bM0dI4OwIMrXWG0ykcXzpnaKONDUaIu
 HMQ/gI0ztGlDhRm8wR5x5A53uO/z4/dv8oeb9PLTqEmNetV/2Ld5m5YyNfg0FmYzFh
 mnShzYbHwUYtR3f8XiLllcx86Qc8nbLw8DWwNhsDKQCjT/CLnUwYipdWqX28kd5Uc0
 m/aJoPvB9rNn9pMAoHv3hbMGEuaQu4mTHjrpuTcoVHeCfWN+8fAIGEOdI3hBJLFBmO
 bFidFeoE42KFL+I5cG7y9pcK2RGt0innEV0Kr/hDQytEKkARXBakfVCWFsnJVxZuZX
 svkrjJGBf6jdcKAIY5WG63pQnkE57P1oo6Kns5FCJwAG8pskkrX0CEjm6244wJzYR/
 cfaA3sftmIOnbMfJGR+f3u4Rxhrg5XlJ6i1mhnvXC6iCQgEy6J+wJZM7+Ewb7FrZjN
 zihkMoSTsPUsHJzaIjbUU39niNhipufQS6rypyyocWCnHNjgNgLzZqrKgdiWsJSDM5
 Dl+2GjlOmCCsCm3y8fY7dTAxfHiDl3EDYhmmJNCQ1Ly0unRiksnG/hiEpFZOOWU3oQ
 /KApXP7EYJuEI6qqhhzbE/ws=
X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on wolfsden
X-Spam-Level: 
X-Spam-Status: No, score=-3.1 required=5.0 tests=ALL_TRUSTED,BAYES_00,
 DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,URIBL_BLOCKED
 autolearn=ham autolearn_force=no version=3.4.6
Received: from localhost (unknown [128.0.188.242])
 by wolfsden.cz (Postfix) with ESMTPSA id 49A5D37E2E6;
 Sat, 12 Apr 2025 16:01:17 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail;
 t=1744473677; bh=N/qr0zkJk00026f5NQs4w8EpgXwymr9ilXpfGL+5xiA=;
 h=From:To:Cc:Subject:In-Reply-To:References:Date;
 b=B0Q8Dqr4RLLMVuoeMPlNcmvI2eibbABC2diF4cSrSWKpBu0g4PbORP0C8SIcoxOwM
 wwA+u2U0WnZnQ8lgc+UifSscSCqG3BjP1l9VVJg4supYQBIhKis+RgJOI9HmgE+djx
 9VpP9pb7zNVog+VcrxsAUr0weTXhoEFoHAwIRB4vHwXPCaTVdn8U0ULvgzdS/naxbH
 XLfK00xLQPBt+7yfHF6bXW2sZPawBMGpIBbS+6jM4sEhi7FXUETLY3AEVuoGa9kz9D
 cNj3vnyrCtvXJO7BR6wMkEbSe942AzCrYhVisvMiQVfqwaVBzzCdgCiiREAYHSP0h3
 /uJ7pD1S6EJ+lST1Mm+i3tGFhuC5oalr9QlpwLahvexx87FTZBfB1wld/WCQqt4Ml2
 u36xMf8x7FlszfYZPhVckS7fzXVBSW7RXQM1p+cWegwg2cPPO46q+x4JAQhdq24Aly
 4e5kAos7eFk6i5IcOi0RngV1Em5ne+ldTt1oHSCUpqbXwaZHwWy2HHKkVDUf3vTRjC
 Q/+pkm5aAssh4VoQUfgRFKCXnc8AJbH0CXol/oIKIGtYjW8gZYs4rytq93gA+8Cooa
 aMUOk8KoNQlugf977HX7QOdoW4H1g2hjGCJM4dCzSnXG06CUPqlA7bkx4tLWm294QW
 6+cNZ393CAUDnJdZgmGPGFFs=
From: Tomas Volf <~@wolfsden.cz>
To: "Thompson, David" <dthompson2@HIDDEN>
Subject: Re: bug#77762: [PATCH] web: Add JSON module.
In-Reply-To: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
 (David Thompson's message of "Sat, 12 Apr 2025 09:14:31 -0400")
References: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
Date: Sat, 12 Apr 2025 18:01:17 +0200
Message-ID: <87v7r92wtu.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 77762
Cc: 77762 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

> - null is the symbol 'null

Out of curiosity, what are your thoughts about using #nil instead?

Tomas

-- 
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.




Information forwarded to bug-guile@HIDDEN:
bug#77762; Package guile. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 12 Apr 2025 13:15:15 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Apr 12 09:15:14 2025
Received: from localhost ([127.0.0.1]:54432 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1u3ahP-0003XN-U5
	for submit <at> debbugs.gnu.org; Sat, 12 Apr 2025 09:15:14 -0400
Received: from lists.gnu.org ([2001:470:142::17]:39282)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <dthompson2@HIDDEN>)
 id 1u3ahG-0003TA-R5
 for submit <at> debbugs.gnu.org; Sat, 12 Apr 2025 09:15:04 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <dthompson2@HIDDEN>)
 id 1u3ah7-0004lH-AI
 for bug-guile@HIDDEN; Sat, 12 Apr 2025 09:14:49 -0400
Received: from mail-ed1-x52e.google.com ([2a00:1450:4864:20::52e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <dthompson2@HIDDEN>)
 id 1u3ah4-0004D6-3g
 for bug-guile@HIDDEN; Sat, 12 Apr 2025 09:14:49 -0400
Received: by mail-ed1-x52e.google.com with SMTP id
 4fb4d7f45d1cf-5e5e8274a74so4496813a12.1
 for <bug-guile@HIDDEN>; Sat, 12 Apr 2025 06:14:44 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=worcester.edu; s=google; t=1744463683; x=1745068483; darn=gnu.org;
 h=to:subject:message-id:date:from:mime-version:from:to:cc:subject
 :date:message-id:reply-to;
 bh=BcgC/Mops6wg+yipKvzZTZ700t8Xmk4QHNI5aXMVIvo=;
 b=KYMbzC2xJ8i0XyD4hOvZfIXaXYJ4s5n03SMs+kFZ1mJx+DG00MAtYUhChevHziFUb/
 XbeYslRzAGxoqwSqQIBJmruWV/hbFcqShQr9p7XsF2uJH4M1rGdimJ5Nwj+RSBEkfN/Q
 cpFFVLDH8VWzwLjyv+yEUPpbhQ6An5A3rQhaY=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1744463683; x=1745068483;
 h=to:subject:message-id:date:from:mime-version:x-gm-message-state
 :from:to:cc:subject:date:message-id:reply-to;
 bh=BcgC/Mops6wg+yipKvzZTZ700t8Xmk4QHNI5aXMVIvo=;
 b=xFN6Sjto1YyL4ml8mikaXJOj+GFgIW79utr23DUF8W/r3SbyavaLbNY6YgpRBqzBxb
 PSbCJbCydkA/uh1BRyJiv5A6fmqAyAlsGH5r83L8LKBhcC1h77ovLIB7EHOHslA0jruZ
 cFcur9kSMUTlTi0IkNRk5enV0AcZ06+4y7gLSDEaAFBq/KMNNwTEFdgOBe2DNoa2otWN
 zIuILrpJyeVyOYgkU/yG3ooPZwei6MgOpIiSe1Q8jwdVwPqx1bz9G/iuATMaf4MH2y03
 L7ROcDGCN808cTeVY3At+oRRe0VC8uMLklWDAX+LJGWbtlk+K8kQj0YMffFRg+ZYkACd
 GrDg==
X-Gm-Message-State: AOJu0YwwIFMjLjA5N5ffK4KZnQXdy+Y8/i0MQ+DIU6DlRAxPuj9v7e9M
 GdJgw0EcsdNQECGjRCj23kfyP61RPcHYY39x0eP3Rpkgl3qZhe3x8ubkESzJf1obpfiJ7O+hk5Y
 abW5XXWruS8TTDcuBNDDowC2JTsM9umgOnnuI5SuYDKoTJk87Q2Y=
X-Gm-Gg: ASbGnct2fgclU4VYkoWEidmyeY77QVFsHLW+NVMbm3O4gYFytGF+VYS01lnpnP36URu
 y0JZk1xyp2mzCMVnWMN9GlOkKUF1wKqn0daQCwQInBk/rcfl5Y5sjZdZHptpDCFROtbDXtbnAZU
 5SqbQXMzeegM++GT1FWWyVRb6G8thjRbdVVT6pH4WKmM5Pasg=
X-Google-Smtp-Source: AGHT+IHpOdS4WEK3yeYujBXWYhxTsWzssg/6PzzyzMIqN8oNGKzL0uyV92bhwW3fNcWa36OsaeIYBXq63mB7rVBbv1Y=
X-Received: by 2002:a05:6402:13d4:b0:5ed:c188:8e7e with SMTP id
 4fb4d7f45d1cf-5f370011ea9mr5642357a12.27.1744463682796; Sat, 12 Apr 2025
 06:14:42 -0700 (PDT)
MIME-Version: 1.0
From: "Thompson, David" <dthompson2@HIDDEN>
Date: Sat, 12 Apr 2025 09:14:31 -0400
X-Gm-Features: ATxdqUEINYzIWlbpAU5oETiN52wEyWYgMXEcpyoOZnTNqkIHbYmRGvFvqCH15Pw
Message-ID: <CAJ=RwfaqMQOsVY46sDTVusrwsUmmZDCE3TrU-MHVKq3OBOEmkg@HIDDEN>
Subject: [PATCH] web: Add JSON module.
To: "bug-guile@HIDDEN" <bug-guile@HIDDEN>
Content-Type: multipart/mixed; boundary="000000000000234de90632949a5a"
Received-SPF: pass client-ip=2a00:1450:4864:20::52e;
 envelope-from=dthompson2@HIDDEN; helo=mail-ed1-x52e.google.com
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,
 RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: submit
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.0 (/)

--000000000000234de90632949a5a
Content-Type: text/plain; charset="UTF-8"

Attached is a patch that adds a new (web json) module. Some may
remember that I submitted a patch back in 2015 (time flies, eh?) for
an (ice-9 json) module that never made it in. Well, 10 years is a long
time and Guile still doesn't have a built-in JSON module. Third party
libraries like guile-json and guile-sjson are available, the latter
being an adaptation of my original patch and the former remaining the
go-to library used by larger Guile projects like Guix. There's also
SRFI-180 (which sounds like a cool surfing trick!) which was published
in 2020 but the API is, in my opinion, overly complicated due to
generators and other things.  Anyway, JSON continues to be *the* data
interchange format of the web and Guile really ought to have a simple
API that can read/write JSON to/from a port using only Scheme data
types that have read syntax (i.e. no hash tables like guile-json).
This minimal, practical API is what my patch provides.  I've tried my
best to make it as efficient as possible.

I've settled on the following JSON<->Scheme data type mapping which is
nearly identical to SRFI-180 with the exception of object keys:

- true and false are #t and #f
- null is the symbol 'null
- numbers are either exact integers (fixnums and bignums) or inexact
reals (flonums, NaNs and infinities excluded)
- strings are strings
- arrays are vectors
- objects are association lists with string keys (SRFI-180 chose
symbols but JSON uses strings so strings feel the most honest)

Thanks in advance for the review,

- Dave

--000000000000234de90632949a5a
Content-Type: text/x-patch; charset="US-ASCII"; name="0001-web-Add-JSON-module.patch"
Content-Disposition: attachment; filename="0001-web-Add-JSON-module.patch"
Content-Transfer-Encoding: base64
Content-ID: <f_m9e8i3ls0>
X-Attachment-Id: f_m9e8i3ls0

RnJvbSAxMDRiNTdlMmE3YjRjYTQ3MDk2Y2I1MjRhZmY2ODhiMGFkYTQ5Zjk0IE1vbiBTZXAgMTcg
MDA6MDA6MDAgMjAwMQpGcm9tOiBEYXZpZCBUaG9tcHNvbiA8ZHRob21wc29uMkB3b3JjZXN0ZXIu
ZWR1PgpEYXRlOiBTYXQsIDEyIEFwciAyMDI1IDA4OjI3OjM1IC0wNDAwClN1YmplY3Q6IFtQQVRD
SF0gd2ViOiBBZGQgSlNPTiBtb2R1bGUuCgoqIG1vZHVsZS93ZWIvanNvbi5zY206IE5ldyBmaWxl
LgoqIGFtL2Jvb3RzdHJhcC5hbSAoU09VUkNFUyk6IEFkZCBpdC4KKiB0ZXN0LXN1aXRlL3Rlc3Rz
L2pzb24udGVzdDogTmV3IGZpbGUuCiogdGVzdC1zdWl0ZS9NYWtlZmlsZS5hbSAoU0NNX1RFU1RT
KTogQWRkIGl0LgoqIGRvYy9yZWYvd2ViLnRleGkgKCJKU09OIik6IE5ldyBzdWJzZWN0aW9uLgot
LS0KIGFtL2Jvb3RzdHJhcC5hbSAgICAgICAgICAgIHwgICAzICstCiBkb2MvcmVmL3dlYi50ZXhp
ICAgICAgICAgICB8ICA5MyArKysrKysrKysrKwogbW9kdWxlL3dlYi9qc29uLnNjbSAgICAgICAg
fCAzMDggKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwogdGVzdC1zdWl0ZS9N
YWtlZmlsZS5hbSAgICAgfCAgIDEgKwogdGVzdC1zdWl0ZS90ZXN0cy9qc29uLnRlc3QgfCAxNTQg
KysrKysrKysrKysrKysrKysrKwogNSBmaWxlcyBjaGFuZ2VkLCA1NTggaW5zZXJ0aW9ucygrKSwg
MSBkZWxldGlvbigtKQogY3JlYXRlIG1vZGUgMTAwNjQ0IG1vZHVsZS93ZWIvanNvbi5zY20KIGNy
ZWF0ZSBtb2RlIDEwMDY0NCB0ZXN0LXN1aXRlL3Rlc3RzL2pzb24udGVzdAoKZGlmZiAtLWdpdCBh
L2FtL2Jvb3RzdHJhcC5hbSBiL2FtL2Jvb3RzdHJhcC5hbQppbmRleCA5NjAyM2Q4M2QuLjY4MDZm
ZGE1ZCAxMDA2NDQKLS0tIGEvYW0vYm9vdHN0cmFwLmFtCisrKyBiL2FtL2Jvb3RzdHJhcC5hbQpA
QCAtNDI1LDcgKzQyNSw4IEBAIFNPVVJDRVMgPQkJCQkJXAogICB3ZWIvcmVzcG9uc2Uuc2NtCQkJ
CVwKICAgd2ViL3NlcnZlci5zY20JCQkJXAogICB3ZWIvc2VydmVyL2h0dHAuc2NtCQkJCVwKLSAg
d2ViL3VyaS5zY20KKyAgd2ViL3VyaS5zY20JCQkJCVwKKyAgd2ViL2pzb24uc2NtCiAKIEVMSVNQ
X1NPVVJDRVMgPQkJCQkJXAogICBsYW5ndWFnZS9lbGlzcC9ib290LmVsCmRpZmYgLS1naXQgYS9k
b2MvcmVmL3dlYi50ZXhpIGIvZG9jL3JlZi93ZWIudGV4aQppbmRleCA2MDdjODU1YjYuLjUzY2Ux
NDgyMCAxMDA2NDQKLS0tIGEvZG9jL3JlZi93ZWIudGV4aQorKysgYi9kb2MvcmVmL3dlYi50ZXhp
CkBAIC00MCw2ICs0MCw3IEBAIGJhY2suCiAqIFRyYW5zZmVyIENvZGluZ3M6OiAgICAgICAgICAg
IEhUVFAgVHJhbnNmZXIgQ29kaW5ncy4KICogUmVxdWVzdHM6OiAgICAgICAgICAgICAgICAgICAg
SFRUUCByZXF1ZXN0cy4KICogUmVzcG9uc2VzOjogICAgICAgICAgICAgICAgICAgSFRUUCByZXNw
b25zZXMuCisqIEpTT046OiAgICAgICAgICAgICAgICAgICAgICAgIFRoZSBKYXZhU2NyaXB0IE9i
amVjdCBOb3RhdGlvbi4KICogV2ViIENsaWVudDo6ICAgICAgICAgICAgICAgICAgQWNjZXNzaW5n
IHdlYiByZXNvdXJjZXMgb3ZlciBIVFRQLgogKiBXZWIgU2VydmVyOjogICAgICAgICAgICAgICAg
ICBTZXJ2aW5nIEhUVFAgdG8gdGhlIGludGVybmV0LgogKiBXZWIgRXhhbXBsZXM6OiAgICAgICAg
ICAgICAgICBIb3cgdG8gdXNlIHRoaXMgdGhpbmcuCkBAIC0xNDQ4LDYgKzE0NDksOTggQEAgUmV0
dXJuIEBjb2RleyN0fSBpZiBAdmFye3R5cGV9LCBhIHN5bWJvbCBhcyByZXR1cm5lZCBieQogQGVu
ZCBkZWZmbgogCiAKK0Bub2RlIEpTT04KK0BzdWJzZWN0aW9uIEpTT04KKworQGNpbmRleCBqc29u
CitAY2luZGV4ICh3ZWIganNvbikKKworQGV4YW1wbGUKKyh1c2UtbW9kdWxlcyAod2ViIGpzb24p
KQorQGVuZCBleGFtcGxlCisKK0phdmFTY3JpcHQgT2JqZWN0IE5vdGF0aW9uIChKU09OKSBpcyB0
aGUgbW9zdCBjb21tb24gZGF0YSBpbnRlcmNoYW5nZQorZm9ybWF0IG9uIHRoZSB3ZWIuICBJdCBp
cyB1YmlxdWl0b3VzIGluIEhUVFAgQVBJcyBhbmQgaGFzIGZvdW5kIGl0cyB3YXkKK2ludG8gbWFu
eSBvdGhlciBkb21haW5zIGJleW9uZCB0aGUgd2ViLCBhcyB3ZWxsLiAgVGhlIEBjb2Rleyh3ZWIg
anNvbil9Cittb2R1bGUgbWFrZXMgaXQgcG9zc2libGUgdG8gY29udmVydCBhIHN1YnNldCBvZiBT
Y2hlbWUgZGF0YSB0eXBlcyB0bworSlNPTiB0ZXh0IGFuZCB2aWNlIHZlcnNhLiAgRm9yIGV4YW1w
bGUsIHRoZSBKU09OIGRvY3VtZW50OgorCitAZXhhbXBsZQorQHZlcmJhdGltCit7CisgICJuYW1l
IjogIkV2YSBMdWF0b3IiLAorICAiYWdlIjogMjQsCisgICJzY2hlbWVyIjogdHJ1ZSwKKyAgImhv
YmJpZXMiOiBbCisgICAgImhhY2tpbmciLAorICAgICJjeWNsaW5nIiwKKyAgICAic3VyZmluZyIK
KyAgXQorfQorQGVuZCB2ZXJiYXRpbQorQGVuZCBleGFtcGxlCisKK2NhbiBiZSByZXByZXNlbnRl
ZCB3aXRoIHRoZSBmb2xsb3dpbmcgU2NoZW1lIGV4cHJlc3Npb246CisKK0BleGFtcGxlCitAdmVy
YmF0aW0KKycoKCJuYW1lIiAuICJFdmEgTHVhdG9yIikKKyAgKCJhZ2UiIC4gMjQpCisgICgic2No
ZW1lciIgLiAjdCkKKyAgKCJob2JiaWVzIiAuICMoImhhY2tpbmciICJjeWNsaW5nIiAic3VyZmlu
ZyIpKSkKK0BlbmQgdmVyYmF0aW0KK0BlbmQgZXhhbXBsZQorCitTdHJpbmdzLCBleGFjdCBpbnRl
Z2VycywgaW5leGFjdCByZWFscyAoZXhjbHVkaW5nIE5hTnMgYW5kIGluZmluaXRpZXMpLAorQGNv
ZGV7I3R9LCBAY29kZXsjZn0sIHRoZSBzeW1ib2wgQGNvZGV7bnVsbH0sIHZlY3RvcnMsIGFuZCBh
c3NvY2lhdGlvbgorbGlzdHMgbWF5IGJlIHNlcmlhbGl6ZWQgYXMgSlNPTi4gIEFzc29jaWF0aW9u
IGxpc3RzIHNlcmlhbGl6ZSBhcyBKU09OCitvYmplY3RzIGFuZCB2ZWN0b3JzIHNlcmlhbGl6ZSBh
cyBKU09OIGFycmF5cy4gIFRoZSBrZXlzIG9mIGFzc29jaWF0aW9uCitsaXN0cyBAZW1waHttdXN0
fSBiZSBzdHJpbmdzLgorCitAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHJlYWQtanNvbiBbcG9y
dF0KKworUGFyc2UgYSBKU09OLWVuY29kZWQgdmFsdWUgZnJvbSBAdmFye3BvcnR9IGFuZCByZXR1
cm4gaXRzIFNjaGVtZQorcmVwcmVzZW50YXRpb24uICBJZiBAdmFye3BvcnR9IGlzIHVuc3BlY2lm
aWVkLCB0aGUgY3VycmVudCBpbnB1dCBwb3J0IGlzCit1c2VkLgorCitAZXhhbXBsZQorQHZlcmJh
dGltCisoY2FsbC13aXRoLWlucHV0LXN0cmluZyAiW3RydWUsZmFsc2UsbnVsbCw0MixcImZvb1wi
XSIgcmVhZC1qc29uKQorOzsgPT4gIygjdCAjZiBudWxsIDQyICJmb28iKQorCisoY2FsbC13aXRo
LWlucHV0LXN0cmluZyAie1wiZm9vXCI6MSxcImJhclwiOjJ9IiByZWFkLWpzb24pCis7OyA9PiAo
KCJmb28iIC4gMSkgKCJiYXIiIC4gMikpCitAZW5kIHZlcmJhdGltCitAZW5kIGV4YW1wbGUKKwor
QGVuZCBkZWZmbgorCitAZGVmdHAge0V4Y2VwdGlvbiBUeXBlfSAmanNvbi1yZWFkLWVycm9yCitB
biBleGNlcHRpb24gdHlwZSBkZW5vdGluZyBKU09OIHJlYWQgZXJyb3JzLgorQGVuZCBkZWZ0cAor
CitAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHdyaXRlLWpzb24gZXhwIFtwb3J0XQorCitTZXJp
YWxpemUgdGhlIGV4cHJlc3Npb24gQHZhcntleHB9IGFzIEpTT04tZW5jb2RlZCB0ZXh0IHRvIEB2
YXJ7cG9ydH0uCitJZiBAdmFye3BvcnR9IGlzIHVuc3BlY2lmaWVkLCB0aGUgY3VycmVudCBvdXRw
dXQgcG9ydCBpcyB1c2VkLgorCitAZXhhbXBsZQorQHZlcmJhdGltCisod2l0aC1vdXRwdXQtdG8t
c3RyaW5nIChsYW1iZGEgKCkgKHdyaXRlLWpzb24gIygjdCAjZiBudWxsIDQyICJmb28iKSkpKQor
OzsgPT4gIlt0cnVlLGZhbHNlLG51bGwsNDIsXCJmb29cIl0iCisKKyh3aXRoLW91dHB1dC10by1z
dHJpbmcgKGxhbWJkYSAoKSAod3JpdGUtanNvbiAnKCgiZm9vIiAuIDEpICgiYmFyIiAuIDIpKSkp
KQorOzsgPT4gIntcImZvb1wiOjEsXCJiYXJcIjoyfSIKK0BlbmQgdmVyYmF0aW0KK0BlbmQgZXhh
bXBsZQorCitAZW5kIGRlZmZuCisKK0BkZWZ0cCB7RXhjZXB0aW9uIFR5cGV9ICZqc29uLXdyaXRl
LWVycm9yCitBbiBleGNlcHRpb24gdHlwZSBkZW5vdGluZyBKU09OIHdyaXRlIGVycm9ycy4KK0Bl
bmQgZGVmdHAKKworCiBAbm9kZSBXZWIgQ2xpZW50CiBAc3Vic2VjdGlvbiBXZWIgQ2xpZW50CiAK
ZGlmZiAtLWdpdCBhL21vZHVsZS93ZWIvanNvbi5zY20gYi9tb2R1bGUvd2ViL2pzb24uc2NtCm5l
dyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAwMC4uNDFhYWMwZTkwCi0tLSAvZGV2L251
bGwKKysrIGIvbW9kdWxlL3dlYi9qc29uLnNjbQpAQCAtMCwwICsxLDMwOCBAQAorOzs7OyBqc29u
LnNjbSAtLS0gSlNPTiByZWFkZXIvd3JpdGVyIChFQ01BLTQwNCkKKzs7OzsgQ29weXJpZ2h0IChD
KSAyMDI1IEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLgorOzs7OworOzs7OyBUaGlzIGxp
YnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yCis7
Ozs7IG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQ
dWJsaWMKKzs7OzsgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91
bmRhdGlvbjsgZWl0aGVyCis7Ozs7IHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlv
dXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4KKzs7OzsKKzs7OzsgVGhpcyBsaWJyYXJ5IGlz
IGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCis7Ozs7IGJ1
dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5
IG9mCis7Ozs7IE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVS
UE9TRS4gIFNlZSB0aGUgR05VCis7Ozs7IExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZv
ciBtb3JlIGRldGFpbHMuCis7Ozs7Cis7Ozs7IFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNv
cHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMKKzs7OzsgTGljZW5zZSBhbG9uZyB3
aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQorOzs7
OyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0
b24sIE1BIDAyMTEwLTEzMDEgVVNBCis7Ozs7CisKKyhkZWZpbmUtbW9kdWxlICh3ZWIganNvbikK
KyAgIzp1c2UtbW9kdWxlIChpY2UtOSBleGNlcHRpb25zKQorICAjOnVzZS1tb2R1bGUgKGljZS05
IG1hdGNoKQorICAjOnVzZS1tb2R1bGUgKGljZS05IHRleHR1YWwtcG9ydHMpCisgICM6ZXhwb3J0
ICgmanNvbi1yZWFkLWVycm9yCisgICAgICAgICAgICByZWFkLWpzb24KKworICAgICAgICAgICAg
Jmpzb24td3JpdGUtZXJyb3IKKyAgICAgICAgICAgIHdyaXRlLWpzb24pKQorCisoZGVmaW5lLWV4
Y2VwdGlvbi10eXBlICZqc29uLXJlYWQtZXJyb3IgJmVycm9yCisgIG1ha2UtanNvbi1yZWFkLWVy
cm9yCisgIGpzb24tcmVhZC1lcnJvcj8pCisKKyhkZWZpbmUqIChyZWFkLWpzb24gIzpvcHRpb25h
bCAocG9ydCAoY3VycmVudC1pbnB1dC1wb3J0KSkpCisgICJQYXJzZSBhIEpTT04tZW5jb2RlZCB2
YWx1ZSBmcm9tIEB2YXJ7cG9ydH0gYW5kIHJldHVybiBpdHMgU2NoZW1lCityZXByZXNlbnRhdGlv
bi4gIElmIEB2YXJ7cG9ydH0gaXMgdW5zcGVjaWZpZWQsIHRoZSBjdXJyZW50IGlucHV0IHBvcnQg
aXMKK3VzZWQuIgorICAoZGVmaW5lIChmYWlsIG1lc3NhZ2UpCisgICAgKHJhaXNlLWV4Y2VwdGlv
bgorICAgICAobWFrZS1leGNlcHRpb24gKG1ha2UtanNvbi1yZWFkLWVycm9yKQorICAgICAgICAg
ICAgICAgICAgICAgKG1ha2UtZXhjZXB0aW9uLXdpdGgtb3JpZ2luICdyZWFkLWpzb24pCisgICAg
ICAgICAgICAgICAgICAgICAobWFrZS1leGNlcHRpb24td2l0aC1tZXNzYWdlIG1lc3NhZ2UpCisg
ICAgICAgICAgICAgICAgICAgICAobWFrZS1leGNlcHRpb24td2l0aC1pcnJpdGFudHMgKGxpc3Qg
cG9ydCkpKSkpCisgIChkZWZpbmUgKGNvbnN1bWUtd2hpdGVzcGFjZSkKKyAgICAoY2FzZSAocGVl
ay1jaGFyIHBvcnQpCisgICAgICAoKCNcc3BhY2UgI1x0YWIgI1xyZXR1cm4gI1xuZXdsaW5lKQor
ICAgICAgIChyZWFkLWNoYXIgcG9ydCkKKyAgICAgICAoY29uc3VtZS13aGl0ZXNwYWNlKSkKKyAg
ICAgIChlbHNlICh2YWx1ZXMpKSkpCisgIChkZWZpbmUtc3ludGF4LXJ1bGUgKGRlZmluZS1rZXl3
b3JkLXJlYWRlciBuYW1lIHN0ciB2YWwpCisgICAgKGRlZmluZSAobmFtZSkKKyAgICAgIChpZiAo
c3RyaW5nPT8gKGdldC1zdHJpbmctbiBwb3J0IChzdHJpbmctbGVuZ3RoIHN0cikpIHN0cikKKyAg
ICAgICAgICB2YWwKKyAgICAgICAgICAoZmFpbCAiaW52YWxpZCBrZXl3b3JkIikpKSkKKyAgKGRl
ZmluZS1rZXl3b3JkLXJlYWRlciByZWFkLXRydWUgInRydWUiICN0KQorICAoZGVmaW5lLWtleXdv
cmQtcmVhZGVyIHJlYWQtZmFsc2UgImZhbHNlIiAjZikKKyAgKGRlZmluZS1rZXl3b3JkLXJlYWRl
ciByZWFkLW51bGwgIm51bGwiICdudWxsKQorICAoZGVmaW5lIChyZWFkLWhleC1kaWdpdCkKKyAg
ICAoY2FzZSAocGVlay1jaGFyIHBvcnQpCisgICAgICAoKCNcMCAjXDEgI1wyICNcMyAjXDQgI1w1
ICNcNiAjXDcgI1w4ICNcOSkKKyAgICAgICAoLSAoY2hhci0+aW50ZWdlciAocmVhZC1jaGFyIHBv
cnQpKSAoY2hhci0+aW50ZWdlciAjXDApKSkKKyAgICAgICgoI1xhICNcYiAjXGMgI1xkICNcZSAj
XGYpCisgICAgICAgKCsgMTAgKC0gKGNoYXItPmludGVnZXIgKHJlYWQtY2hhciBwb3J0KSkgKGNo
YXItPmludGVnZXIgI1xhKSkpKQorICAgICAgKCgjXEEgI1xCICNcQyAjXEQgI1xFICNcRikKKyAg
ICAgICAoKyAxMCAoLSAoY2hhci0+aW50ZWdlciAocmVhZC1jaGFyIHBvcnQpKSAoY2hhci0+aW50
ZWdlciAjXEEpKSkpCisgICAgICAoZWxzZSAoZmFpbCAiaW52YWxpZCBoZXggZGlnaXQiKSkpKQor
ICAoZGVmaW5lIChyZWFkLXV0ZjE2LWNoYXJhY3RlcikKKyAgICAobGV0KiAoKGEgKHJlYWQtaGV4
LWRpZ2l0KSkKKyAgICAgICAgICAgKGIgKHJlYWQtaGV4LWRpZ2l0KSkKKyAgICAgICAgICAgKGMg
KHJlYWQtaGV4LWRpZ2l0KSkKKyAgICAgICAgICAgKGQgKHJlYWQtaGV4LWRpZ2l0KSkpCisgICAg
ICAoaW50ZWdlci0+Y2hhciAoKyAoKiBhIChleHB0IDE2IDMpKSAoKiBiIChleHB0IDE2IDIpKSAo
KiBjIDE2KSBkKSkpKQorICAoZGVmaW5lIChyZWFkLWVzY2FwZS1jaGFyYWN0ZXIpCisgICAgKGNh
c2UgKHJlYWQtY2hhciBwb3J0KQorICAgICAgKCgjXCIpICNcIikKKyAgICAgICgoI1xcKSAjXFwp
CisgICAgICAoKCNcLykgI1wvKQorICAgICAgKCgjXGIpICNcYmFja3NwYWNlKQorICAgICAgKCgj
XGYpICNccGFnZSkKKyAgICAgICgoI1xuKSAjXG5ld2xpbmUpCisgICAgICAoKCNccikgI1xyZXR1
cm4pCisgICAgICAoKCNcdCkgI1x0YWIpCisgICAgICAoKCNcdSkgKHJlYWQtdXRmMTYtY2hhcmFj
dGVyKSkKKyAgICAgIChlbHNlIChmYWlsICJpbnZhbGlkIGVzY2FwZSBjaGFyYWN0ZXIiKSkpKQor
ICAoZGVmaW5lIChyZWFkLXN0cmluZykKKyAgICAocmVhZC1jaGFyIHBvcnQpCisgICAgKGxpc3Qt
PnN0cmluZworICAgICAobGV0IGxwICgpCisgICAgICAgKG1hdGNoIChyZWFkLWNoYXIgcG9ydCkK
KyAgICAgICAgICgoPyBlb2Ytb2JqZWN0PykgKGZhaWwgIkVPRiB3aGlsZSByZWFkaW5nIHN0cmlu
ZyIpKQorICAgICAgICAgKCNcIiAnKCkpCisgICAgICAgICAoI1xcIChjb25zIChyZWFkLWVzY2Fw
ZS1jaGFyYWN0ZXIpIChscCkpKQorICAgICAgICAgKGNoYXIgKGNvbnMgY2hhciAobHApKSkpKSkp
CisgIChkZWZpbmUgKHJlYWQtZGlnaXQtbWF5YmUpCisgICAgKGNhc2UgKHBlZWstY2hhciBwb3J0
KQorICAgICAgKCgjXDAgI1wxICNcMiAjXDMgI1w0ICNcNSAjXDYgI1w3ICNcOCAjXDkpCisgICAg
ICAgKC0gKGNoYXItPmludGVnZXIgKHJlYWQtY2hhciBwb3J0KSkKKyAgICAgICAgICAoY2hhci0+
aW50ZWdlciAjXDApKSkKKyAgICAgIChlbHNlICNmKSkpCisgIChkZWZpbmUgKHJlYWQtaW50ZWdl
cikKKyAgICAobGV0ICgoeCAocmVhZC1kaWdpdC1tYXliZSkpKQorICAgICAgKGFuZCB4CisgICAg
ICAgICAgIChsZXQgbHAgKCh4IHgpKQorICAgICAgICAgICAgIChtYXRjaCAocmVhZC1kaWdpdC1t
YXliZSkKKyAgICAgICAgICAgICAgICgjZiB4KQorICAgICAgICAgICAgICAgKHkgKGxwICgrICgq
IHggMTApIHkpKSkpKSkpKQorICAoZGVmaW5lIChyZWFkLWZyYWN0aW9uKQorICAgIChjYXNlIChw
ZWVrLWNoYXIgcG9ydCkKKyAgICAgICgoI1wuKQorICAgICAgIChyZWFkLWNoYXIgcG9ydCkKKyAg
ICAgICAobGV0IGxwICgobWFnIDEwKSkKKyAgICAgICAgIChsZXQgKChuIChyZWFkLWRpZ2l0LW1h
eWJlKSkpCisgICAgICAgICAgIChpZiBuICgrICgvIG4gbWFnKSAobHAgKCogbWFnIDEwKSkpIDAp
KSkpCisgICAgICAoZWxzZSAwKSkpCisgIChkZWZpbmUgKHJlYWQtZXhwb25lbnQpCisgICAgKGNh
c2UgKHBlZWstY2hhciBwb3J0KQorICAgICAgKCgjXGUgI1xFKQorICAgICAgIChyZWFkLWNoYXIg
cG9ydCkKKyAgICAgICAoY2FzZSAocGVlay1jaGFyIHBvcnQpCisgICAgICAgICAoKCNcLSkKKyAg
ICAgICAgICAocmVhZC1jaGFyIHBvcnQpCisgICAgICAgICAgKGV4cHQgMTAgKC0gKHJlYWQtaW50
ZWdlcikpKSkKKyAgICAgICAgICgoI1wrKQorICAgICAgICAgIChyZWFkLWNoYXIgcG9ydCkKKyAg
ICAgICAgICAoZXhwdCAxMCAocmVhZC1pbnRlZ2VyKSkpCisgICAgICAgICAoZWxzZQorICAgICAg
ICAgIChleHB0IDEwIChyZWFkLWludGVnZXIpKSkpKQorICAgICAgKGVsc2UgMSkpKQorICAoZGVm
aW5lIChyZWFkLXBvc2l0aXZlLW51bWJlcikKKyAgICAobGV0ICgobiAocmVhZC1pbnRlZ2VyKSkp
CisgICAgICAoYW5kIG4KKyAgICAgICAgICAgKGxldCogKChmIChyZWFkLWZyYWN0aW9uKSkKKyAg
ICAgICAgICAgICAgICAgIChlIChyZWFkLWV4cG9uZW50KSkKKyAgICAgICAgICAgICAgICAgICh4
ICgqICgrIG4gZikgZSkpKQorICAgICAgICAgICAgIChpZiAoZXhhY3QtaW50ZWdlcj8geCkgeCAo
ZXhhY3QtPmluZXhhY3QgeCkpKSkpKQorICAoZGVmaW5lIChyZWFkLW5lZ2F0aXZlLW51bWJlcikK
KyAgICAocmVhZC1jaGFyIHBvcnQpCisgICAgKGxldCAoKHggKHJlYWQtcG9zaXRpdmUtbnVtYmVy
KSkpCisgICAgICAoaWYgeCAoLSB4KSAoZmFpbCAiaW52YWxpZCBudW1iZXIiKSkpKQorICAoZGVm
aW5lIChyZWFkLWxlYWRpbmctemVyby1udW1iZXIpCisgICAgKHJlYWQtY2hhciBwb3J0KQorICAg
IChjYXNlIChwZWVrLWNoYXIgcG9ydCkKKyAgICAgIDs7IEV4dHJhbmVvdXMgemVyb2VzIGFyZSBu
b3QgYWxsb3dlZC4gIEEgc2luZ2xlIGxlYWRpbmcgemVybworICAgICAgOzsgY2FuIG9ubHkgYmUg
Zm9sbG93ZWQgYnkgYSBkZWNpbWFsIHBvaW50LgorICAgICAgKCgjXDAgI1wxICNcMiAjXDMgI1w0
ICNcNSAjXDYgI1w3ICNcOCAjXDkgI1xlICNcRSkKKyAgICAgICAoZmFpbCAiZXh0cmFuZW91cyBs
ZWFkaW5nIHplcm8iKSkKKyAgICAgIDs7IEZyYWN0aW9uYWwgbnVtYmVyLgorICAgICAgKCgjXC4p
CisgICAgICAgKGxldCogKChkIChyZWFkLWZyYWN0aW9uKSkKKyAgICAgICAgICAgICAgKGUgKHJl
YWQtZXhwb25lbnQpKSkKKyAgICAgICAgIChleGFjdC0+aW5leGFjdCAoKiBkIGUpKSkpCisgICAg
ICA7OyBKdXN0IHBsYWluIHplcm8uCisgICAgICAoZWxzZSAwKSkpCisgIChkZWZpbmUgKHJlYWQt
a2V5K3ZhbHVlLXBhaXIpCisgICAgKGxldCAoKGtleSAocmVhZC1zdHJpbmcpKSkKKyAgICAgIChj
b25zdW1lLXdoaXRlc3BhY2UpCisgICAgICAoY2FzZSAocmVhZC1jaGFyIHBvcnQpCisgICAgICAg
ICgoI1w6KQorICAgICAgICAgKGNvbnN1bWUtd2hpdGVzcGFjZSkKKyAgICAgICAgIChjb25zIGtl
eSAocmVhZC12YWx1ZSkpKQorICAgICAgICAoZWxzZSAoZmFpbCAiaW52YWxpZCBrZXkvdmFsdWUg
cGFpciBkZWxpbWl0ZXIiKSkpKSkKKyAgKGRlZmluZSAocmVhZC1vYmplY3QpCisgICAgKHJlYWQt
Y2hhciBwb3J0KQorICAgIChjb25zdW1lLXdoaXRlc3BhY2UpCisgICAgKGNhc2UgKHBlZWstY2hh
ciBwb3J0KQorICAgICAgOzsgRW1wdHkgb2JqZWN0LgorICAgICAgKCgjXH0pCisgICAgICAgKHJl
YWQtY2hhciBwb3J0KQorICAgICAgICcoKSkKKyAgICAgIChlbHNlCisgICAgICAgOzsgUmVhZCBm
aXJzdCBrZXkvdmFsdWUgcGFpciwgdGhlbiBhbGwgc3Vic2VxdWVudCBwYWlycyBkZWxpbWl0ZWQK
KyAgICAgICA7OyBieSBjb21tYXMuCisgICAgICAgKGNvbnMgKHJlYWQta2V5K3ZhbHVlLXBhaXIp
CisgICAgICAgICAgICAgKGxldCBscCAoKQorICAgICAgICAgICAgICAgKGNvbnN1bWUtd2hpdGVz
cGFjZSkKKyAgICAgICAgICAgICAgIChjYXNlIChwZWVrLWNoYXIgcG9ydCkKKyAgICAgICAgICAg
ICAgICAgKCgjXCwpCisgICAgICAgICAgICAgICAgICAocmVhZC1jaGFyIHBvcnQpCisgICAgICAg
ICAgICAgICAgICAoY29uc3VtZS13aGl0ZXNwYWNlKQorICAgICAgICAgICAgICAgICAgKGNvbnMg
KHJlYWQta2V5K3ZhbHVlLXBhaXIpIChscCkpKQorICAgICAgICAgICAgICAgICA7OyBFbmQgb2Yg
b2JqZWN0LgorICAgICAgICAgICAgICAgICAoKCNcfSkKKyAgICAgICAgICAgICAgICAgIChyZWFk
LWNoYXIgcG9ydCkKKyAgICAgICAgICAgICAgICAgICcoKSkKKyAgICAgICAgICAgICAgICAgKGVs
c2UgKGZhaWwgImludmFsaWQgb2JqZWN0IGRlbGltaXRlciIpKSkpKSkpKQorICAoZGVmaW5lIChy
ZWFkLWFycmF5KQorICAgIChyZWFkLWNoYXIgcG9ydCkKKyAgICAoY29uc3VtZS13aGl0ZXNwYWNl
KQorICAgIChjYXNlIChwZWVrLWNoYXIgcG9ydCkKKyAgICAgIDs7IEVtcHR5IGFycmF5LgorICAg
ICAgKCgjXF0pCisgICAgICAgKHJlYWQtY2hhciBwb3J0KQorICAgICAgICMoKSkKKyAgICAgIChl
bHNlCisgICAgICAgKGxpc3QtPnZlY3RvcgorICAgICAgICA7OyBSZWFkIHRoZSBmaXJzdCBlbGVt
ZW50LCB0aGVuIGFsbCBzdWJzZXF1ZW50IGVsZW1lbnRzCisgICAgICAgIDs7IGRlbGltaXRlZCBi
eSBjb21tYXMuCisgICAgICAgIChjb25zIChyZWFkLXZhbHVlKQorICAgICAgICAgICAgICAobGV0
IGxwICgpCisgICAgICAgICAgICAgICAgKGNvbnN1bWUtd2hpdGVzcGFjZSkKKyAgICAgICAgICAg
ICAgICAoY2FzZSAocGVlay1jaGFyIHBvcnQpCisgICAgICAgICAgICAgICAgICA7OyBFbGVtZW50
cyBhcmUgY29tbWEgZGVsaW1pdGVkLgorICAgICAgICAgICAgICAgICAgKCgjXCwpCisgICAgICAg
ICAgICAgICAgICAgKHJlYWQtY2hhciBwb3J0KQorICAgICAgICAgICAgICAgICAgIChjb25zdW1l
LXdoaXRlc3BhY2UpCisgICAgICAgICAgICAgICAgICAgKGNvbnMgKHJlYWQtdmFsdWUpIChscCkp
KQorICAgICAgICAgICAgICAgICAgOzsgRW5kIG9mIGFycmF5LgorICAgICAgICAgICAgICAgICAg
KCgjXF0pCisgICAgICAgICAgICAgICAgICAgKHJlYWQtY2hhciBwb3J0KQorICAgICAgICAgICAg
ICAgICAgICcoKSkKKyAgICAgICAgICAgICAgICAgIChlbHNlIChmYWlsICJpbnZhbGlkIGFycmF5
IGRlbGltaXRlciIpKSkpKSkpKSkKKyAgKGRlZmluZSAocmVhZC12YWx1ZSkKKyAgICAoY29uc3Vt
ZS13aGl0ZXNwYWNlKQorICAgIChjYXNlIChwZWVrLWNoYXIgcG9ydCkKKyAgICAgICgoI1wiKSAo
cmVhZC1zdHJpbmcpKQorICAgICAgKCgjXHspIChyZWFkLW9iamVjdCkpCisgICAgICAoKCNcWykg
KHJlYWQtYXJyYXkpKQorICAgICAgKCgjXHQpIChyZWFkLXRydWUpKQorICAgICAgKCgjXGYpIChy
ZWFkLWZhbHNlKSkKKyAgICAgICgoI1xuKSAocmVhZC1udWxsKSkKKyAgICAgICgoI1wtKSAocmVh
ZC1uZWdhdGl2ZS1udW1iZXIpKQorICAgICAgKCgjXDApIChyZWFkLWxlYWRpbmctemVyby1udW1i
ZXIpKQorICAgICAgKCgjXDEgI1wyICNcMyAjXDQgI1w1ICNcNiAjXDcgI1w4ICNcOSkgKHJlYWQt
cG9zaXRpdmUtbnVtYmVyKSkKKyAgICAgIChlbHNlIChmYWlsICJpbnZhbGlkIHZhbHVlIikpKSkK
KyAgKHJlYWQtdmFsdWUpKQorCisoZGVmaW5lLWV4Y2VwdGlvbi10eXBlICZqc29uLXdyaXRlLWVy
cm9yICZlcnJvcgorICBtYWtlLWpzb24td3JpdGUtZXJyb3IKKyAganNvbi13cml0ZS1lcnJvcj8p
CisKKyhkZWZpbmUqICh3cml0ZS1qc29uIGV4cCAjOm9wdGlvbmFsIChwb3J0IChjdXJyZW50LW91
dHB1dC1wb3J0KSkpCisgICJTZXJpYWxpemUgdGhlIGV4cHJlc3Npb24gQHZhcntleHB9IGFzIEpT
T04tZW5jb2RlZCB0ZXh0IHRvIEB2YXJ7cG9ydH0uCitJZiBAdmFye3BvcnR9IGlzIHVuc3BlY2lm
aWVkLCB0aGUgY3VycmVudCBvdXRwdXQgcG9ydCBpcyB1c2VkLiIKKyAgKGRlZmluZSAoZmFpbCBt
ZXNzYWdlIHgpCisgICAgKHJhaXNlLWV4Y2VwdGlvbgorICAgICAobWFrZS1leGNlcHRpb24gKG1h
a2UtanNvbi13cml0ZS1lcnJvcikKKyAgICAgICAgICAgICAgICAgICAgIChtYWtlLWV4Y2VwdGlv
bi13aXRoLW9yaWdpbiAnd3JpdGUtanNvbikKKyAgICAgICAgICAgICAgICAgICAgIChtYWtlLWV4
Y2VwdGlvbi13aXRoLW1lc3NhZ2UgbWVzc2FnZSkKKyAgICAgICAgICAgICAgICAgICAgIChtYWtl
LWV4Y2VwdGlvbi13aXRoLWlycml0YW50cyAobGlzdCB4KSkpKSkKKyAgKGRlZmluZSAod3JpdGUt
Y2hhci9lc2NhcGUgY2hhcikKKyAgICAobWF0Y2ggY2hhcgorICAgICAgKCNcIiAocHV0LXN0cmlu
ZyBwb3J0ICJcXFwiIikpCisgICAgICAoI1xcIChwdXQtc3RyaW5nIHBvcnQgIlxcXFwiKSkKKyAg
ICAgICgjXC8gKHB1dC1zdHJpbmcgcG9ydCAiXFwvIikpCisgICAgICAoI1xiYWNrc3BhY2UgKHB1
dC1zdHJpbmcgcG9ydCAiXFxiIikpCisgICAgICAoI1xwYWdlIChwdXQtc3RyaW5nIHBvcnQgIlxc
ZiIpKQorICAgICAgKCNcbmV3bGluZSAocHV0LXN0cmluZyBwb3J0ICJcXG4iKSkKKyAgICAgICgj
XHJldHVybiAocHV0LXN0cmluZyBwb3J0ICJcXHIiKSkKKyAgICAgICgjXHRhYiAocHV0LXN0cmlu
ZyBwb3J0ICJcXHQiKSkKKyAgICAgIChfIChwdXQtY2hhciBwb3J0IGNoYXIpKSkpCisgIChkZWZp
bmUgKHdyaXRlLXN0cmluZyBzdHIpCisgICAgKGxldCAoKGluIChvcGVuLWlucHV0LXN0cmluZyBz
dHIpKSkKKyAgICAgIChwdXQtY2hhciBwb3J0ICNcIikKKyAgICAgIChzdHJpbmctZm9yLWVhY2gg
d3JpdGUtY2hhci9lc2NhcGUgc3RyKQorICAgICAgKHB1dC1jaGFyIHBvcnQgI1wiKSkpCisgIChk
ZWZpbmUgKHdyaXRlLXBhaXIgeCkKKyAgICAobWF0Y2ggeAorICAgICAgKCgoPyBzdHJpbmc/IGtl
eSkgLiB2YWx1ZSkKKyAgICAgICAod3JpdGUtc3RyaW5nIGtleSkKKyAgICAgICAocHV0LWNoYXIg
cG9ydCAjXDopCisgICAgICAgKHdyaXRlLXZhbHVlIHZhbHVlKSkKKyAgICAgIChfIChmYWlsICJp
bnZhbGlkIGtleS92YWx1ZSBwYWlyIiB4KSkpKQorICAoZGVmaW5lICh3cml0ZS1vYmplY3Qgb2Jq
KQorICAgIChwdXQtY2hhciBwb3J0ICNceykKKyAgICAobWF0Y2ggb2JqCisgICAgICAoKGhlYWQg
LiByZXN0KQorICAgICAgICh3cml0ZS1wYWlyIGhlYWQpCisgICAgICAgKGxldCBscCAoKG9iaiBy
ZXN0KSkKKyAgICAgICAgIChtYXRjaCBvYmoKKyAgICAgICAgICAgKCgpICh2YWx1ZXMpKQorICAg
ICAgICAgICAoKGhlYWQgLiByZXN0KQorICAgICAgICAgICAgKHB1dC1jaGFyIHBvcnQgI1wsKQor
ICAgICAgICAgICAgKHdyaXRlLXBhaXIgaGVhZCkKKyAgICAgICAgICAgIChscCByZXN0KSkKKyAg
ICAgICAgICAgKF8gKGZhaWwgImludmFsaWQgb2JqZWN0IiBvYmopKSkpKSkKKyAgICAocHV0LWNo
YXIgcG9ydCAjXH0pKQorICAoZGVmaW5lICh3cml0ZS1hcnJheSB2KQorICAgIChwdXQtY2hhciBw
b3J0ICNcWykKKyAgICAobWF0Y2ggKHZlY3Rvci1sZW5ndGggdikKKyAgICAgICgwICh2YWx1ZXMp
KQorICAgICAgKG4KKyAgICAgICAod3JpdGUtdmFsdWUgKHZlY3Rvci1yZWYgdiAwKSkKKyAgICAg
ICAoZG8gKChpIDEgKDErIGkpKSkKKyAgICAgICAgICAgKCg9IGkgbikpCisgICAgICAgICAocHV0
LWNoYXIgcG9ydCAjXCwpCisgICAgICAgICAod3JpdGUtdmFsdWUgKHZlY3Rvci1yZWYgdiBpKSkp
KSkKKyAgICAocHV0LWNoYXIgcG9ydCAjXF0pKQorICAoZGVmaW5lICh3cml0ZS1udW1iZXIgeCkK
KyAgICAoaWYgKG9yIChleGFjdC1pbnRlZ2VyPyB4KQorICAgICAgICAgICAgKGFuZCAocmVhbD8g
eCkKKyAgICAgICAgICAgICAgICAgKGluZXhhY3Q/IHgpCisgICAgICAgICAgICAgICAgIDs7IE5h
TnMgYW5kIGluZmluaXRpZXMgYXJlIG5vdCBhbGxvd2VkLgorICAgICAgICAgICAgICAgICAobm90
IChvciAobmFuPyB4KSAoaW5mPyB4KSkpKSkKKyAgICAgICAgOzsgU2NoZW1lJ3Mgc3RyaW5nIHJl
cHJlc2VudGF0aW9ucyBvZiBleGFjdCBpbnRlZ2VycyBhbmQgZmxvYXRzCisgICAgICAgIDs7IGFy
ZSBjb21wYXRpYmxlIHdpdGggSlNPTi4KKyAgICAgICAgKHB1dC1zdHJpbmcgcG9ydCAobnVtYmVy
LT5zdHJpbmcgeCkpCisgICAgICAgIChmYWlsICJpbnZhbGlkIG51bWJlciIgeCkpKQorICAoZGVm
aW5lICh3cml0ZS12YWx1ZSB4KQorICAgIChtYXRjaCB4CisgICAgICAoI3QgKHB1dC1zdHJpbmcg
cG9ydCAidHJ1ZSIpKQorICAgICAgKCNmIChwdXQtc3RyaW5nIHBvcnQgImZhbHNlIikpCisgICAg
ICAoJ251bGwgKHB1dC1zdHJpbmcgcG9ydCAibnVsbCIpKQorICAgICAgKCgpIChwdXQtc3RyaW5n
IHBvcnQgInt9IikpCisgICAgICAoKD8gcGFpcj8pICh3cml0ZS1vYmplY3QgeCkpCisgICAgICAo
KD8gdmVjdG9yPykgKHdyaXRlLWFycmF5IHgpKQorICAgICAgKCg/IHN0cmluZz8pICh3cml0ZS1z
dHJpbmcgeCkpCisgICAgICAoKD8gbnVtYmVyPykgKHdyaXRlLW51bWJlciB4KSkKKyAgICAgIChf
IChmYWlsICJpbnZhbGlkIHZhbHVlIiB4KSkpKQorICAod3JpdGUtdmFsdWUgZXhwKSkKZGlmZiAt
LWdpdCBhL3Rlc3Qtc3VpdGUvTWFrZWZpbGUuYW0gYi90ZXN0LXN1aXRlL01ha2VmaWxlLmFtCmlu
ZGV4IDYwMTRiMWYxZi4uMDBhZmVhMTQyIDEwMDY0NAotLS0gYS90ZXN0LXN1aXRlL01ha2VmaWxl
LmFtCisrKyBiL3Rlc3Qtc3VpdGUvTWFrZWZpbGUuYW0KQEAgLTczLDYgKzczLDcgQEAgU0NNX1RF
U1RTID0gdGVzdHMvMDAtaW5pdGlhbC1lbnYudGVzdAkJXAogCSAgICB0ZXN0cy9pY29udi50ZXN0
CQkJXAogCSAgICB0ZXN0cy9pbXBvcnQudGVzdAkJCVwKIAkgICAgdGVzdHMvaW50ZXJwLnRlc3QJ
CQlcCisJICAgIHRlc3RzL2pzb24udGVzdAkJCVwKIAkgICAgdGVzdHMva2V5d29yZHMudGVzdAkJ
CVwKIAkgICAgdGVzdHMvbGlzdC50ZXN0CQkJXAogCSAgICB0ZXN0cy9sb2FkLnRlc3QJCQlcCmRp
ZmYgLS1naXQgYS90ZXN0LXN1aXRlL3Rlc3RzL2pzb24udGVzdCBiL3Rlc3Qtc3VpdGUvdGVzdHMv
anNvbi50ZXN0Cm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAwMC4uZjkyZWVjY2Vj
Ci0tLSAvZGV2L251bGwKKysrIGIvdGVzdC1zdWl0ZS90ZXN0cy9qc29uLnRlc3QKQEAgLTAsMCAr
MSwxNTQgQEAKKzs7OzsganNvbi50ZXN0IC0tLSB0ZXN0IEpTT04gcmVhZGVyL3dyaXRlciAgICAg
LSotIHNjaGVtZSAtKi0KKzs7OzsKKzs7OzsgQ29weXJpZ2h0IChDKSAyMDE1IEZyZWUgU29mdHdh
cmUgRm91bmRhdGlvbiwgSW5jLgorOzs7OworOzs7OyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0
d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yCis7Ozs7IG1vZGlmeSBpdCB1bmRl
ciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMKKzs7OzsgTGljZW5z
ZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyCis7
Ozs7IHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0
ZXIgdmVyc2lvbi4KKzs7OzsKKzs7OzsgVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRo
ZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCis7Ozs7IGJ1dCBXSVRIT1VUIEFOWSBXQVJS
QU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mCis7Ozs7IE1FUkNIQU5U
QUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05V
Cis7Ozs7IExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCis7
Ozs7Cis7Ozs7IFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNz
ZXIgR2VuZXJhbCBQdWJsaWMKKzs7OzsgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsg
aWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQorOzs7OyBGb3VuZGF0aW9uLCBJbmMu
LCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BIDAyMTEwLTEzMDEg
VVNBCisKKyhkZWZpbmUtbW9kdWxlICh0ZXN0LXN1aXRlIHRlc3QtanNvbikKKyAgIzp1c2UtbW9k
dWxlICh0ZXN0LXN1aXRlIGxpYikKKyAgIzp1c2UtbW9kdWxlICh3ZWIganNvbikpCisKKzs7Owor
Ozs7IFJlYWRlcgorOzs7CisKKyhkZWZpbmUgKHJlYWQtanNvbi1zdHJpbmcgc3RyKQorICAoY2Fs
bC13aXRoLWlucHV0LXN0cmluZyBzdHIgcmVhZC1qc29uKSkKKworKGRlZmluZSAoanNvbi1yZWFk
PT8gc3RyIHgpCisgICg9IHggKHJlYWQtanNvbi1zdHJpbmcgc3RyKSkpCisKKyhkZWZpbmUgKGpz
b24tcmVhZC1lcT8gc3RyIHgpCisgIChlcT8geCAocmVhZC1qc29uLXN0cmluZyBzdHIpKSkKKwor
KGRlZmluZSAoanNvbi1yZWFkLWVxdWFsPyBzdHIgeCkKKyAgKGVxdWFsPyB4IChyZWFkLWpzb24t
c3RyaW5nIHN0cikpKQorCisoZGVmaW5lIChqc29uLXJlYWQtc3RyaW5nPT8gc3RyIHgpCisgIChz
dHJpbmc9PyB4IChyZWFkLWpzb24tc3RyaW5nIHN0cikpKQorCisod2l0aC10ZXN0LXByZWZpeCAi
cmVhZC1qc29uIgorICA7OyBLZXl3b3JkcworICAocGFzcy1pZiAoanNvbi1yZWFkLWVxPyAidHJ1
ZSIgI3QpKQorICAocGFzcy1pZiAoanNvbi1yZWFkLWVxPyAiZmFsc2UiICNmKSkKKyAgKHBhc3Mt
aWYgKGpzb24tcmVhZC1lcT8gIm51bGwiICdudWxsKSkKKyAgOzsgTnVtYmVycworICAocGFzcy1p
ZiAoanNvbi1yZWFkPT8gIjAiIDApKQorICAocGFzcy1pZiAoanNvbi1yZWFkPT8gIi0wIiAwKSkK
KyAgKHBhc3MtaWYgKGpzb24tcmVhZD0/ICIwLjAiIDAuMCkpCisgIChwYXNzLWlmIChqc29uLXJl
YWQ9PyAiLTAuMCIgLTAuMCkpCisgIChwYXNzLWlmIChqc29uLXJlYWQ9PyAiMC4xIiAwLjEpKQor
ICAocGFzcy1pZiAoanNvbi1yZWFkPT8gIjEuMjM0IiAxLjIzNCkpCisgIChwYXNzLWlmIChqc29u
LXJlYWQ9PyAiMSIgMSkpCisgIChwYXNzLWlmIChqc29uLXJlYWQ9PyAiLTEiIC0xKSkKKyAgKHBh
c3MtaWYgKGpzb24tcmVhZD0/ICIxLjEiIDEuMSkpCisgIChwYXNzLWlmIChqc29uLXJlYWQ9PyAi
MWUyIiAxZTIpKQorICAocGFzcy1pZiAoanNvbi1yZWFkPT8gIjEuMWUyIiAxLjFlMikpCisgIChw
YXNzLWlmIChqc29uLXJlYWQ9PyAiMS4xZS0yIiAxLjFlLTIpKQorICAocGFzcy1pZiAoanNvbi1y
ZWFkPT8gIjEuMWUrMiIgMS4xZTIpKQorICA7OyBFeHRyYW5lb3VzIHplcm9lcyBpbiBmcmFjdGlv
bgorICAocGFzcy1pZiAoanNvbi1yZWFkPT8gIjEuMDAwIiAxKSkKKyAgKHBhc3MtaWYgKGpzb24t
cmVhZD0/ICIxLjUwMDAiIDEuNSkpCisgIDs7IEV4dHJhbmVvdXMgemVyb2VzIGluIGV4cG9uZW50
CisgIChwYXNzLWlmIChqc29uLXJlYWQ9PyAiMS4xZTAwMCIgMS4xKSkKKyAgKHBhc3MtaWYgKGpz
b24tcmVhZD0/ICIxLjFlLTAyIiAxLjFlLTIpKQorICAocGFzcy1pZiAoanNvbi1yZWFkPT8gIjEu
MWUrMDIiIDEuMWUyKSkKKyAgOzsgU3RyaW5ncworICAocGFzcy1pZiAoanNvbi1yZWFkLXN0cmlu
Zz0/ICJcImZvb1wiIiAiZm9vIikpCisgIDs7IEVzY2FwZSBjb2RlcworICAocGFzcy1pZiAoanNv
bi1yZWFkLXN0cmluZz0/ICJcIlxcXCJcIiIgIlwiIikpCisgIChwYXNzLWlmIChqc29uLXJlYWQt
c3RyaW5nPT8gIlwiXFxcXFwiIiAiXFwiKSkKKyAgKHBhc3MtaWYgKGpzb24tcmVhZC1zdHJpbmc9
PyAiXCJcXC9cIiIgIi8iKSkKKyAgKHBhc3MtaWYgKGpzb24tcmVhZC1zdHJpbmc9PyAiXCJcXGJc
IiIgIlxiIikpCisgIChwYXNzLWlmIChqc29uLXJlYWQtc3RyaW5nPT8gIlwiXFxmXCIiICJcZiIp
KQorICAocGFzcy1pZiAoanNvbi1yZWFkLXN0cmluZz0/ICJcIlxcblwiIiAiXG4iKSkKKyAgKHBh
c3MtaWYgKGpzb24tcmVhZC1zdHJpbmc9PyAiXCJcXHJcIiIgIlxyIikpCisgIChwYXNzLWlmIChq
c29uLXJlYWQtc3RyaW5nPT8gIlwiXFx0XCIiICJcdCIpKQorICA7OyBVbmljb2RlIGluIGhleGFk
ZWNpbWFsIGZvcm1hdAorICAocGFzcy1pZiAoanNvbi1yZWFkLXN0cmluZz0/ICJcIlxcdTEyYWJc
IiIgIlx1MTJhYiIpKQorICA7OyBPYmplY3RzCisgIChwYXNzLWlmIChqc29uLXJlYWQtZXF1YWw/
ICJ7fSIgJygpKSkKKyAgKHBhc3MtaWYgKGpzb24tcmVhZC1lcXVhbD8gInsgXCJmb29cIjogXCJi
YXJcIiwgXCJiYXpcIjogXCJmcm9iXCJ9IgorICAgICAgICAgICAgICAgICAgICAgICAgICAgICAn
KCgiZm9vIiAuICJiYXIiKSAoImJheiIgLiAiZnJvYiIpKSkpCisgIDs7IE5lc3RlZCBvYmplY3Rz
CisgIChwYXNzLWlmIChqc29uLXJlYWQtZXF1YWw/ICJ7XCJmb29cIjp7XCJiYXJcIjpcImJhelwi
fX0iCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcoKCJmb28iIC4gKCgiYmFyIiAuICJi
YXoiKSkpKSkpCisgIDs7IEFycmF5cworICAocGFzcy1pZiAoanNvbi1yZWFkLWVxdWFsPyAiW10i
ICMoKSkpCisgIChwYXNzLWlmIChqc29uLXJlYWQtZXF1YWw/ICJbMSwgMiwgXCJmb29cIl0iCisg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICMoMSAyICJmb28iKSkpCisgIDs7IE5lc3RlZCBh
cnJheXMKKyAgKHBhc3MtaWYgKGpzb24tcmVhZC1lcXVhbD8gIlsxLCAyLCBbXCJmb29cIiwgXCJi
YXJcIl1dIgorICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjKDEgMiAjKCJmb28iICJiYXIi
KSkpKQorICA7OyBBcnJheXMgYW5kIG9iamVjdHMgbmVzdGVkIHdpdGhpbiBlYWNoIG90aGVyCisg
IChwYXNzLWlmIChqc29uLXJlYWQtZXF1YWw/ICJ7XCJmb29cIjpbe1wiYmFyXCI6dHJ1ZX0se1wi
YmF6XCI6WzEsMiwzXX1dfSIKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJygoImZvbyIg
LiAjKCgoImJhciIgLiAjdCkpCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAoKCJiYXoiIC4gIygxIDIgMykpKSkpKSkpCisgIDs7IExlYWRpbmcgd2hpdGVzcGFjZQor
ICAocGFzcy1pZiAoanNvbi1yZWFkLWVxPyAiXHRcclxuIHRydWUiICN0KSkpCisKKzs7OworOzs7
IFdyaXRlcgorOzs7CisKKyhkZWZpbmUgKHdyaXRlLWpzb24tc3RyaW5nIGV4cCkKKyAgKGNhbGwt
d2l0aC1vdXRwdXQtc3RyaW5nCisgICAobGFtYmRhIChwb3J0KQorICAgICAod3JpdGUtanNvbiBl
eHAgcG9ydCkpKSkKKworKGRlZmluZSAoanNvbi13cml0ZS1zdHJpbmc9PyBleHAgc3RyKQorICAo
c3RyaW5nPT8gc3RyICh3cml0ZS1qc29uLXN0cmluZyBleHApKSkKKworKHdpdGgtdGVzdC1wcmVm
aXggIndyaXRlLWpzb24iCisgIDs7IEtleXdvcmRzCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0
cmluZz0/ICN0ICJ0cnVlIikpCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0cmluZz0/ICNmICJm
YWxzZSIpKQorICAocGFzcy1pZiAoanNvbi13cml0ZS1zdHJpbmc9PyAnbnVsbCAibnVsbCIpKQor
ICA7OyBOdW1iZXJzCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0cmluZz0/IDAgIjAiKSkKKyAg
KHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gMC4wICIwLjAiKSkKKyAgKHBhc3MtaWYgKGpz
b24td3JpdGUtc3RyaW5nPT8gMC4xICIwLjEiKSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3Ry
aW5nPT8gMSAiMSIpKQorICAocGFzcy1pZiAoanNvbi13cml0ZS1zdHJpbmc9PyAtMSAiLTEiKSkK
KyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gMS4xICIxLjEiKSkKKyAgOzsgU3RyaW5n
cworICAocGFzcy1pZiAoanNvbi13cml0ZS1zdHJpbmc9PyAiZm9vIiAiXCJmb29cIiIpKQorICA7
OyBFc2NhcGUgY29kZXMKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gIlwiIiAiXCJc
XFwiXCIiKSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gIlxcIiAiXCJcXFxcXCIi
KSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gIi8iICJcIlxcL1wiIikpCisgIChw
YXNzLWlmIChqc29uLXdyaXRlLXN0cmluZz0/ICJcYiIgIlwiXFxiXCIiKSkKKyAgKHBhc3MtaWYg
KGpzb24td3JpdGUtc3RyaW5nPT8gIlxmIiAiXCJcXGZcIiIpKQorICAocGFzcy1pZiAoanNvbi13
cml0ZS1zdHJpbmc9PyAiXG4iICJcIlxcblwiIikpCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0
cmluZz0/ICJcciIgIlwiXFxyXCIiKSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8g
Ilx0IiAiXCJcXHRcIiIpKQorICA7OyBPYmplY3RzCisgIChwYXNzLWlmIChqc29uLXdyaXRlLXN0
cmluZz0/ICcoKSAie30iKSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gJygoImZv
byIgLiAiYmFyIikgKCJiYXoiIC4gImZyb2IiKSkKKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIntcImZvb1wiOlwiYmFyXCIsXCJiYXpcIjpcImZyb2JcIn0iKSkKKyAgOzsgTmVzdGVk
IG9iamVjdHMKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gJygoImZvbyIgLiAoKCJi
YXIiIC4gImJheiIpKSkpCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ7XCJmb29c
Ijp7XCJiYXJcIjpcImJhelwifX0iKSkKKyAgOzsgQXJyYXlzCisgIChwYXNzLWlmIChqc29uLXdy
aXRlLXN0cmluZz0/ICMoKSAiW10iKSkKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8g
IygxIDIgImZvbyIpCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJbMSwyLFwiZm9v
XCJdIikpCisgIDs7IE5lc3RlZCBhcnJheXMKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5n
PT8gIygxIDIgIygiZm9vIiAiYmFyIikpCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICJbMSwyLFtcImZvb1wiLFwiYmFyXCJdXSIpKQorICA7OyBBcnJheXMgYW5kIG9iamVjdHMgbmVz
dGVkIGluIGVhY2ggb3RoZXIKKyAgKHBhc3MtaWYgKGpzb24td3JpdGUtc3RyaW5nPT8gJygoImZv
byIgLiAjKCgoImJhciIgLiAjdCkpCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAoKCJiYXoiIC4gIygxIDIpKSkpKSkKKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIntcImZvb1wiOlt7XCJiYXJcIjp0cnVlfSx7XCJiYXpcIjpbMSwyXX1dfSIpKSkK
LS0gCjIuNDcuMQoK
--000000000000234de90632949a5a--




Acknowledgement sent to "Thompson, David" <dthompson2@HIDDEN>:
New bug report received and forwarded. Copy sent to bug-guile@HIDDEN. Full text available.
Report forwarded to bug-guile@HIDDEN:
bug#77762; Package guile. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Sun, 20 Apr 2025 14:00:03 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.