* [PATCH]
@ 2012-11-10 16:08 Ludovic Courtès
2012-11-10 19:18 ` [PATCH] Mark H Weaver
2012-11-11 3:30 ` [PATCH] Ian Price
0 siblings, 2 replies; 11+ messages in thread
From: Ludovic Courtès @ 2012-11-10 16:08 UTC (permalink / raw)
To: guile-devel; +Cc: Mark H. Weaver
[-- Attachment #1: Type: text/plain, Size: 453 bytes --]
Hello,
As Mark suggested on IRC, here’s a patch that moves SRFI-9 under
“Compound Data Types”, plus a new section “Record Overview” that aims to
guide users through the maze of record APIs.
Initially, I wanted to add a “Records & Structures” section, and move
SRFI-9, Guile records, and Guile structures there, but since
@subsubsubsection doesn’t exist, I just kept them at the same level.
Comments?
Thanks,
Ludo’.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: the patch --]
[-- Type: text/x-patch, Size: 11976 bytes --]
From f2c224480114d0a874ccd3d8d2400a43f99727d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@gnu.org>
Date: Sat, 10 Nov 2012 16:02:35 +0100
Subject: [PATCH] doc: Move SRFI-9 records under "Compound Data Types".
Suggested by Mark Weaver.
* doc/ref/srfi-modules.texi (SRFI-9): Keep the node, but move contents
to...
* doc/ref/api-compound.texi (SRFI-9 Records): ...here.
(Record Overview): New section.
---
doc/ref/api-compound.texi | 152 ++++++++++++++++++++++++++++++++++++++++++++-
doc/ref/srfi-modules.texi | 104 +------------------------------
2 files changed, 153 insertions(+), 103 deletions(-)
diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index d020774..b3fe0bd 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -25,8 +25,10 @@ values can be looked up within them.
* Generalized Vectors:: Treating all vector-like things uniformly.
* Arrays:: Matrices, etc.
* VLists:: Vector-like lists.
-* Records::
-* Structures::
+* Record Overview:: Walking through the maze of record APIs.
+* SRFI-9 Records:: The standard, recommended record API.
+* Records:: Guile's historical record API.
+* Structures:: Low-level record representation.
* Dictionary Types:: About dictionary types in general.
* Association Lists:: List-based dictionaries.
* VHashes:: VList-based dictionaries.
@@ -2249,6 +2251,152 @@ Return a new vlist whose contents correspond to @var{lst}.
Return a new list whose contents match those of @var{vlist}.
@end deffn
+@node Record Overview
+@subsection Record Overview
+
+@cindex record
+@cindex structure
+
+@dfn{Records}, also called @dfn{structures}, are Scheme's primary
+mechanism to define new disjoint types. A @dfn{record type} defines a
+list of @dfn{fields} that instances of the type consist of. This is like
+C's @code{struct}.
+
+Historically, Guile has offered several different ways to define record
+types and to create records, offering different features, and making
+different trade-offs. Over the years, each ``standard'' has also come
+with its own new record interface, leading to a maze of record APIs.
+
+At the highest level is SRFI-9, a high-level record interface
+implemented by most Scheme implementations (@pxref{SRFI-9}). It defines
+a simple and efficient syntactic abstraction of record types and their
+associated type predicate, fields, and field accessors. SRFI-9 is
+suitable for most uses, and this is the recommended way to create record
+types in Guile. Similar high-level record APIs include SRFI-35
+(@pxref{SRFI-35}) and R6RS records (@pxref{rnrs records syntactic}).
+
+Then comes Guile's historical ``records'' API (@pxref{Records}). Record
+types defined this way are first-class objects. Introspection
+facilities are available, allowing users to query the list of fields or
+the value of a specific field at run-time, without prior knowledge of
+the type.
+
+Finally, the common denominator of these interfaces is Guile's
+@dfn{structure} API (@pxref{Structures}). Guile's structures are the
+low-level building block for all other record APIs. Application writers
+will normally not need to use it.
+
+Records created with these APIs may all be pattern-matched using Guile's
+standard pattern matcher (@pxref{Pattern Matching}).
+
+
+@node SRFI-9 Records
+@subsection SRFI-9 Records
+
+@cindex SRFI-9
+@cindex record
+
+SRFI-9 standardizes a syntax for defining new record types and creating
+predicate, constructor, and field getter and setter functions. In Guile
+this is the recommended option to create new record types (@pxref{Record
+Overview}). It can be used with:
+
+@example
+(use-modules (srfi srfi-9))
+@end example
+
+@deffn {library syntax} define-record-type type @* (constructor fieldname @dots{}) @* predicate @* (fieldname accessor [modifier]) @dots{}
+@sp 1
+Create a new record type, and make various @code{define}s for using
+it. This syntax can only occur at the top-level, not nested within
+some other form.
+
+@var{type} is bound to the record type, which is as per the return
+from the core @code{make-record-type}. @var{type} also provides the
+name for the record, as per @code{record-type-name}.
+
+@var{constructor} is bound to a function to be called as
+@code{(@var{constructor} fieldval @dots{})} to create a new record of
+this type. The arguments are initial values for the fields, one
+argument for each field, in the order they appear in the
+@code{define-record-type} form.
+
+The @var{fieldname}s provide the names for the record fields, as per
+the core @code{record-type-fields} etc, and are referred to in the
+subsequent accessor/modifier forms.
+
+@var{predicate} is bound to a function to be called as
+@code{(@var{predicate} obj)}. It returns @code{#t} or @code{#f}
+according to whether @var{obj} is a record of this type.
+
+Each @var{accessor} is bound to a function to be called
+@code{(@var{accessor} record)} to retrieve the respective field from a
+@var{record}. Similarly each @var{modifier} is bound to a function to
+be called @code{(@var{modifier} record val)} to set the respective
+field in a @var{record}.
+@end deffn
+
+@noindent
+An example will illustrate typical usage,
+
+@example
+(define-record-type employee-type
+ (make-employee name age salary)
+ employee?
+ (name get-employee-name)
+ (age get-employee-age set-employee-age)
+ (salary get-employee-salary set-employee-salary))
+@end example
+
+This creates a new employee data type, with name, age and salary
+fields. Accessor functions are created for each field, but no
+modifier function for the name (the intention in this example being
+that it's established only when an employee object is created). These
+can all then be used as for example,
+
+@example
+employee-type @result{} #<record-type employee-type>
+
+(define fred (make-employee "Fred" 45 20000.00))
+
+(employee? fred) @result{} #t
+(get-employee-age fred) @result{} 45
+(set-employee-salary fred 25000.00) ;; pay rise
+@end example
+
+The functions created by @code{define-record-type} are ordinary
+top-level @code{define}s. They can be redefined or @code{set!} as
+desired, exported from a module, etc.
+
+@unnumberedsubsubsec Non-toplevel Record Definitions
+
+The SRFI-9 specification explicitly disallows record definitions in a
+non-toplevel context, such as inside @code{lambda} body or inside a
+@var{let} block. However, Guile's implementation does not enforce that
+restriction.
+
+@unnumberedsubsubsec Custom Printers
+
+You may use @code{set-record-type-printer!} to customize the default printing
+behavior of records. This is a Guile extension and is not part of SRFI-9. It
+is located in the @nicode{(srfi srfi-9 gnu)} module.
+
+@deffn {Scheme Syntax} set-record-type-printer! name thunk
+Where @var{type} corresponds to the first argument of @code{define-record-type},
+and @var{thunk} is a procedure accepting two arguments, the record to print, and
+an output port.
+@end deffn
+
+@noindent
+This example prints the employee's name in brackets, for instance @code{[Fred]}.
+
+@example
+(set-record-type-printer! employee-type
+ (lambda (record port)
+ (write-char #\[ port)
+ (display (get-employee-name record) port)
+ (write-char #\] port)))
+@end example
@node Records
diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index 0e2fa9d..70a49c8 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -1862,110 +1862,12 @@ procedures easier. It is documented in @xref{Multiple Values}.
@node SRFI-9
@subsection SRFI-9 - define-record-type
-@cindex SRFI-9
-@cindex record
This SRFI is a syntax for defining new record types and creating
-predicate, constructor, and field getter and setter functions. In
-Guile this is simply an alternate interface to the core record
-functionality (@pxref{Records}). It can be used with,
+predicate, constructor, and field getter and setter functions. It is
+documented in the ``Compound Data Types'' section of the manual
+(@pxref{SRFI-9 Records}).
-@example
-(use-modules (srfi srfi-9))
-@end example
-
-@deffn {library syntax} define-record-type type @* (constructor fieldname @dots{}) @* predicate @* (fieldname accessor [modifier]) @dots{}
-@sp 1
-Create a new record type, and make various @code{define}s for using
-it. This syntax can only occur at the top-level, not nested within
-some other form.
-
-@var{type} is bound to the record type, which is as per the return
-from the core @code{make-record-type}. @var{type} also provides the
-name for the record, as per @code{record-type-name}.
-
-@var{constructor} is bound to a function to be called as
-@code{(@var{constructor} fieldval @dots{})} to create a new record of
-this type. The arguments are initial values for the fields, one
-argument for each field, in the order they appear in the
-@code{define-record-type} form.
-
-The @var{fieldname}s provide the names for the record fields, as per
-the core @code{record-type-fields} etc, and are referred to in the
-subsequent accessor/modifier forms.
-
-@var{predicate} is bound to a function to be called as
-@code{(@var{predicate} obj)}. It returns @code{#t} or @code{#f}
-according to whether @var{obj} is a record of this type.
-
-Each @var{accessor} is bound to a function to be called
-@code{(@var{accessor} record)} to retrieve the respective field from a
-@var{record}. Similarly each @var{modifier} is bound to a function to
-be called @code{(@var{modifier} record val)} to set the respective
-field in a @var{record}.
-@end deffn
-
-@noindent
-An example will illustrate typical usage,
-
-@example
-(define-record-type employee-type
- (make-employee name age salary)
- employee?
- (name get-employee-name)
- (age get-employee-age set-employee-age)
- (salary get-employee-salary set-employee-salary))
-@end example
-
-This creates a new employee data type, with name, age and salary
-fields. Accessor functions are created for each field, but no
-modifier function for the name (the intention in this example being
-that it's established only when an employee object is created). These
-can all then be used as for example,
-
-@example
-employee-type @result{} #<record-type employee-type>
-
-(define fred (make-employee "Fred" 45 20000.00))
-
-(employee? fred) @result{} #t
-(get-employee-age fred) @result{} 45
-(set-employee-salary fred 25000.00) ;; pay rise
-@end example
-
-The functions created by @code{define-record-type} are ordinary
-top-level @code{define}s. They can be redefined or @code{set!} as
-desired, exported from a module, etc.
-
-@unnumberedsubsubsec Non-toplevel Record Definitions
-
-The SRFI-9 specification explicitly disallows record definitions in a
-non-toplevel context, such as inside @code{lambda} body or inside a
-@var{let} block. However, Guile's implementation does not enforce that
-restriction.
-
-@unnumberedsubsubsec Custom Printers
-
-You may use @code{set-record-type-printer!} to customize the default printing
-behavior of records. This is a Guile extension and is not part of SRFI-9. It
-is located in the @nicode{(srfi srfi-9 gnu)} module.
-
-@deffn {Scheme Syntax} set-record-type-printer! name thunk
-Where @var{type} corresponds to the first argument of @code{define-record-type},
-and @var{thunk} is a procedure accepting two arguments, the record to print, and
-an output port.
-@end deffn
-
-@noindent
-This example prints the employee's name in brackets, for instance @code{[Fred]}.
-
-@example
-(set-record-type-printer! employee-type
- (lambda (record port)
- (write-char #\[ port)
- (display (get-employee-name record) port)
- (write-char #\] port)))
-@end example
@node SRFI-10
@subsection SRFI-10 - Hash-Comma Reader Extension
--
1.7.10.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH]
2012-11-10 16:08 [PATCH] Ludovic Courtès
@ 2012-11-10 19:18 ` Mark H Weaver
2012-11-10 21:30 ` [PATCH] Moving SRFI-9 doc under “Compound Data Types” Ludovic Courtès
2012-11-11 3:30 ` [PATCH] Ian Price
1 sibling, 1 reply; 11+ messages in thread
From: Mark H Weaver @ 2012-11-10 19:18 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: guile-devel
ludo@gnu.org (Ludovic Courtès) writes:
> As Mark suggested on IRC, here’s a patch that moves SRFI-9 under
> “Compound Data Types”, plus a new section “Record Overview” that aims to
> guide users through the maze of record APIs.
Wow, thanks for doing this!
Looks great, please push :)
Mark
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Moving SRFI-9 doc under “Compound Data Types”
2012-11-10 19:18 ` [PATCH] Mark H Weaver
@ 2012-11-10 21:30 ` Ludovic Courtès
0 siblings, 0 replies; 11+ messages in thread
From: Ludovic Courtès @ 2012-11-10 21:30 UTC (permalink / raw)
To: Mark H Weaver; +Cc: guile-devel
Mark H Weaver <mhw@netris.org> skribis:
> ludo@gnu.org (Ludovic Courtès) writes:
>> As Mark suggested on IRC, here’s a patch that moves SRFI-9 under
>> “Compound Data Types”, plus a new section “Record Overview” that aims to
>> guide users through the maze of record APIs.
>
> Wow, thanks for doing this!
> Looks great, please push :)
Done, thanks! (I also added a topic to the message this time. ;-))
Ludo’.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH]
2012-11-10 16:08 [PATCH] Ludovic Courtès
2012-11-10 19:18 ` [PATCH] Mark H Weaver
@ 2012-11-11 3:30 ` Ian Price
2012-11-11 6:06 ` [PATCH] Noah Lavine
2012-11-11 14:02 ` [PATCH] Ludovic Courtès
1 sibling, 2 replies; 11+ messages in thread
From: Ian Price @ 2012-11-11 3:30 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: Mark H. Weaver, guile-devel
The patch looks fine to me (it had better be, since it is already pushed
:P), however I wonder if it wouldn't be prudent to look to moving
define-record-type into guile proper, and making (use-modules (srfi
srfi-9)) effectively a no-op.
--
Ian Price -- shift-reset.com
"Programming is like pinball. The reward for doing it well is
the opportunity to do it again" - from "The Wizardy Compiled"
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH]
2012-11-11 3:30 ` [PATCH] Ian Price
@ 2012-11-11 6:06 ` Noah Lavine
2012-11-11 14:02 ` [PATCH] Ludovic Courtès
1 sibling, 0 replies; 11+ messages in thread
From: Noah Lavine @ 2012-11-11 6:06 UTC (permalink / raw)
To: Ian Price; +Cc: Mark H. Weaver, Ludovic Courtès, guile-devel
[-- Attachment #1: Type: text/plain, Size: 662 bytes --]
SRFI-9 seems to be part of R7RS anyway (assuming there are no sudden
last-minute changes), so I'd say we'll definitely want to do something like
that soon.
Noah
On Sat, Nov 10, 2012 at 10:30 PM, Ian Price <ianprice90@googlemail.com>wrote:
>
> The patch looks fine to me (it had better be, since it is already pushed
> :P), however I wonder if it wouldn't be prudent to look to moving
> define-record-type into guile proper, and making (use-modules (srfi
> srfi-9)) effectively a no-op.
>
> --
> Ian Price -- shift-reset.com
>
> "Programming is like pinball. The reward for doing it well is
> the opportunity to do it again" - from "The Wizardy Compiled"
>
>
[-- Attachment #2: Type: text/html, Size: 1153 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH]
2012-11-11 3:30 ` [PATCH] Ian Price
2012-11-11 6:06 ` [PATCH] Noah Lavine
@ 2012-11-11 14:02 ` Ludovic Courtès
1 sibling, 0 replies; 11+ messages in thread
From: Ludovic Courtès @ 2012-11-11 14:02 UTC (permalink / raw)
To: Ian Price; +Cc: Mark H. Weaver, guile-devel
Hi,
Ian Price <ianprice90@googlemail.com> skribis:
> The patch looks fine to me (it had better be, since it is already pushed
> :P),
We could always change that.
> however I wonder if it wouldn't be prudent to look to moving
> define-record-type into guile proper, and making (use-modules (srfi
> srfi-9)) effectively a no-op.
In general, I’m not in favor of adding global bindings. Quite the
opposite: I’d be happier if, for instance, POSIX stuff was under an
(ice-9 posix) module. That’d make sandboxing much easier.
Thanks,
Ludo’.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH]
@ 2010-10-27 18:27 Neil Jerram
2010-10-27 18:30 ` [PATCH] Noah Lavine
2010-10-27 22:14 ` [PATCH] Ludovic Courtès
0 siblings, 2 replies; 11+ messages in thread
From: Neil Jerram @ 2010-10-27 18:27 UTC (permalink / raw)
To: guile-devel
[-- Attachment #1: Type: text/plain, Size: 353 bytes --]
I have a program that calls (read-elisp) in a loop, to read in a BBDB
file. When it gets to the end of the file, the next (read-elisp) throws
an error (wrong type arg, pair expected), and the attached patch makes
it return '*eoi* instead.
Is that correct? Is *eoi* better than #<eof> here? Or should I just
catch the exception instead?
Neil
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Make-read-elisp-handle-EOF.patch --]
[-- Type: text/x-diff, Size: 1142 bytes --]
From b6017106abe754c596efe208554e98efc0248662 Mon Sep 17 00:00:00 2001
From: Neil Jerram <neil@ossau.uklinux.net>
Date: Wed, 27 Oct 2010 19:23:35 +0100
Subject: [PATCH] Make (read-elisp) handle EOF
* module/language/elisp/parser.scm (get-expression): Handle the case
where a top level lex returns *eoi*.
---
module/language/elisp/parser.scm | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/module/language/elisp/parser.scm b/module/language/elisp/parser.scm
index 4d9b0c3..bb495ea 100644
--- a/module/language/elisp/parser.scm
+++ b/module/language/elisp/parser.scm
@@ -171,7 +171,7 @@
(define (get-expression lex)
(let* ((token (lex 'get))
- (type (car token))
+ (type (if (pair? token) (car token) token))
(return (lambda (result)
(if (pair? result)
(set-source-properties! result (source-properties token)))
@@ -194,6 +194,8 @@
(setter expr)
(force-promises! expr)
expr))
+ ((*eoi*)
+ (return token))
(else
(parse-error token "expected expression, got" token)))))
--
1.7.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH]
2010-10-27 18:27 [PATCH] Neil Jerram
@ 2010-10-27 18:30 ` Noah Lavine
2010-10-27 22:14 ` [PATCH] Ludovic Courtès
1 sibling, 0 replies; 11+ messages in thread
From: Noah Lavine @ 2010-10-27 18:30 UTC (permalink / raw)
To: Neil Jerram; +Cc: guile-devel
*eoi* is what the LALR parser generator would need as input, so it
seems more consistent with the Guile API to make it return '*eoi*.
Noah
On Wed, Oct 27, 2010 at 2:27 PM, Neil Jerram <neil@ossau.uklinux.net> wrote:
> I have a program that calls (read-elisp) in a loop, to read in a BBDB
> file. When it gets to the end of the file, the next (read-elisp) throws
> an error (wrong type arg, pair expected), and the attached patch makes
> it return '*eoi* instead.
>
> Is that correct? Is *eoi* better than #<eof> here? Or should I just
> catch the exception instead?
>
> Neil
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH]
2010-10-27 18:27 [PATCH] Neil Jerram
2010-10-27 18:30 ` [PATCH] Noah Lavine
@ 2010-10-27 22:14 ` Ludovic Courtès
2010-10-27 23:35 ` [PATCH] Neil Jerram
1 sibling, 1 reply; 11+ messages in thread
From: Ludovic Courtès @ 2010-10-27 22:14 UTC (permalink / raw)
To: guile-devel
Hi Neil,
Neil Jerram <neil@ossau.uklinux.net> writes:
> I have a program that calls (read-elisp) in a loop, to read in a BBDB
> file. When it gets to the end of the file, the next (read-elisp) throws
> an error (wrong type arg, pair expected), and the attached patch makes
> it return '*eoi* instead.
>
> Is that correct?
‘get-lexer/1’ can return '*eoi*, so yes, I think.
> Is *eoi* better than #<eof> here?
I don’t think so, since it’s the result returned by ‘read-elisp’, whose
callers shouldn’t see '*eoi*. So I think ‘get-expression’ should return
the EOF object when it encounters '*eoi*.
Besides, you might want to check if it’s fixed in the elisp branch, who
knows. :-)
Thanks,
Ludo’.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH]
2010-10-27 22:14 ` [PATCH] Ludovic Courtès
@ 2010-10-27 23:35 ` Neil Jerram
2010-11-20 15:42 ` [PATCH] Andy Wingo
0 siblings, 1 reply; 11+ messages in thread
From: Neil Jerram @ 2010-10-27 23:35 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: guile-devel
ludo@gnu.org (Ludovic Courtès) writes:
> Besides, you might want to check if it’s fixed in the elisp branch, who
> knows. :-)
Ah, yes, I didn't think of that. As luck would have it, this has indeed
been fixed already. :-)
Thanks,
Neil
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH]
2010-10-27 23:35 ` [PATCH] Neil Jerram
@ 2010-11-20 15:42 ` Andy Wingo
0 siblings, 0 replies; 11+ messages in thread
From: Andy Wingo @ 2010-11-20 15:42 UTC (permalink / raw)
To: Neil Jerram; +Cc: Ludovic Courtès, guile-devel
On Thu 28 Oct 2010 01:35, Neil Jerram <neil@ossau.uklinux.net> writes:
> ludo@gnu.org (Ludovic Courtès) writes:
>
>> Besides, you might want to check if it’s fixed in the elisp branch, who
>> knows. :-)
>
> Ah, yes, I didn't think of that. As luck would have it, this has indeed
> been fixed already. :-)
And Brian's paperwork has finally come through, so we can merge it now,
after a review.
I have been totally negligent regarding getting the fine SoC work in. I
hope to get to that in the coming week.
Andy
--
http://wingolog.org/
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2012-11-11 14:02 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-10 16:08 [PATCH] Ludovic Courtès
2012-11-10 19:18 ` [PATCH] Mark H Weaver
2012-11-10 21:30 ` [PATCH] Moving SRFI-9 doc under “Compound Data Types” Ludovic Courtès
2012-11-11 3:30 ` [PATCH] Ian Price
2012-11-11 6:06 ` [PATCH] Noah Lavine
2012-11-11 14:02 ` [PATCH] Ludovic Courtès
-- strict thread matches above, loose matches on Subject: below --
2010-10-27 18:27 [PATCH] Neil Jerram
2010-10-27 18:30 ` [PATCH] Noah Lavine
2010-10-27 22:14 ` [PATCH] Ludovic Courtès
2010-10-27 23:35 ` [PATCH] Neil Jerram
2010-11-20 15:42 ` [PATCH] Andy Wingo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).